Skip to content

Commit 3d7f8ab

Browse files
committed
fix(@angular/build): ensure TestBed setup is robust in non-isolated Vitest
This commit refines the Angular TestBed initialization within the Vitest runner to ensure correct behavior in non-isolated test environments (`isolate: false`). Previously, in a non-isolated setup, the TestBed initialization logic in the virtual setup file could be problematic if the file was evaluated multiple times. This could lead to re-registering `beforeEach`/`afterEach` hooks or attempting to re-initialize the TestBed, causing errors or unexpected test behavior. This change introduces a globally unique symbol guard (`Symbol.for('@angular/cli/testbed-setup')`) that ensures the entire TestBed setup block (including hook registration and `initTestEnvironment`) is executed only once per test run. This prevents redundant executions and potential errors. Finally, the `isolate` option in Vitest is now explicitly defaulted to `false` when not specified by the user, aligning with the traditional Karma/Jasmine experience.
1 parent 0aab115 commit 3d7f8ab

File tree

3 files changed

+29
-12
lines changed

3 files changed

+29
-12
lines changed

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

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,29 @@ function createTestBedInitVirtualFile(
4949
import { getTestBed, ɵgetCleanupHook as getCleanupHook } from '@angular/core/testing';
5050
import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';
5151
${providersImport}
52-
// Same as https://github.com/angular/angular/blob/05a03d3f975771bb59c7eefd37c01fa127ee2229/packages/core/testing/srcs/test_hooks.ts#L21-L29
53-
beforeEach(getCleanupHook(false));
54-
afterEach(getCleanupHook(true));
55-
@NgModule({
56-
providers: [${usesZoneJS ? 'provideZoneChangeDetection(), ' : ''}...providers],
57-
})
58-
export class TestModule {}
59-
getTestBed().initTestEnvironment([BrowserTestingModule, TestModule], platformBrowserTesting(), {
60-
errorOnUnknownElements: true,
61-
errorOnUnknownProperties: true,
62-
});
52+
53+
const ANGULAR_TESTBED_SETUP = Symbol.for('@angular/cli/testbed-setup');
54+
if (!globalThis[ANGULAR_TESTBED_SETUP]) {
55+
globalThis[ANGULAR_TESTBED_SETUP] = true;
56+
57+
// The Angular TestBed needs to be initialized before any tests are run.
58+
// In a non-isolated environment, this setup file can be executed multiple times.
59+
// The guard condition above ensures that the setup is only performed once.
60+
61+
// Same as https://github.com/angular/angular/blob/05a03d3f975771bb59c7eefd37c01fa127ee2229/packages/core/testing/srcs/test_hooks.ts#L21-L29
62+
beforeEach(getCleanupHook(false));
63+
afterEach(getCleanupHook(true));
64+
65+
@NgModule({
66+
providers: [${usesZoneJS ? 'provideZoneChangeDetection(), ' : ''}...providers],
67+
})
68+
class TestModule {}
69+
70+
getTestBed().initTestEnvironment([BrowserTestingModule, TestModule], platformBrowserTesting(), {
71+
errorOnUnknownElements: true,
72+
errorOnUnknownProperties: true,
73+
});
74+
}
6375
`;
6476
}
6577

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,10 @@ export class VitestExecutor implements TestExecutor {
223223
reporters,
224224
setupFiles: testSetupFiles,
225225
projectPlugins,
226-
include: [...this.testFileToEntryPoint.keys()],
226+
include: [...this.testFileToEntryPoint.keys()].filter(
227+
// Filter internal entries
228+
(entry) => !entry.startsWith('angular:'),
229+
),
227230
}),
228231
],
229232
},

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ export function createVitestConfigPlugin(options: VitestConfigPluginOptions): Vi
125125
setupFiles: combinedSetupFiles,
126126
include,
127127
globals: testConfig?.globals ?? true,
128+
// Default to `false` to align with the Karma/Jasmine experience.
129+
isolate: testConfig?.isolate ?? false,
128130
...(browser ? { browser } : {}),
129131
// If the user has not specified an environment, use a smart default.
130132
...(!testConfig?.environment

0 commit comments

Comments
 (0)