Skip to content

Commit 927bf95

Browse files
committed
feat(@angular/build): add isolate option to unit-test builder
This commit adds an `isolate` option to the `@angular/build:unit-test` builder for the Vitest runner. By default, tests run in a non-isolated environment to match the behavior of Karma/Jasmine. This new option allows developers to easily opt-in to Vitest native isolation (running tests in separate threads or processes) without requiring a custom Vitest configuration file. The option is not supported by the Karma runner and will result in an error if used there.
1 parent 73233dc commit 927bf95

5 files changed

Lines changed: 70 additions & 3 deletions

File tree

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,16 @@ export async function normalizeOptions(
5454
const buildTargetSpecifier = options.buildTarget ?? `::development`;
5555
const buildTarget = targetFromTargetString(buildTargetSpecifier, projectName, 'build');
5656

57-
const { runner, browsers, progress, filter, browserViewport, ui, runnerConfig } = options;
57+
const { runner, browsers, progress, filter, browserViewport, ui, runnerConfig, isolate } = options;
5858

5959
if (ui && runner !== Runner.Vitest) {
6060
throw new Error('The "ui" option is only available for the "vitest" runner.');
6161
}
6262

63+
if (isolate && runner !== Runner.Vitest) {
64+
throw new Error('The "isolate" option is only available for the "vitest" runner.');
65+
}
66+
6367
const [width, height] = browserViewport?.split('x').map(Number) ?? [];
6468

6569
let tsConfig = options.tsConfig;
@@ -121,6 +125,7 @@ export async function normalizeOptions(
121125
watch,
122126
debug: options.debug ?? false,
123127
ui: process.env['CI'] ? false : ui,
128+
isolate: isolate ?? false,
124129
quiet: options.quiet ?? (process.env['CI'] ? false : true),
125130
providersFile: options.providersFile && path.join(workspaceRoot, options.providersFile),
126131
setupFiles: options.setupFiles

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
@@ -378,6 +378,7 @@ export class VitestExecutor implements TestExecutor {
378378
projectPlugins,
379379
include,
380380
watch,
381+
isolate: this.options.isolate,
381382
}),
382383
],
383384
};

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ interface VitestConfigPluginOptions {
5454
include: string[];
5555
optimizeDepsInclude: string[];
5656
watch: boolean;
57+
isolate: boolean;
5758
}
5859

5960
async function findTestEnvironment(
@@ -250,8 +251,7 @@ export async function createVitestConfigPlugin(
250251
test: {
251252
setupFiles,
252253
globals: true,
253-
// Default to `false` to align with the Karma/Jasmine experience.
254-
isolate: false,
254+
isolate: options.isolate,
255255
sequence: { setupFiles: 'list' },
256256
},
257257
optimizeDeps: {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@
7373
"type": "boolean",
7474
"description": "Enables the Vitest UI for interactive test execution. This option is only available for the Vitest runner."
7575
},
76+
"isolate": {
77+
"type": "boolean",
78+
"description": "Enables isolation for test execution. When true, Vitest runs tests in separate threads or processes. This option is only available for the Vitest runner. Defaults to false to align with the Karma/Jasmine experience."
79+
},
7680
"quiet": {
7781
"type": "boolean",
7882
"description": "Suppresses the verbose build summary and stats table on each rebuild. Defaults to `true` locally and `false` in CI environments."
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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('Option: "isolate"', () => {
19+
beforeEach(async () => {
20+
setupApplicationTarget(harness);
21+
});
22+
23+
it('should fail when isolate is true and runner is karma', async () => {
24+
harness.useTarget('test', {
25+
...BASE_OPTIONS,
26+
runner: 'karma',
27+
isolate: true,
28+
});
29+
30+
await expectAsync(harness.executeOnce()).toBeRejectedWithError(
31+
/The "isolate" option is only available for the "vitest" runner/,
32+
);
33+
});
34+
35+
it('should run tests successfully when isolate is true and runner is vitest', async () => {
36+
harness.useTarget('test', {
37+
...BASE_OPTIONS,
38+
runner: 'vitest',
39+
isolate: true,
40+
});
41+
42+
const { result } = await harness.executeOnce();
43+
expect(result?.success).toBeTrue();
44+
});
45+
46+
it('should run tests successfully when isolate is false and runner is vitest', async () => {
47+
harness.useTarget('test', {
48+
...BASE_OPTIONS,
49+
runner: 'vitest',
50+
isolate: false,
51+
});
52+
53+
const { result } = await harness.executeOnce();
54+
expect(result?.success).toBeTrue();
55+
});
56+
});
57+
});

0 commit comments

Comments
 (0)