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
21 changes: 20 additions & 1 deletion lib/internal/test_runner/coverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const { fileURLToPath, URL } = require('internal/url');
const { kMappings, SourceMap } = require('internal/source_map/source_map');
const {
codes: {
ERR_OPERATION_FAILED,
ERR_SOURCE_MAP_CORRUPT,
ERR_SOURCE_MAP_MISSING_SOURCE,
},
Expand Down Expand Up @@ -402,7 +403,7 @@ class TestCoverage {
}

const coverageFile = join(this.coverageDirectory, entry.name);
const coverage = JSONParse(readFileSync(coverageFile, 'utf8'));
const coverage = readCoverageFile(coverageFile);
this.mergeCoverage(result, this.mapCoverageWithSourceMap(coverage));
}

Expand Down Expand Up @@ -587,6 +588,24 @@ class TestCoverage {
}
}

function readCoverageFile(coverageFile) {
const rawCoverage = readFileSync(coverageFile, 'utf8');

if (rawCoverage.length === 0) {
throw new ERR_OPERATION_FAILED(`coverage file is empty: ${coverageFile}`);
}

try {
return JSONParse(rawCoverage);
} catch (err) {
const error = new ERR_OPERATION_FAILED(
`failed to parse coverage file ${coverageFile}: ${err.message}`,
);
error.cause = err;
throw error;
}
}

function toPercentage(covered, total) {
return total === 0 ? 100 : (covered / total) * 100;
}
Expand Down
45 changes: 31 additions & 14 deletions test/parallel/test-runner-coverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@ function getSpecCoverageFixtureReport() {
return report;
}

function formatSpawnSyncResult(result) {
return [
`status: ${result.status}`,
`signal: ${result.signal}`,
`stdout:\n${result.stdout}`,
`stderr:\n${result.stderr}`,
].join('\n');
}

function assertIncludesReport(result, report) {
assert(
result.stdout.toString().includes(report),
formatSpawnSyncResult(result),
);
}

test('test coverage report', async (t) => {
await t.test('handles the inspector not being available', (t) => {
if (process.features.inspector) {
Expand Down Expand Up @@ -111,7 +127,7 @@ test('test tap coverage reporter', skipIfNoInspector, async (t) => {
const options = { env: { ...process.env, NODE_V8_COVERAGE: tmpdir.path } };
const result = spawnSync(process.execPath, args, options);
const report = getTapCoverageFixtureReport();
assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.stderr.toString(), '');
assert.strictEqual(result.status, 0);
assert(findCoverageFileForPid(result.pid));
Expand All @@ -129,7 +145,7 @@ test('test tap coverage reporter', skipIfNoInspector, async (t) => {
const result = spawnSync(process.execPath, args);
const report = getTapCoverageFixtureReport();

assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.stderr.toString(), '');
assert.strictEqual(result.status, 0);
assert(!findCoverageFileForPid(result.pid));
Expand All @@ -149,7 +165,7 @@ test('test spec coverage reporter', skipIfNoInspector, async (t) => {
const result = spawnSync(process.execPath, args, options);
const report = getSpecCoverageFixtureReport();

assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.stderr.toString(), '');
assert.strictEqual(result.status, 0);
assert(findCoverageFileForPid(result.pid));
Expand All @@ -166,7 +182,7 @@ test('test spec coverage reporter', skipIfNoInspector, async (t) => {
const result = spawnSync(process.execPath, args);
const report = getSpecCoverageFixtureReport();

assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.stderr.toString(), '');
assert.strictEqual(result.status, 0);
assert(!findCoverageFileForPid(result.pid));
Expand All @@ -187,7 +203,7 @@ test('single process coverage is the same with --test', skipIfNoInspector, () =>
const report = getTapCoverageFixtureReport();

assert.strictEqual(result.stderr.toString(), '');
assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.status, 0);
assert(!findCoverageFileForPid(result.pid));
});
Expand Down Expand Up @@ -226,7 +242,7 @@ test('coverage is combined for multiple processes', skipIfNoInspector, () => {
});

assert.strictEqual(result.stderr.toString(), '');
assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.status, 0);
});

Expand Down Expand Up @@ -268,7 +284,7 @@ test.skip('coverage works with isolation=none', skipIfNoInspector, common.mustCa
});

assert.strictEqual(result.stderr.toString(), '');
assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.status, 0);
}, 0));

Expand All @@ -285,6 +301,7 @@ test('coverage reports on lines, functions, and branches', skipIfNoInspector, as
]);
assert.strictEqual(child.stderr.toString(), '');
const stdout = child.stdout.toString();
assert.notStrictEqual(stdout, '', formatSpawnSyncResult(child));
const coverage = JSON.parse(stdout);

await t.test('does not include node_modules', () => {
Expand Down Expand Up @@ -366,7 +383,7 @@ test('coverage with ESM hook - source irrelevant', skipIfNoInspector, () => {
const result = spawnSync(process.execPath, args, { cwd: fixture });

assert.strictEqual(result.stderr.toString(), '');
assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.status, 0);
});

Expand Down Expand Up @@ -401,7 +418,7 @@ test('coverage with ESM hook - source transpiled', skipIfNoInspector, () => {
const result = spawnSync(process.execPath, args, { cwd: fixture });

assert.strictEqual(result.stderr.toString(), '');
assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.status, 0);
});

Expand Down Expand Up @@ -435,7 +452,7 @@ test('coverage with excluded files', skipIfNoInspector, () => {
return report.replaceAll('/', '\\');
}

assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.status, 0);
assert(!findCoverageFileForPid(result.pid));
});
Expand Down Expand Up @@ -472,7 +489,7 @@ test('coverage with included files', skipIfNoInspector, () => {
return report.replaceAll('/', '\\');
}

assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.status, 0);
assert(!findCoverageFileForPid(result.pid));
});
Expand Down Expand Up @@ -506,7 +523,7 @@ test('coverage with included and excluded files', skipIfNoInspector, () => {
return report.replaceAll('/', '\\');
}

assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.status, 0);
assert(!findCoverageFileForPid(result.pid));
});
Expand Down Expand Up @@ -547,7 +564,7 @@ test('correctly prints the coverage report of files contained in parent director
});

assert.strictEqual(result.stderr.toString(), '');
assert(result.stdout.toString().includes(report));
assertIncludesReport(result, report);
assert.strictEqual(result.status, 0);
});

Expand All @@ -564,5 +581,5 @@ test('coverage with directory and file named "file"', skipIfNoInspector, () => {

assert.strictEqual(result.stderr.toString(), '');
assert.strictEqual(result.status, 0);
assert(result.stdout.toString().includes('start of coverage report'));
assertIncludesReport(result, 'start of coverage report');
});
Loading