Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,12 @@ export async function createVitestConfigPlugin(
delete config.plugins;
}

// Add browser source map support if coverage is enabled
// Validate browser coverage support if coverage is enabled
if (
(browser || testConfig?.browser?.enabled) &&
(options.coverage.enabled || testConfig?.coverage?.enabled)
) {
// Validate that enabled browsers support the selected coverage provider
validateBrowserCoverage(browser, testConfig?.browser, determinedProvider);

projectPlugins.unshift(createSourcemapSupportPlugin());
setupFiles.unshift('virtual:source-map-support');
}

const projectResolver = createRequire(projectSourceRoot + '/').resolve;
Expand Down Expand Up @@ -408,7 +404,7 @@ export function createVitestPlugins(pluginOptions: PluginOptions): VitestPlugins

const map = sourceMapText ? JSON.parse(sourceMapText) : undefined;
if (map) {
adjustSourcemapSources(map, !vitestConfig?.coverage?.enabled, workspaceRoot, id);
adjustSourcemapSources(map, true, workspaceRoot, id);
}

return {
Expand Down Expand Up @@ -475,36 +471,6 @@ function adjustSourcemapSources(
}
}

function createSourcemapSupportPlugin(): VitestPlugins[0] {
return {
name: 'angular:source-map-support',
enforce: 'pre',
resolveId(source) {
if (source.includes('virtual:source-map-support')) {
return '\0source-map-support';
}
},
async load(id) {
if (id !== '\0source-map-support') {
return;
}

const packageResolve = createRequire(__filename).resolve;
const supportPath = packageResolve('source-map-support/browser-source-map-support.js');

const content = await readFile(supportPath, 'utf-8');

// The `source-map-support` library currently relies on `this` being defined in the global scope.
// However, when running in an ESM environment, `this` is undefined.
// To workaround this, we patch the library to use `globalThis` instead of `this`.
return (
content.replaceAll(/this\.(define|sourceMapSupport|base64js)/g, 'globalThis.$1') +
'\n;globalThis.sourceMapSupport.install();'
);
},
};
}

interface CustomBrowserConfigOptions {
enabled?: boolean;
instances?: { browser: string }[];
Expand Down
43 changes: 43 additions & 0 deletions tests/e2e/tests/vitest/browser-coverage-sourcemaps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import assert from 'node:assert/strict';
import { applyVitestBuilder } from '../../utils/vitest';
import { ng } from '../../utils/process';
import { installPackage } from '../../utils/packages';
import { expectFileToExist, readFile } from '../../utils/fs';

export default async function (): Promise<void> {
await applyVitestBuilder();
await installPackage('playwright@1');
await installPackage('@vitest/browser-playwright@4');
await installPackage('@vitest/coverage-v8@4');
Comment thread
clydin marked this conversation as resolved.

// Run tests with coverage in browser mode.
// We use the default passing tests generated for the project.
const { stdout } = await ng(
'test',
'--no-watch',
'--browsers',
'chromiumHeadless',
'--coverage',
'--coverage-reporters=json-summary',
);

// Verify that tests passed
assert.match(stdout, /pass/, 'Expected tests to run successfully.');

// Verify that coverage files are generated
const summaryPath = 'coverage/test-project/coverage-summary.json';
await expectFileToExist(summaryPath);

const summary = JSON.parse(await readFile(summaryPath));

// Find the key for app.ts (it might be an absolute path)
const appFileKey = Object.keys(summary).find((key) => key.endsWith('app.ts'));
assert.ok(appFileKey, 'Expected coverage summary to contain app.ts.');

const appCoverage = summary[appFileKey];
assert.ok(appCoverage.lines.pct > 0, 'Expected lines percentage to be greater than 0.');

// Also verify that spec files are NOT present in the summary
const specFileKey = Object.keys(summary).find((key) => key.endsWith('.spec.ts'));
assert.ok(!specFileKey, 'Expected coverage report to not contain .spec.ts files.');
}
Loading