test_runner: print coverage and diagnostic info with dot reporter

When using the dot reporter with coverage enabled, coverage threshold
failures and coverage reports were not printed, only an exit code was
returned. This made it impossible to know why the test run failed.

This change adds handling for test:diagnostic and test:coverage events
to the dot reporter, matching the behavior of the spec reporter.

Fixes: https://github.com/nodejs/node/issues/60884
Signed-off-by: mag123c <diehreo@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/61423
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: Xuguang Mei <meixuguang@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
This commit is contained in:
mag123c authored and Kamat, Trivikram committed 2026-08-22 12:09:19 -07:00
1 parent 4b3bba58dd
commit 2858f34652
5 files changed
+95 -1

No files matched your search

+24 -1
View File
@@ -4,12 +4,19 @@ const {
MathMax,
} = primordials;
const colors = require('internal/util/colors');
const { formatTestReport } = require('internal/test_runner/reporter/utils');
const { getCoverageReport } = require('internal/test_runner/utils');
const {
formatTestReport,
reporterColorMap,
reporterUnicodeSymbolMap,
} = require('internal/test_runner/reporter/utils');
module.exports = async function* dot(source) {
let count = 0;
let columns = getLineLength();
const failedTests = [];
const diagnostics = [];
let coverage;
for await (const { type, data } of source) {
if (type === 'test:pass') {
yield `${colors.green}.${colors.reset}`;
@@ -25,8 +32,24 @@ module.exports = async function* dot(source) {
columns = getLineLength();
count = 0;
}
if (type === 'test:diagnostic' && data.level === 'error') {
ArrayPrototypePush(diagnostics, data);
}
if (type === 'test:coverage') {
coverage = data;
}
}
yield '\n';
if (diagnostics.length > 0) {
for (const diagnostic of diagnostics) {
const color = reporterColorMap[diagnostic.level] || reporterColorMap['test:diagnostic'];
yield `${color}${reporterUnicodeSymbolMap['test:diagnostic']}${diagnostic.message}${colors.white}\n`;
}
if (coverage) {
yield getCoverageReport('', coverage.summary,
reporterUnicodeSymbolMap['test:coverage'], colors.blue, true);
}
}
if (failedTests.length > 0) {
yield `\n${colors.red}Failed tests:${colors.white}\n\n`;
for (const test of failedTests) {
@@ -0,0 +1,17 @@
'use strict';
require('../../../common');
const fixtures = require('../../../common/fixtures');
const spawn = require('node:child_process').spawn;
spawn(
process.execPath,
[
'--no-warnings',
'--experimental-test-coverage',
'--test-coverage-exclude=!test/**',
'--test-coverage-lines=99',
'--test-reporter', 'dot',
fixtures.path('test-runner/coverage.js'),
],
{ stdio: 'inherit' },
);
@@ -0,0 +1,18 @@
invalid tap output
.
ℹ Error: 78.35% line coverage does not meet threshold of 99%.
ℹ start of coverage report
ℹ --------------------------------------------------------------------------------------------
ℹ file | line % | branch % | funcs % | uncovered lines
ℹ --------------------------------------------------------------------------------------------
ℹ test | | | |
ℹ fixtures | | | |
ℹ test-runner | | | |
ℹ coverage.js | 78.65 | 38.46 | 60.00 | 12-13 16-22 27 39 43-44 61-62 66-67 71-72
ℹ invalid-tap.js | 100.00 | 100.00 | 100.00 |
ℹ v8-coverage | | | |
ℹ throw.js | 71.43 | 50.00 | 100.00 | 5-6
ℹ --------------------------------------------------------------------------------------------
ℹ all files | 78.35 | 43.75 | 60.00 |
ℹ --------------------------------------------------------------------------------------------
ℹ end of coverage report
@@ -170,4 +170,25 @@ for (const coverage of coverages) {
assert.strictEqual(result.status, 1);
assert(!findCoverageFileForPid(result.pid));
});
test(`test failing ${coverage.flag} with dot reporter`, () => {
const result = spawnSync(process.execPath, [
'--test',
'--experimental-test-coverage',
'--test-coverage-exclude=!test/**',
`${coverage.flag}=99`,
'--test-reporter', 'dot',
fixture,
]);
const stdout = result.stdout.toString();
assert.match(
stdout,
RegExp(`Error: ${coverage.actual.toFixed(2)}% ${coverage.name} coverage does not meet threshold of 99%`)
);
assert.match(stdout, /start of coverage report/);
assert.match(stdout, /end of coverage report/);
assert.strictEqual(result.status, 1);
assert(!findCoverageFileForPid(result.pid));
});
}
@@ -0,0 +1,15 @@
// Test that the output of test-runner/output/dot_reporter_coverage_threshold.js matches
// test-runner/output/dot_reporter_coverage_threshold.snapshot
import * as common from '../common/index.mjs';
import * as fixtures from '../common/fixtures.mjs';
import { spawnAndAssert, specTransform, ensureCwdIsProjectRoot } from '../common/assertSnapshot.js';
if (!process.features.inspector) {
common.skip('inspector support required');
}
ensureCwdIsProjectRoot();
await spawnAndAssert(
fixtures.path('test-runner/output/dot_reporter_coverage_threshold.js'),
specTransform,
);