Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 66dd6dd

Browse filesBrowse files
committed
feat(@angular/build): allow options for unit test reporters
This change enhances the `reporters` option in the unit-test builder to support passing an options object, similar to the existing `codeCoverageReporters` option. Users can now specify a reporter as a tuple of `[name, options]`. - The `schema.json` is updated to allow either a string or a `[string, object]` tuple in the `reporters` array. An `enum` is provided for common reporters while still allowing custom string paths. - The option normalization logic in `options.ts` is refactored into a shared helper function to handle both `reporters` and `codeCoverageReporters`, reducing code duplication. - The Karma runner, which does not support reporter options, is updated to safely ignore them and warn the user.
1 parent 69c3b12 commit 66dd6dd
Copy full SHA for 66dd6dd

File tree

Expand file treeCollapse file tree

5 files changed

+106
-24
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

5 files changed

+106
-24
lines changed
Open diff view settings
Collapse file

‎goldens/public-api/angular/build/index.api.md‎

Copy file name to clipboardExpand all lines: goldens/public-api/angular/build/index.api.md
+1-1Lines changed: 1 addition & 1 deletion
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ export type UnitTestBuilderOptions = {
225225
include?: string[];
226226
progress?: boolean;
227227
providersFile?: string;
228-
reporters?: string[];
228+
reporters?: SchemaReporter[];
229229
runner: Runner;
230230
setupFiles?: string[];
231231
tsConfig: string;
Collapse file

‎packages/angular/build/src/builders/unit-test/options.ts‎

Copy file name to clipboardExpand all lines: packages/angular/build/src/builders/unit-test/options.ts
+13-7Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ import type { Schema as UnitTestBuilderOptions } from './schema';
1515

1616
export type NormalizedUnitTestBuilderOptions = Awaited<ReturnType<typeof normalizeOptions>>;
1717

18+
function normalizeReporterOption(
19+
reporters: unknown[] | undefined,
20+
): [string, Record<string, unknown>][] | undefined {
21+
return reporters?.map((entry) =>
22+
typeof entry === 'string'
23+
? ([entry, {}] as [string, Record<string, unknown>])
24+
: (entry as [string, Record<string, unknown>]),
25+
);
26+
}
27+
1828
export async function normalizeOptions(
1929
context: BuilderContext,
2030
projectName: string,
@@ -33,7 +43,7 @@ export async function normalizeOptions(
3343
const buildTargetSpecifier = options.buildTarget ?? `::development`;
3444
const buildTarget = targetFromTargetString(buildTargetSpecifier, projectName, 'build');
3545

36-
const { tsConfig, runner, reporters, browsers, progress } = options;
46+
const { tsConfig, runner, browsers, progress } = options;
3747

3848
return {
3949
// Project/workspace information
@@ -49,16 +59,12 @@ export async function normalizeOptions(
4959
codeCoverage: options.codeCoverage
5060
? {
5161
exclude: options.codeCoverageExclude,
52-
reporters: options.codeCoverageReporters?.map((entry) =>
53-
typeof entry === 'string'
54-
? ([entry, {}] as [string, Record<string, unknown>])
55-
: (entry as [string, Record<string, unknown>]),
56-
),
62+
reporters: normalizeReporterOption(options.codeCoverageReporters),
5763
}
5864
: undefined,
5965
tsConfig,
6066
buildProgress: progress,
61-
reporters,
67+
reporters: normalizeReporterOption(options.reporters),
6268
browsers,
6369
watch: options.watch ?? isTTY(),
6470
debug: options.debug ?? false,
Collapse file

‎packages/angular/build/src/builders/unit-test/runners/karma/executor.ts‎

Copy file name to clipboardExpand all lines: packages/angular/build/src/builders/unit-test/runners/karma/executor.ts
+10-1Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,16 @@ export class KarmaExecutor implements TestExecutor {
6060
codeCoverage: !!unitTestOptions.codeCoverage,
6161
codeCoverageExclude: unitTestOptions.codeCoverage?.exclude,
6262
fileReplacements: buildTargetOptions.fileReplacements,
63-
reporters: unitTestOptions.reporters,
63+
reporters: unitTestOptions.reporters?.map((reporter) => {
64+
// Karma only supports string reporters.
65+
if (Object.keys(reporter[1]).length > 0) {
66+
context.logger.warn(
67+
`The "karma" test runner does not support options for the "${reporter[0]}" reporter. The options will be ignored.`,
68+
);
69+
}
70+
71+
return reporter[0];
72+
}),
6473
webWorkerTsConfig: buildTargetOptions.webWorkerTsConfig,
6574
aot: buildTargetOptions.aot,
6675
};
Collapse file

‎packages/angular/build/src/builders/unit-test/schema.json‎

Copy file name to clipboardExpand all lines: packages/angular/build/src/builders/unit-test/schema.json
+37-2Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,40 @@
8888
},
8989
"reporters": {
9090
"type": "array",
91-
"description": "Test runner reporters to use. Directly passed to the test runner.",
91+
"description": "Specifies the reporters to use during test execution. Each reporter can be a string representing its name, or a tuple containing the name and an options object. Built-in reporters include 'default', 'verbose', 'dots', 'json', 'junit', 'tap', 'tap-flat', and 'html'. You can also provide a path to a custom reporter.",
9292
"items": {
93-
"type": "string"
93+
"oneOf": [
94+
{
95+
"anyOf": [
96+
{
97+
"$ref": "#/definitions/reporters-enum"
98+
},
99+
{
100+
"type": "string"
101+
}
102+
]
103+
},
104+
{
105+
"type": "array",
106+
"minItems": 1,
107+
"maxItems": 2,
108+
"items": [
109+
{
110+
"anyOf": [
111+
{
112+
"$ref": "#/definitions/reporters-enum"
113+
},
114+
{
115+
"type": "string"
116+
}
117+
]
118+
},
119+
{
120+
"type": "object"
121+
}
122+
]
123+
}
124+
]
94125
}
95126
},
96127
"providersFile": {
@@ -124,6 +155,10 @@
124155
"json",
125156
"json-summary"
126157
]
158+
},
159+
"reporters-enum": {
160+
"type": "string",
161+
"enum": ["default", "verbose", "dots", "json", "junit", "tap", "tap-flat", "html"]
127162
}
128163
}
129164
}
Collapse file

‎packages/angular/build/src/builders/unit-test/tests/options/reporters_spec.ts‎

Copy file name to clipboardExpand all lines: packages/angular/build/src/builders/unit-test/tests/options/reporters_spec.ts
+45-13Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,66 @@ import {
1515
} from '../setup';
1616

1717
describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => {
18-
xdescribe('Option: "reporters"', () => {
19-
beforeEach(async () => {
18+
describe('Option: "reporters"', () => {
19+
beforeEach(() => {
2020
setupApplicationTarget(harness);
2121
});
2222

23-
it('should use the default reporter when none is specified', async () => {
23+
it(`should support a single reporter`, async () => {
2424
harness.useTarget('test', {
2525
...BASE_OPTIONS,
26+
reporters: ['json'],
2627
});
2728

28-
const { result, logs } = await harness.executeOnce();
29+
const { result } = await harness.executeOnce();
2930
expect(result?.success).toBeTrue();
30-
expect(logs).toContain(
31-
jasmine.objectContaining({ message: jasmine.stringMatching(/DefaultReporter/) }),
32-
);
3331
});
3432

35-
it('should use a custom reporter when specified', async () => {
33+
it(`should support multiple reporters`, async () => {
3634
harness.useTarget('test', {
3735
...BASE_OPTIONS,
38-
reporters: ['json'],
36+
reporters: ['json', 'verbose'],
37+
});
38+
39+
const { result } = await harness.executeOnce();
40+
expect(result?.success).toBeTrue();
41+
});
42+
43+
it(`should support a single reporter with options`, async () => {
44+
harness.useTarget('test', {
45+
...BASE_OPTIONS,
46+
reporters: [['json', { outputFile: 'a.json' }]],
47+
});
48+
49+
const { result } = await harness.executeOnce();
50+
expect(result?.success).toBeTrue();
51+
harness.expectFile('a.json').toExist();
52+
});
53+
54+
it(`should support multiple reporters with options`, async () => {
55+
harness.useTarget('test', {
56+
...BASE_OPTIONS,
57+
reporters: [
58+
['json', { outputFile: 'a.json' }],
59+
['junit', { outputFile: 'a.xml' }],
60+
],
61+
});
62+
63+
const { result } = await harness.executeOnce();
64+
expect(result?.success).toBeTrue();
65+
harness.expectFile('a.json').toExist();
66+
harness.expectFile('a.xml').toExist();
67+
});
68+
69+
it(`should support multiple reporters with and without options`, async () => {
70+
harness.useTarget('test', {
71+
...BASE_OPTIONS,
72+
reporters: [['json', { outputFile: 'a.json' }], 'verbose', 'default'],
3973
});
4074

41-
const { result, logs } = await harness.executeOnce();
75+
const { result } = await harness.executeOnce();
4276
expect(result?.success).toBeTrue();
43-
expect(logs).toContain(
44-
jasmine.objectContaining({ message: jasmine.stringMatching(/JsonReporter/) }),
45-
);
77+
harness.expectFile('a.json').toExist();
4678
});
4779
});
4880
});

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.