Skip to content

Commit 0bba993

Browse files
committed
fix(@angular/build): dynamically select Vitest DOM environment
This change enhances the Vitest unit test builder to intelligently select the default DOM test environment (`jsdom` or `happy-dom`) based on which package is installed in the user's project. Previously, the builder strictly defaulted to `jsdom`. With this update: - The `validateDependencies` function now checks for the presence of either `jsdom` or `happy-dom` when browser-based tests are not configured, providing a more flexible dependency requirement. - A new `findTestEnvironment` helper function is introduced to detect the available DOM environment (`happy-dom` is preferred if installed, otherwise `jsdom`). - The `createVitestConfigPlugin` now uses this helper to dynamically set the `environment` in the Vitest configuration, ensuring a smart default if the user has not explicitly specified one. This improves the out-of-the-box experience by adapting to common project setups and offering more choice in DOM emulation.
1 parent a9c700a commit 0bba993

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

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
@@ -219,6 +219,7 @@ export class VitestExecutor implements TestExecutor {
219219
browser: browserOptions.browser,
220220
coverage,
221221
projectName,
222+
projectSourceRoot: this.options.projectSourceRoot,
222223
reporters,
223224
setupFiles: testSetupFiles,
224225
projectPlugins,

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@ const VitestTestRunner: TestRunner = {
3333
);
3434
}
3535
} else {
36-
// JSDOM is used when no browsers are specified
37-
checker.check('jsdom');
36+
// DOM emulation is used when no browsers are specified
37+
checker.checkAny(
38+
['jsdom', 'happy-dom'],
39+
'A DOM environment is required for non-browser tests. Please install either "jsdom" or "happy-dom".',
40+
);
3841
}
3942

4043
if (options.coverage.enabled) {

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

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import assert from 'node:assert';
1010
import { readFile } from 'node:fs/promises';
11+
import { createRequire } from 'node:module';
1112
import path from 'node:path';
1213
import type {
1314
BrowserConfigOptions,
@@ -36,20 +37,44 @@ interface VitestConfigPluginOptions {
3637
browser: BrowserConfigOptions | undefined;
3738
coverage: NormalizedUnitTestBuilderOptions['coverage'];
3839
projectName: string;
40+
projectSourceRoot: string;
3941
reporters?: string[] | [string, object][];
4042
setupFiles: string[];
4143
projectPlugins: VitestPlugins;
4244
include: string[];
4345
}
4446

47+
async function findTestEnvironment(
48+
projectResolver: NodeJS.RequireResolve,
49+
): Promise<'jsdom' | 'happy-dom'> {
50+
try {
51+
projectResolver('happy-dom');
52+
53+
return 'happy-dom';
54+
} catch {
55+
// happy-dom is not installed, fallback to jsdom
56+
return 'jsdom';
57+
}
58+
}
59+
4560
export function createVitestConfigPlugin(options: VitestConfigPluginOptions): VitestPlugins[0] {
46-
const { include, browser, projectName, reporters, setupFiles, projectPlugins } = options;
61+
const {
62+
include,
63+
browser,
64+
projectName,
65+
reporters,
66+
setupFiles,
67+
projectPlugins,
68+
projectSourceRoot,
69+
} = options;
4770

4871
return {
4972
name: 'angular:vitest-configuration',
5073
async config(config) {
5174
const testConfig = config.test;
5275

76+
const projectResolver = createRequire(projectSourceRoot + '/').resolve;
77+
5378
const projectConfig: UserWorkspaceConfig = {
5479
test: {
5580
...testConfig,
@@ -58,8 +83,10 @@ export function createVitestConfigPlugin(options: VitestConfigPluginOptions): Vi
5883
include,
5984
globals: testConfig?.globals ?? true,
6085
...(browser ? { browser } : {}),
61-
// If the user has not specified an environment, use `jsdom`.
62-
...(!testConfig?.environment ? { environment: 'jsdom' } : {}),
86+
// If the user has not specified an environment, use a smart default.
87+
...(!testConfig?.environment
88+
? { environment: await findTestEnvironment(projectResolver) }
89+
: {}),
6390
},
6491
optimizeDeps: {
6592
noDiscovery: true,

0 commit comments

Comments
 (0)