From 9d6261f999407d10ef7b0144c08e006e0812b6e7 Mon Sep 17 00:00:00 2001 From: yangzhice Date: Thu, 23 Jul 2026 18:06:49 +0800 Subject: [PATCH 1/2] test_runner: display coverage errors in dot reporter --- lib/internal/test_runner/reporter/dot.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/internal/test_runner/reporter/dot.js b/lib/internal/test_runner/reporter/dot.js index 45ff047bc4e5a0..5eb40880a6f451 100644 --- a/lib/internal/test_runner/reporter/dot.js +++ b/lib/internal/test_runner/reporter/dot.js @@ -10,6 +10,7 @@ module.exports = async function* dot(source) { let count = 0; let columns = getLineLength(); const failedTests = []; + const diagnosticErrors = []; for await (const { type, data } of source) { if (type === 'test:pass') { yield `${colors.green}.${colors.reset}`; @@ -18,6 +19,9 @@ module.exports = async function* dot(source) { yield `${colors.red}X${colors.reset}`; ArrayPrototypePush(failedTests, data); } + if (type === 'test:diagnostic' && data.level === 'error') { + ArrayPrototypePush(diagnosticErrors, data.message); + } if ((type === 'test:fail' || type === 'test:pass') && ++count === columns) { yield '\n'; @@ -33,6 +37,12 @@ module.exports = async function* dot(source) { yield formatTestReport('test:fail', test); } } + if (diagnosticErrors.length > 0) { + yield `\n${colors.red}Diagnostic errors:${colors.white}\n\n`; + for (const msg of diagnosticErrors) { + yield `${msg}\n`; + } + } }; function getLineLength() { From 837df80b86681f6a2e1a22d0b1d99d8c4879b7cb Mon Sep 17 00:00:00 2001 From: yangzhice Date: Fri, 24 Jul 2026 14:23:44 +0800 Subject: [PATCH 2/2] test_runner: add coverage output test for dot reporter --- .../output/dot_reporter_coverage.js | 18 ++ .../output/dot_reporter_coverage.snapshot | 168 ++++++++++++++++++ .../test-output-dot-reporter-coverage.mjs | 10 ++ 3 files changed, 196 insertions(+) create mode 100644 test/fixtures/test-runner/output/dot_reporter_coverage.js create mode 100644 test/fixtures/test-runner/output/dot_reporter_coverage.snapshot create mode 100644 test/test-runner/test-output-dot-reporter-coverage.mjs diff --git a/test/fixtures/test-runner/output/dot_reporter_coverage.js b/test/fixtures/test-runner/output/dot_reporter_coverage.js new file mode 100644 index 00000000000000..607098385eee5c --- /dev/null +++ b/test/fixtures/test-runner/output/dot_reporter_coverage.js @@ -0,0 +1,18 @@ +'use strict'; +require('../../../common'); +const fixtures = require('../../../common/fixtures'); +const spawn = require('node:child_process').spawn; + +spawn( + process.execPath, + [ + '--no-warnings', + '--test-reporter', 'dot', + '--experimental-test-coverage', + '--test-coverage-lines=100', + '--test-coverage-branches=100', + '--test-coverage-functions=100', + fixtures.path('test-runner/output/output.js'), + ], + { stdio: 'inherit' }, +); diff --git a/test/fixtures/test-runner/output/dot_reporter_coverage.snapshot b/test/fixtures/test-runner/output/dot_reporter_coverage.snapshot new file mode 100644 index 00000000000000..2c9aefc2dcd36e --- /dev/null +++ b/test/fixtures/test-runner/output/dot_reporter_coverage.snapshot @@ -0,0 +1,168 @@ +........XX...X..XXX. +X.....XXX........... +.X.........X...XXX.X +X.....XXXXXXX...XXXX +X + +Failed tests: + +⚠ sync fail todo (*ms) # TODO + Error: thrown from sync fail todo + at TestContext. (/test/fixtures/test-runner/output/output.js:42:9) + at +⚠ sync fail todo with message (*ms) # this is a failing todo + Error: thrown from sync fail todo with message + at TestContext. (/test/fixtures/test-runner/output/output.js:47:9) + at +✖ sync throw fail (*ms) + Error: thrown from sync throw fail + at TestContext. (/test/fixtures/test-runner/output/output.js:63:9) + at +✖ async throw fail (*ms) + Error: thrown from async throw fail + at TestContext. (/test/fixtures/test-runner/output/output.js:75:9) + at +﹣ async skip fail (*ms) # SKIP + Error: thrown from async throw fail + at TestContext. (/test/fixtures/test-runner/output/output.js:80:9) + at +✖ async assertion fail (*ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + true !== false + + at TestContext. (/test/fixtures/test-runner/output/output.js:85:10) + at + at { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: true, + expected: false, + operator: 'strictEqual', + diff: 'simple' + } +✖ reject fail (*ms) + Error: rejected from reject fail + at TestContext. (/test/fixtures/test-runner/output/output.js:93:25) + at +✖ +sync throw fail (*ms) + Error: thrown from subtest sync throw fail + at TestContext. (/test/fixtures/test-runner/output/output.js:127:11) + at + at TestContext. (/test/fixtures/test-runner/output/output.js:125:11) + at +✖ subtest sync throw fail (*ms) + '1 subtest failed' +✖ sync throw non-error fail (*ms) + Symbol(thrown symbol from sync throw non-error fail) +✖ sync skip option is false fail (*ms) + Error: this should be executed + at TestContext. (/test/fixtures/test-runner/output/output.js:212:9) + at +✖ callback fail (*ms) + Error: callback failure + at Immediate. (/test/fixtures/test-runner/output/output.js:245:10) + at +✖ callback also returns a Promise (*ms) + 'passed a callback but also returned a Promise' +✖ callback throw (*ms) + Error: thrown from callback throw + at TestContext. (/test/fixtures/test-runner/output/output.js:267:9) + at +✖ callback called twice (*ms) + 'callback invoked multiple times' +✖ callback called twice in future tick (*ms) + Error [ERR_TEST_FAILURE]: callback invoked multiple times + at Immediate. (/test/fixtures/test-runner/output/output.js:283:5) { + code: 'ERR_TEST_FAILURE', + failureType: 'multipleCallbackInvocations', + cause: 'callback invoked multiple times' + } +✖ callback async throw (*ms) + Error: thrown from callback async throw + at Immediate. (/test/fixtures/test-runner/output/output.js:289:11) + at +✖ custom inspect symbol fail (*ms) + customized +✖ custom inspect symbol that throws fail (*ms) + { foo: 1, Symbol(nodejs.util.inspect.custom): [Function: [nodejs.util.inspect.custom]] } +✖ sync throw fails at first (*ms) + Error: thrown from subtest sync throw fails at first + at TestContext. (/test/fixtures/test-runner/output/output.js:335:11) + at + at TestContext. (/test/fixtures/test-runner/output/output.js:334:11) + at +✖ sync throw fails at second (*ms) + Error: thrown from subtest sync throw fails at second + at TestContext. (/test/fixtures/test-runner/output/output.js:338:11) + at + at TestContext. (/test/fixtures/test-runner/output/output.js:337:11) + at +✖ subtest sync throw fails (*ms) + '2 subtests failed' +✖ timed out async test (*ms) + 'test timed out after *ms' +✖ timed out callback test (*ms) + 'test timed out after *ms' +✖ rejected thenable (*ms) + 'custom error' +✖ unfinished test with uncaughtException (*ms) + Error: foo + at Timeout._onTimeout (/test/fixtures/test-runner/output/output.js:393:30) + at +✖ unfinished test with unhandledRejection (*ms) + Error: bar + at Timeout._onTimeout (/test/fixtures/test-runner/output/output.js:399:37) + at +✖ assertion errors display actual and expected properly (*ms) + AssertionError [ERR_ASSERTION]: Expected values to be loosely deep-equal: + + { + bar: 1, + baz: { + date: 1970-01-01T00:00:00.000Z, + null: null, + number: 1, + string: 'Hello', + undefined: undefined + }, + boo: [ + 1 + ], + foo: 1 + } + + should loosely deep-equal + + { + baz: { + date: 1970-01-01T00:00:00.000Z, + null: null, + number: 1, + string: 'Hello', + undefined: undefined + }, + boo: [ + 1 + ], + circular: { + bar: 2, + c: [Circular *1] + } + } + at TestContext. (/test/fixtures/test-runner/output/output.js:425:12) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: [Object], + expected: [Object], + operator: 'deepEqual', + diff: 'simple' + } +✖ invalid subtest fail (*ms) + 'test could not be created because its parent finished' + +Diagnostic errors: + +Error: *% line coverage does not meet threshold of 100.00%. +Error: *% branch coverage does not meet threshold of 100.00%. +Error: *% function coverage does not meet threshold of 100.00%. diff --git a/test/test-runner/test-output-dot-reporter-coverage.mjs b/test/test-runner/test-output-dot-reporter-coverage.mjs new file mode 100644 index 00000000000000..fb45b5a8fc3b9b --- /dev/null +++ b/test/test-runner/test-output-dot-reporter-coverage.mjs @@ -0,0 +1,10 @@ +// Test that dot reporter output with coverage includes diagnostic errors +import '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import { spawnAndAssert, specTransform, ensureCwdIsProjectRoot } from '../common/assertSnapshot.js'; + +ensureCwdIsProjectRoot(); +await spawnAndAssert( + fixtures.path('test-runner/output/dot_reporter_coverage.js'), + specTransform, +);