Skip to content

Commit c0b00d7

Browse files
cexbrayatclydin
authored andcommitted
feat(@angular/build): add reporter output file option for unit-test
The experimental `unit-test` builder now contains an additional option named `outputFile` that supports configuring the output file for the reporter. This option is currently only used by the `vitest` runner. See https://vitest.dev/config/#outputfile Usage example: ``` ng test --no-watch --reporter=json --output-file=results/unit-test.json ```
1 parent 66dd6dd commit c0b00d7

File tree

5 files changed

+55
-2
lines changed

5 files changed

+55
-2
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ export type UnitTestBuilderOptions = {
223223
debug?: boolean;
224224
exclude?: string[];
225225
include?: string[];
226+
outputFile?: string;
226227
progress?: boolean;
227228
providersFile?: string;
228229
reporters?: SchemaReporter[];

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export async function normalizeOptions(
6565
tsConfig,
6666
buildProgress: progress,
6767
reporters: normalizeReporterOption(options.reporters),
68+
outputFile: options.outputFile,
6869
browsers,
6970
watch: options.watch ?? isTTY(),
7071
debug: options.debug ?? false,

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ export class VitestExecutor implements TestExecutor {
127127
}
128128

129129
private async initializeVitest(): Promise<Vitest> {
130-
const { codeCoverage, reporters, workspaceRoot, browsers, debug, watch } = this.options;
131-
130+
const { codeCoverage, reporters, outputFile, workspaceRoot, browsers, debug, watch } =
131+
this.options;
132132
let vitestNodeModule;
133133
try {
134134
vitestNodeModule = await loadEsmModule<typeof import('vitest/node')>('vitest/node');
@@ -188,6 +188,7 @@ export class VitestExecutor implements TestExecutor {
188188
name: 'base',
189189
include: [],
190190
reporters: reporters ?? ['default'],
191+
outputFile,
191192
watch,
192193
coverage: generateCoverageOption(codeCoverage),
193194
...debugOptions,

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@
124124
]
125125
}
126126
},
127+
"outputFile": {
128+
"type": "string",
129+
"description": "The file to output the test report to. If not specified, the test runner will output to the console."
130+
},
127131
"providersFile": {
128132
"type": "string",
129133
"description": "TypeScript file that exports an array of Angular providers to use during test execution. The array must be a default export.",
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import { execute } from '../../index';
10+
import {
11+
BASE_OPTIONS,
12+
describeBuilder,
13+
UNIT_TEST_BUILDER_INFO,
14+
setupApplicationTarget,
15+
} from '../setup';
16+
17+
describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => {
18+
describe('Options: "reporter" and "outputFile"', () => {
19+
beforeEach(async () => {
20+
setupApplicationTarget(harness);
21+
});
22+
23+
it(`should output a JSON report`, async () => {
24+
await harness.removeFile('src/app/app.component.spec.ts');
25+
await harness.writeFiles({
26+
'src/app/services/test.service.spec.ts': `
27+
describe('TestService', () => {
28+
it('should succeed', () => {
29+
expect(true).toBe(true);
30+
});
31+
});`,
32+
});
33+
34+
harness.useTarget('test', {
35+
...BASE_OPTIONS,
36+
reporters: ['json'],
37+
outputFile: 'test-report.json',
38+
});
39+
40+
const { result } = await harness.executeOnce();
41+
expect(result?.success).toBeTrue();
42+
const reportContent = await harness.readFile('test-report.json');
43+
expect(reportContent).toContain('TestService');
44+
});
45+
});
46+
});

0 commit comments

Comments
 (0)