Skip to content
Merged
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 @@ -285,7 +285,10 @@ async function generateCoverageOption(
return {
enabled: coverage.enabled,
excludeAfterRemap: true,
include: coverage.include,
// Vitest performs a pre-check and a post-check for sourcemaps.
// The pre-check uses the bundled files, so specific bundled entry points and chunks need to be included.
// The post-check uses the original source files, so the user's include is used.
...(coverage.include ? { include: ['spec-*.js', 'chunk-*.js', ...coverage.include] } : {}),
reportsDirectory: toPosixPath(path.join('coverage', projectName)),
thresholds: coverage.thresholds,
watermarks: coverage.watermarks,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/

import { execute } from '../../index';
import {
BASE_OPTIONS,
describeBuilder,
UNIT_TEST_BUILDER_INFO,
setupApplicationTarget,
} from '../setup';

describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => {
describe('Option: "coverageInclude"', () => {
beforeEach(async () => {
setupApplicationTarget(harness);
await harness.writeFiles({
'src/app/included.ts': `export const a = 1;`,
'src/app/included.spec.ts': `
import { a } from './included';
describe('included', () => {
it('should work', () => {
expect(a).toBe(1);
});
});
`,
'src/app/excluded.ts': `export const b = 2;`,
});
});

it('should only include and report coverage for files that match the glob pattern', async () => {
harness.useTarget('test', {
...BASE_OPTIONS,
coverage: true,
coverageInclude: ['**/included.ts'],
});

const { result } = await harness.executeOnce();
expect(result?.success).toBeTrue();

const summary = JSON.parse(harness.readFile('coverage/test/coverage-final.json'));
const summaryKeys = Object.keys(summary);

const includedKey = summaryKeys.find((key) => key.endsWith('src/app/included.ts'));
const excludedKey = summaryKeys.find((key) => key.endsWith('src/app/excluded.ts'));

// Check that the included file is in the report and the excluded one is not.
expect(includedKey).toBeDefined();
expect(excludedKey).toBeUndefined();

// Check that the coverage data for the included file is valid.
const includedCoverage = summary[includedKey!];
// The file has one statement, and it should have been executed once.
expect(includedCoverage.s['0']).toBe(1);
});

it('should only include referenced files when no include pattern is provided', async () => {
harness.useTarget('test', {
...BASE_OPTIONS,
coverage: true,
// coverageInclude is not provided, so only referenced files should be included.
});

const { result } = await harness.executeOnce();
expect(result?.success).toBeTrue();
const summary = JSON.parse(harness.readFile('coverage/test/coverage-final.json'));
const summaryKeys = Object.keys(summary);

const includedKey = summaryKeys.find((key) => key.endsWith('src/app/included.ts'));
const excludedKey = summaryKeys.find((key) => key.endsWith('src/app/excluded.ts'));

// The included file is referenced by its spec and should be in the report.
expect(includedKey).toBeDefined();
// The excluded file is not referenced and should NOT be in the report.
expect(excludedKey).toBeUndefined();
});
});
});