Skip to content

Commit d411403

Browse files
committed
feat(@angular/build): add 'filter' option to unit-test builder
This change introduces a new `filter` option to the `unit-test` builder. This allows users to specify a regular expression to match against test description names, providing a way to run a subset of tests. The option is implemented for the Vitest runner by passing the value to the `testNamePattern` configuration option. A warning is added for the Karma runner to inform users that the option is not yet supported there.
1 parent cfac923 commit d411403

File tree

6 files changed

+76
-1
lines changed

6 files changed

+76
-1
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ export type UnitTestBuilderOptions = {
222222
codeCoverageReporters?: SchemaCodeCoverageReporter[];
223223
debug?: boolean;
224224
exclude?: string[];
225+
filter?: string;
225226
include?: string[];
226227
progress?: boolean;
227228
providersFile?: string;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export async function normalizeOptions(
3333
const buildTargetSpecifier = options.buildTarget ?? `::development`;
3434
const buildTarget = targetFromTargetString(buildTargetSpecifier, projectName, 'build');
3535

36-
const { tsConfig, runner, reporters, browsers, progress } = options;
36+
const { tsConfig, runner, reporters, browsers, progress, filter } = options;
3737

3838
return {
3939
// Project/workspace information
@@ -45,6 +45,7 @@ export async function normalizeOptions(
4545
buildTarget,
4646
include: options.include ?? ['**/*.spec.ts'],
4747
exclude: options.exclude,
48+
filter,
4849
runnerName: runner,
4950
codeCoverage: options.codeCoverage
5051
? {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ export class KarmaExecutor implements TestExecutor {
3333
);
3434
}
3535

36+
if (unitTestOptions.filter) {
37+
context.logger.warn(
38+
'The "karma" test runner does not support the "filter" option. The option will be ignored.',
39+
);
40+
}
41+
3642
const buildTargetOptions = (await context.validateOptions(
3743
await context.getTargetOptions(unitTestOptions.buildTarget),
3844
await context.getBuilderNameForTarget(unitTestOptions.buildTarget),

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ export class VitestExecutor implements TestExecutor {
187187
project: ['base', this.projectName],
188188
name: 'base',
189189
include: [],
190+
testNamePattern: this.options.filter,
190191
reporters: reporters ?? ['default'],
191192
watch,
192193
coverage: generateCoverageOption(codeCoverage),

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
},
4242
"description": "Globs of files to exclude, relative to the project root."
4343
},
44+
"filter": {
45+
"type": "string",
46+
"description": "A regular expression to match against test names, running only matching tests."
47+
},
4448
"watch": {
4549
"type": "boolean",
4650
"description": "Re-run tests when source files change. Defaults to `true` in TTY environments and `false` otherwise."
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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 '../../builder';
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('Option: "filter"', () => {
19+
beforeEach(async () => {
20+
setupApplicationTarget(harness);
21+
22+
await harness.writeFiles({
23+
'src/app/pass.spec.ts': `
24+
describe('Passing Suite', () => {
25+
it('should pass', () => {
26+
expect(true).toBe(true);
27+
});
28+
});
29+
`,
30+
'src/app/fail.spec.ts': `
31+
describe('Failing Suite', () => {
32+
it('should fail', () => {
33+
expect(true).toBe(false);
34+
});
35+
});
36+
`,
37+
});
38+
});
39+
40+
it('should only run tests that match the filter regex', async () => {
41+
harness.useTarget('test', {
42+
...BASE_OPTIONS,
43+
// This filter should only match the 'should pass' test
44+
filter: 'pass$',
45+
});
46+
47+
const { result } = await harness.executeOnce();
48+
// The overall result should be success because the failing test was filtered out.
49+
expect(result?.success).toBe(true);
50+
});
51+
52+
it('should run all tests when no filter is provided', async () => {
53+
harness.useTarget('test', {
54+
...BASE_OPTIONS,
55+
});
56+
57+
const { result } = await harness.executeOnce();
58+
// The overall result should be failure because the failing test was included.
59+
expect(result?.success).toBe(false);
60+
});
61+
});
62+
});

0 commit comments

Comments
 (0)