Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f9d3099

Browse files
committed
fix(@angular/build): inject source-map-support for Vitest browser tests
This change ensures that `source-map-support` is injected into the setup files when running Vitest tests in a browser environment. This allows stack traces from failing tests to correctly map back to the original source files, significantly improving debugging capabilities. A regression test has been added to `tests/vitest/browser-sourcemaps.ts` to verify that a failing test correctly identifies the source file in its stack trace.
1 parent edeb41c commit f9d3099

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
import { createRequire } from 'node:module';
910
import path from 'node:path';
1011
import { toPosixPath } from '../../../../utils/path';
1112
import type { ApplicationBuilderInternalOptions } from '../../../application/options';
@@ -18,6 +19,7 @@ function createTestBedInitVirtualFile(
1819
providersFile: string | undefined,
1920
projectSourceRoot: string,
2021
polyfills: string[] = [],
22+
sourcemapSupport: boolean = false,
2123
): string {
2224
const usesZoneJS = polyfills.includes('zone.js');
2325
let providersImport = 'const providers = [];';
@@ -28,13 +30,26 @@ function createTestBedInitVirtualFile(
2830
providersImport = `import providers from './${importPath}';`;
2931
}
3032

33+
// Resolve and add sourcemap support (mainly for browsers)
34+
let sourceMapSetup;
35+
if (sourcemapSupport) {
36+
const packageResolve = createRequire(__filename).resolve;
37+
const sourceMapPath = packageResolve('source-map-support');
38+
39+
sourceMapSetup = `
40+
import sourceMapSupport from '${sourceMapPath}';
41+
sourceMapSupport.install();
42+
`;
43+
}
44+
3145
return `
3246
// Initialize the Angular testing environment
3347
import { NgModule${usesZoneJS ? ', provideZoneChangeDetection' : ''} } from '@angular/core';
3448
import { getTestBed, ɵgetCleanupHook as getCleanupHook } from '@angular/core/testing';
3549
import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';
3650
import { afterEach, beforeEach } from 'vitest';
3751
${providersImport}
52+
${sourceMapSetup}
3853
3954
// The beforeEach and afterEach hooks are registered outside the globalThis guard.
4055
// This ensures that the hooks are always applied, even in non-isolated browser environments.
@@ -98,8 +113,13 @@ export async function getVitestBuildOptions(
98113
});
99114
entryPoints.set('init-testbed', 'angular:test-bed-init');
100115

116+
const hasBrowsers = !!options.browsers?.length;
117+
101118
// The 'vitest' package is always external for testing purposes
102119
const externalDependencies = ['vitest'];
120+
if (hasBrowsers) {
121+
externalDependencies.push('source-map');
122+
}
103123
if (baseBuildOptions.externalDependencies) {
104124
externalDependencies.push(...baseBuildOptions.externalDependencies);
105125
}
@@ -134,6 +154,7 @@ export async function getVitestBuildOptions(
134154
providersFile,
135155
projectSourceRoot,
136156
buildOptions.polyfills,
157+
hasBrowsers,
137158
);
138159

139160
return {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import assert from 'node:assert/strict';
2+
import { applyVitestBuilder } from '../../utils/vitest';
3+
import { ng, noSilentNg } from '../../utils/process';
4+
import { installPackage } from '../../utils/packages';
5+
import { writeFile } from '../../utils/fs';
6+
7+
export default async function (): Promise<void> {
8+
await applyVitestBuilder();
9+
await installPackage('playwright@1');
10+
await installPackage('@vitest/browser-playwright@4');
11+
await ng('generate', 'component', 'my-comp');
12+
13+
// Add a failing test to verify source map support
14+
await writeFile(
15+
'src/app/failing.spec.ts',
16+
`
17+
describe('Failing Test', () => {
18+
it('should fail', () => {
19+
expect(true).toBe(false);
20+
});
21+
});
22+
`,
23+
);
24+
25+
try {
26+
await noSilentNg('test', '--no-watch', '--browsers', 'chromiumHeadless');
27+
throw new Error('Expected "ng test" to fail.');
28+
} catch (error: any) {
29+
const stdout = error.stdout || error.message;
30+
// We expect the failure from failing.spec.ts
31+
assert.match(stdout, /1failed/, 'Expected 1 test to fail.');
32+
// Check that the stack trace points to the correct file
33+
assert.match(
34+
stdout,
35+
/src\/app\/failing\.spec\.ts:\d+:\d+/,
36+
'Expected stack trace to point to the source file.',
37+
);
38+
}
39+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /