Skip to content

Commit 1e39c77

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 bc48163 commit 1e39c77

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ export async function createVitestConfigPlugin(
112112
delete config.plugins;
113113
}
114114

115+
// Add browser source map support
116+
if (browser || testConfig?.browser?.enabled) {
117+
projectPlugins.unshift(createSourcemapSupportPlugin());
118+
setupFiles.unshift('virtual:source-map-support');
119+
}
120+
115121
const projectResolver = createRequire(projectSourceRoot + '/').resolve;
116122

117123
const projectDefaults: UserWorkspaceConfig = {
@@ -310,6 +316,36 @@ export function createVitestPlugins(pluginOptions: PluginOptions): VitestPlugins
310316
];
311317
}
312318

319+
function createSourcemapSupportPlugin(): VitestPlugins[0] {
320+
return {
321+
name: 'angular:source-map-support',
322+
enforce: 'pre',
323+
resolveId(source) {
324+
if (source.includes('virtual:source-map-support')) {
325+
return '\0source-map-support';
326+
}
327+
},
328+
async load(id) {
329+
if (id !== '\0source-map-support') {
330+
return;
331+
}
332+
333+
const packageResolve = createRequire(__filename).resolve;
334+
const supportPath = packageResolve('source-map-support/browser-source-map-support.js');
335+
336+
const content = await readFile(supportPath, 'utf-8');
337+
338+
// The `source-map-support` library currently relies on `this` being defined in the global scope.
339+
// However, when running in an ESM environment, `this` is undefined.
340+
// To workaround this, we patch the library to use `globalThis` instead of `this`.
341+
return (
342+
content.replaceAll(/this\.(define|sourceMapSupport|base64js)/g, 'globalThis.$1') +
343+
'\n;globalThis.sourceMapSupport.install();'
344+
);
345+
},
346+
};
347+
}
348+
313349
async function generateCoverageOption(
314350
optionsCoverage: NormalizedUnitTestBuilderOptions['coverage'],
315351
configCoverage: VitestCoverageOption | undefined,
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, noSilentNg } from '../../utils/process';
4+
import { installPackage } from '../../utils/packages';
5+
import { writeFile } from '../../utils/fs';
6+
import { stripVTControlCharacters } from 'node:util';
7+
8+
export default async function (): Promise<void> {
9+
await applyVitestBuilder();
10+
await installPackage('playwright@1');
11+
await installPackage('@vitest/browser-playwright@4');
12+
await ng('generate', 'component', 'my-comp');
13+
14+
// Add a failing test to verify source map support
15+
await writeFile(
16+
'src/app/failing.spec.ts',
17+
`
18+
describe('Failing Test', () => {
19+
it('should fail', () => {
20+
expect(true).toBe(false);
21+
});
22+
});
23+
`,
24+
);
25+
26+
try {
27+
await noSilentNg('test', '--no-watch', '--browsers', 'chromiumHeadless');
28+
throw new Error('Expected "ng test" to fail.');
29+
} catch (error: any) {
30+
const stdout = stripVTControlCharacters(error.stdout || error.message);
31+
// We expect the failure from failing.spec.ts
32+
assert.match(stdout, /1 failed/, 'Expected 1 test to fail.');
33+
// Check that the stack trace points to the correct file
34+
assert.match(
35+
stdout,
36+
/\bsrc[\/\\]app[\/\\]failing\.spec\.ts:4:\d+/,
37+
'Expected stack trace to point to the source file.',
38+
);
39+
}
40+
}

0 commit comments

Comments
 (0)