Skip to content

Commit c9448fe

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 efd1180 commit c9448fe

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

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

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

99
import type { BuilderOutput } from '@angular-devkit/architect';
1010
import assert from 'node:assert';
11-
import path, { join } from 'node:path';
11+
import { createRequire } from 'node:module';
12+
import path from 'node:path';
1213
import type { Vitest } from 'vitest/node';
1314
import {
1415
DevServerExternalResultMetadata,
@@ -126,7 +127,7 @@ export class VitestExecutor implements TestExecutor {
126127
await this.vitest?.close();
127128
}
128129

129-
private prepareSetupFiles(): string[] {
130+
private prepareSetupFiles(sourcemapSupport: boolean): string[] {
130131
const { setupFiles } = this.options;
131132
// Add setup file entries for TestBed initialization and project polyfills
132133
const testSetupFiles = ['init-testbed.js', ...setupFiles];
@@ -136,6 +137,12 @@ export class VitestExecutor implements TestExecutor {
136137
testSetupFiles.unshift('polyfills.js');
137138
}
138139

140+
// Resolve and add sourcemap support (mainly for browsers)
141+
if (sourcemapSupport) {
142+
const packageResolve = createRequire(__filename).resolve;
143+
testSetupFiles.unshift(packageResolve('source-map-support/browser-source-map-support.js'));
144+
}
145+
139146
return testSetupFiles;
140147
}
141148

@@ -187,7 +194,7 @@ export class VitestExecutor implements TestExecutor {
187194
'buildResult must be available before initializing vitest',
188195
);
189196

190-
const testSetupFiles = this.prepareSetupFiles();
197+
const testSetupFiles = this.prepareSetupFiles(!!browserOptions.browser?.enabled);
191198
const projectPlugins = createVitestPlugins({
192199
workspaceRoot,
193200
projectSourceRoot,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import assert from 'node:assert/strict';
2+
import { applyVitestBuilder } from '../../utils/vitest';
3+
import { ng } 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+
throw new Error('This is a failing test');
20+
});
21+
});
22+
`,
23+
);
24+
25+
try {
26+
await ng(
27+
'test',
28+
'--no-watch',
29+
'--browsers',
30+
'chromiumHeadless',
31+
);
32+
throw new Error('Expected "ng test" to fail.');
33+
} catch (error: any) {
34+
const stdout = error.stdout || error.message;
35+
// We expect the failure from failing.spec.ts
36+
assert.match(stdout, /1 failed/, 'Expected 1 test to fail.');
37+
// Check that the stack trace points to the correct file
38+
assert.match(stdout, /src\/app\/failing\.spec\.ts:\d+:\d+/, 'Expected stack trace to point to the source file.');
39+
}
40+
}

0 commit comments

Comments
 (0)