import assert from 'node:assert/strict';
import { glob, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { dirname, join } from 'node:path';
import { after, before, describe, it } from 'node:test';
import {
classifyWarning,
composeCoverageConfig,
discoverCoverageConfigs,
loadPackageCoverageConfig,
rebasePackageGlob,
} from './coverage-config.js';
const packagePolicy = {
include: ['src/**/*.{ts,tsx}'],
exclude: ['dist/**', '**/*.test.ts'],
thresholds: { lines: 90, branches: 80, functions: 70, statements: 60 },
};
async function writeJson(root, path, value) {
const file = join(root, path);
await mkdir(dirname(file), { recursive: true });
await writeFile(file, `${JSON.stringify(value, null, 2)}\n`);
}
async function writeProject(root, packageDir, policy = packagePolicy) {
await writeJson(root, `${packageDir}/coverage.config.json`, policy);
await writeFile(join(root, packageDir, 'vitest.config.ts'), 'export default { test: {} };\n');
}
async function writeRootPolicy(root, value = { warningOnly: [], excludedPackages: [] }) {
await writeJson(root, 'coverage.config.json', value);
}
function warning(overrides = {}) {
return {
package: 'group/a',
reason: 'Coverage recovery needs dedicated tests.',
addedDate: '2026-01-01',
expiryDays: 10,
assignee: null,
linear: null,
notes: null,
...overrides,
};
}
describe('coverage config', () => {
let root;
before(async () => {
root = await mkdtemp(join(tmpdir(), 'coverage-config-'));
});
after(async () => {
await rm(root, { recursive: true, force: true });
});
it('discovers package policies in deterministic order', async () => {
await writeProject(root, 'packages/z');
await writeProject(root, 'packages/a');
const configs = discoverCoverageConfigs(root);
assert.deepEqual(
configs.map(({ packageDir }) => packageDir),
['packages/a', 'packages/z'],
);
});
it('rebases package globs without expanding braces', () => {
assert.equal(
rebasePackageGlob('packages/group/a', 'src/**/*.{ts,tsx}'),
'packages/group/a/src/**/*.{ts,tsx}',
);
});
it('composes includes, excludes, empty thresholds, and full thresholds', async () => {
const fixture = await mkdtemp(join(tmpdir(), 'coverage-compose-'));
try {
await writeRootPolicy(fixture);
await writeProject(fixture, 'packages/group/a', packagePolicy);
await writeProject(fixture, 'packages/group/b', {
include: [],
exclude: [],
thresholds: {},
});
assert.deepEqual(composeCoverageConfig(fixture, new Date('2026-01-01T12:00:00Z')), {
include: ['packages/group/a/src/**/*.{ts,tsx}'],
exclude: ['packages/group/a/dist/**', 'packages/group/a/**/*.test.ts'],
thresholds: {
'packages/group/a/**': packagePolicy.thresholds,
'packages/group/b/**': {},
},
});
} finally {
await rm(fixture, { recursive: true, force: true });
}
});
it('keeps warnings active through the expiry date', () => {
assert.deepEqual(classifyWarning(warning(), new Date('2026-01-11T23:59:59Z')), {
expiryDate: '2026-01-11',
active: true,
});
assert.deepEqual(classifyWarning(warning(), new Date('2026-01-12T00:00:00Z')), {
expiryDate: '2026-01-11',
active: false,
});
});
it('omits active-warning thresholds but retains expired thresholds', async () => {
const fixture = await mkdtemp(join(tmpdir(), 'coverage-warning-'));
try {
await writeProject(fixture, 'packages/group/a');
await writeProject(fixture, 'packages/group/b');
await writeRootPolicy(fixture, {
warningOnly: [warning(), warning({ package: 'group/b', addedDate: '2025-01-01' })],
excludedPackages: [],
});
assert.deepEqual(
composeCoverageConfig(fixture, new Date('2026-01-11T12:00:00Z')).thresholds,
{ 'packages/group/b/**': packagePolicy.thresholds },
);
} finally {
await rm(fixture, { recursive: true, force: true });
}
});
it('omits excluded packages from collection and composition', async () => {
const fixture = await mkdtemp(join(tmpdir(), 'coverage-excluded-'));
try {
await writeProject(fixture, 'packages/group/a');
await writeProject(fixture, 'packages/group/b');
await writeRootPolicy(fixture, {
warningOnly: [],
excludedPackages: ['group/a'],
});
assert.deepEqual(composeCoverageConfig(fixture, new Date('2026-01-01T12:00:00Z')), {
include: ['packages/group/b/src/**/*.{ts,tsx}'],
exclude: ['packages/group/b/dist/**', 'packages/group/b/**/*.test.ts'],
thresholds: { 'packages/group/b/**': packagePolicy.thresholds },
});
} finally {
await rm(fixture, { recursive: true, force: true });
}
});
it('rejects malformed, unknown, unsafe, and out-of-range package policies', async () => {
const invalid = [
{ include: [], exclude: [] },
{ include: [], exclude: [], thresholds: {}, extra: true },
{ include: ['/src/**'], exclude: [], thresholds: {} },
{ include: ['src\\**'], exclude: [], thresholds: {} },
{ include: ['../src/**'], exclude: [], thresholds: {} },
{ include: ['{src,..}/**'], exclude: [], thresholds: {} },
{ include: [], exclude: [], thresholds: { lines: -1 } },
{ include: [], exclude: [], thresholds: { lines: 101 } },
{ include: [], exclude: [], thresholds: { lines: 90.5 } },
{ include: [], exclude: [], thresholds: { unknown: 90 } },
];
for (const [index, policy] of invalid.entries()) {
const path = join(root, `invalid-${index}.json`);
await writeFile(path, JSON.stringify(policy));
assert.throws(() => loadPackageCoverageConfig(path));
}
});
it('accepts threshold boundaries', async () => {
const path = join(root, 'boundaries.json');
const policy = {
include: [],
exclude: [],
thresholds: { lines: 0, branches: 100, functions: 0, statements: 100 },
};
await writeFile(path, JSON.stringify(policy));
assert.deepEqual(loadPackageCoverageConfig(path), policy);
});
it('rejects malformed warning entries and unsafe excluded packages', async () => {
const fixture = await mkdtemp(join(tmpdir(), 'coverage-root-invalid-'));
try {
const invalid = [
{ warningOnly: [{ ...warning(), unknown: true }], excludedPackages: [] },
{ warningOnly: [warning({ addedDate: '2026-02-30' })], excludedPackages: [] },
{ warningOnly: [warning({ package: './group/a' })], excludedPackages: [] },
{ warningOnly: [warning({ package: 'group/./a' })], excludedPackages: [] },
{ warningOnly: [], excludedPackages: ['../group/a'] },
{ warningOnly: [], excludedPackages: ['packages/group/a'] },
{ warningOnly: [], excludedPackages: ['./group/a'] },
{ warningOnly: [], excludedPackages: ['group//a'] },
{ warningOnly: [], excludedPackages: ['C:group/a'] },
];
for (const policy of invalid) {
await writeRootPolicy(fixture, policy);
assert.throws(() => composeCoverageConfig(fixture, new Date('2026-01-01T12:00:00Z')));
}
} finally {
await rm(fixture, { recursive: true, force: true });
}
});
it('rejects duplicate warning and excluded package entries', async () => {
const fixture = await mkdtemp(join(tmpdir(), 'coverage-duplicates-'));
try {
await writeRootPolicy(fixture, {
warningOnly: [warning(), warning()],
excludedPackages: [],
});
assert.throws(() => composeCoverageConfig(fixture, new Date('2026-01-01T12:00:00Z')));
await writeRootPolicy(fixture, {
warningOnly: [],
excludedPackages: ['group/a', 'group/a'],
});
assert.throws(() => composeCoverageConfig(fixture, new Date('2026-01-01T12:00:00Z')));
} finally {
await rm(fixture, { recursive: true, force: true });
}
});
it('runs package coverage once from the root without package entry points', async () => {
const repositoryRoot = join(import.meta.dirname, '..');
const rootManifest = JSON.parse(await readFile(join(repositoryRoot, 'package.json'), 'utf8'));
assert.equal(
rootManifest.scripts['coverage:packages'],
"turbo run build --filter='!./examples/**' --filter='!./test/**' && vitest run --coverage",
);
assert.equal(rootManifest.scripts['test:coverage'], 'pnpm coverage:packages');
assert.equal(
rootManifest.scripts['coverage:packages:merge'],
'vitest --merge-reports=.vitest/blob --coverage',
);
assert.equal(rootManifest.scripts['coverage:report'], 'node scripts/coverage-report.mjs');
for await (const path of glob('packages/**/package.json', { cwd: repositoryRoot })) {
const manifest = JSON.parse(await readFile(join(repositoryRoot, path), 'utf8'));
assert.equal(manifest.scripts?.['test:coverage'], undefined, path);
assert.equal(manifest.scripts?.['~test:coverage'], undefined, path);
}
const turbo = await readFile(join(repositoryRoot, 'turbo.json'), 'utf8');
assert.doesNotMatch(turbo, /^\s*"test:coverage"\s*:/m);
const rootVitestConfig = await readFile(join(repositoryRoot, 'vitest.config.ts'), 'utf8');
assert.match(rootVitestConfig, /from ['"]\.\/scripts\/coverage-config['"]/);
assert.doesNotMatch(rootVitestConfig, /from ['"]\.\/scripts\/coverage-config\.[^'"]+['"]/);
assert.match(rootVitestConfig, /provider:\s*['"]v8['"]/);
assert.match(rootVitestConfig, /process\.env\[['"]VITEST_COVERAGE_SHARD['"]\]/);
assert.match(
rootVitestConfig,
/thresholds:\s*coverageShard\s*\?\s*\{\}\s*:\s*coveragePolicy\.thresholds/,
);
assert.match(rootVitestConfig, /reportOnFailure:\s*true/);
});
it('fans sharded coverage artifacts into one stable Test gate', async () => {
const repositoryRoot = join(import.meta.dirname, '..');
const workflow = await readFile(join(repositoryRoot, '.github/workflows/ci.yml'), 'utf8');
const shardJob = workflow.match(
/\n {2}test-packages:\n(?<body>[\s\S]*?)(?=\n {2}test-examples:\n)/,
)?.groups?.body;
const examplesJob = workflow.match(
/\n {2}test-examples:\n(?<body>[\s\S]*?)(?=\n {2}coverage:\n)/,
)?.groups?.body;
const coverageJob = workflow.match(/\n {2}coverage:\n(?<body>[\s\S]*?)(?=\n {2}test:\n)/)
?.groups?.body;
const testJob = workflow.match(/\n {2}test:\n(?<body>[\s\S]*?)(?=\n {2}test-e2e:\n)/)?.groups
?.body;
assert.ok(shardJob);
assert.match(shardJob, /^ {4}name: Package Tests \(\$\{\{ matrix\.index \}\}\/4\)$/m);
assert.match(shardJob, /^ {4}if: needs\.changes\.outputs\.inert != 'true'$/m);
assert.match(shardJob, /index: \[1, 2, 3, 4\]/);
assert.match(shardJob, /VITEST_COVERAGE_SHARD: \$\{\{ matrix\.index \}\}/);
assert.match(
shardJob,
/run: pnpm coverage:packages --reporter=default --reporter=github-actions --reporter=blob --shard=\$\{\{ matrix\.index \}\}\/4/,
);
assert.match(
shardJob,
/uses: actions\/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a/,
);
assert.match(shardJob, /name: package-coverage-\$\{\{ matrix\.index \}\}/);
assert.match(shardJob, /path: \.vitest\/blob\/blob-\$\{\{ matrix\.index \}\}-4\.json/);
assert.match(shardJob, /if-no-files-found: error/);
assert.match(shardJob, /include-hidden-files: true/);
assert.match(
shardJob,
/continue-on-error: true[\s\S]*if: steps\.package-tests\.outcome == 'failure'\n {8}run: exit 1/,
);
assert.ok(examplesJob);
assert.match(examplesJob, /^ {4}name: Test Examples$/m);
assert.match(examplesJob, /^ {4}needs: \[build, changes\]$/m);
assert.match(examplesJob, /run: pnpm test:examples/);
assert.ok(coverageJob);
assert.match(coverageJob, /^ {4}name: Coverage$/m);
assert.match(coverageJob, /^ {4}needs: \[build, changes, test-packages\]$/m);
assert.doesNotMatch(coverageJob, /^ {4}services:/m);
assert.match(
coverageJob,
/uses: actions\/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c/,
);
assert.match(coverageJob, /pattern: package-coverage-\*/);
assert.match(coverageJob, /path: \.vitest\/blob/);
assert.match(coverageJob, /merge-multiple: true/);
assert.equal(coverageJob.match(/test -f \.vitest\/blob\/blob-[1-4]-4\.json/g)?.length, 4);
assert.match(
coverageJob,
/run: pnpm coverage:packages:merge\n {6}- name: Report package coverage\n {8}if: \$\{\{ !cancelled\(\) \}\}\n {8}run: pnpm coverage:report/,
);
assert.ok(testJob);
assert.match(testJob, /^ {4}name: Test$/m);
assert.match(
testJob,
/^ {4}needs: \[build, changes, test-packages, test-examples, coverage, test-integration\]$/m,
);
assert.match(testJob, /needs\.test-packages\.result != 'success'/);
assert.match(testJob, /needs\.test-examples\.result != 'success'/);
assert.match(testJob, /needs\.coverage\.result != 'success'/);
assert.match(testJob, /run: exit 1/);
assert.doesNotMatch(shardJob, /actions\/cache\/(?:save|restore)@/);
assert.doesNotMatch(coverageJob, /actions\/cache\/(?:save|restore)@/);
assert.equal(workflow.match(/run: pnpm coverage:packages:merge/g)?.length, 1);
assert.equal(workflow.match(/run: pnpm coverage:report/g)?.length, 1);
assert.equal(workflow.match(/run: pnpm test:examples/g)?.length, 1);
});
it('runs the integration shards only in the merge queue, where Test requires them', async () => {
const repositoryRoot = join(import.meta.dirname, '..');
const workflow = await readFile(join(repositoryRoot, '.github/workflows/ci.yml'), 'utf8');
const integrationJob = workflow.match(
/\n {2}test-integration:\n(?<body>[\s\S]*?)(?=\n {2}\S|\n {2}# )/,
)?.groups?.body;
const testJob = workflow.match(/\n {2}test:\n(?<body>[\s\S]*?)(?=\n {2}test-e2e:\n)/)?.groups
?.body;
assert.ok(integrationJob);
assert.match(
integrationJob,
/^ {4}if: github\.event_name == 'merge_group' && needs\.changes\.outputs\.inert != 'true'$/m,
);
assert.match(integrationJob, /shard: \['1\/4', '2\/4', '3\/4', '4\/4'\]/);
assert.match(integrationJob, /uses: \.\/\.github\/actions\/integration-tests/);
assert.ok(testJob);
assert.match(testJob, /^ {4}needs: \[[^\]]*\btest-integration\b[^\]]*\]$/m);
assert.match(
testJob,
/- name: Require integration tests in the merge queue\n {8}if: \$\{\{ github\.event_name == 'merge_group' && needs\.changes\.outputs\.inert != 'true' && needs\.test-integration\.result != 'success' \}\}\n {8}run: exit 1/,
);
});
});