From 9e21914f5fbfa3651b1bbafa9d80cff3c7c31fb1 Mon Sep 17 00:00:00 2001 From: Pietro Marchini Date: Tue, 4 Feb 2025 13:50:52 +0100 Subject: [PATCH 1/2] test_runner: print formatted errors on summary --- lib/internal/test_runner/reporter/spec.js | 51 ++++++++++++------- .../output/test-runner-watch-spec.mjs | 46 +++++++++++++++++ .../output/test-runner-watch-spec.snapshot | 30 +++++++++++ test/parallel/test-runner-output.mjs | 4 ++ 4 files changed, 112 insertions(+), 19 deletions(-) create mode 100644 test/fixtures/test-runner/output/test-runner-watch-spec.mjs create mode 100644 test/fixtures/test-runner/output/test-runner-watch-spec.snapshot diff --git a/lib/internal/test_runner/reporter/spec.js b/lib/internal/test_runner/reporter/spec.js index caee92a7ba13e1..7c4452d53d139c 100644 --- a/lib/internal/test_runner/reporter/spec.js +++ b/lib/internal/test_runner/reporter/spec.js @@ -30,6 +30,32 @@ class SpecReporter extends Transform { colors.refresh(); } + #formatFailedTestResults() { + if (this.#failedTests.length === 0) { + return ''; + } + + const results = [ + `\n${reporterColorMap['test:fail']}${reporterUnicodeSymbolMap['test:fail']}failing tests:${colors.white}\n`, + ]; + + for (let i = 0; i < this.#failedTests.length; i++) { + const test = this.#failedTests[i]; + const formattedErr = formatTestReport('test:fail', test); + + if (test.file) { + const relPath = relative(this.#cwd, test.file); + const location = `test at ${relPath}:${test.line}:${test.column}`; + ArrayPrototypePush(results, location); + } + + ArrayPrototypePush(results, formattedErr); + } + + const output = ArrayPrototypeJoin(results, '\n'); + this.#failedTests = []; // Clean up the failed tests + return output; + } #handleTestReportEvent(type, data) { const subtest = ArrayPrototypeShift(this.#stack); // This is the matching `test:start` event if (subtest) { @@ -74,31 +100,18 @@ class SpecReporter extends Transform { case 'test:coverage': return getCoverageReport(indent(data.nesting), data.summary, reporterUnicodeSymbolMap['test:coverage'], colors.blue, true); + case 'test:summary': + // We report only the root test summary + if (data.file === undefined) { + return this.#formatFailedTestResults(); + } } } _transform({ type, data }, encoding, callback) { callback(null, this.#handleEvent({ __proto__: null, type, data })); } _flush(callback) { - if (this.#failedTests.length === 0) { - callback(null, ''); - return; - } - const results = [`\n${reporterColorMap['test:fail']}${reporterUnicodeSymbolMap['test:fail']}failing tests:${colors.white}\n`]; - for (let i = 0; i < this.#failedTests.length; i++) { - const test = this.#failedTests[i]; - const formattedErr = formatTestReport('test:fail', test); - - if (test.file) { - const relPath = relative(this.#cwd, test.file); - const location = `test at ${relPath}:${test.line}:${test.column}`; - - ArrayPrototypePush(results, location); - } - - ArrayPrototypePush(results, formattedErr); - } - callback(null, ArrayPrototypeJoin(results, '\n')); + callback(null, this.#formatFailedTestResults()); } } diff --git a/test/fixtures/test-runner/output/test-runner-watch-spec.mjs b/test/fixtures/test-runner/output/test-runner-watch-spec.mjs new file mode 100644 index 00000000000000..6c9b575a164dc7 --- /dev/null +++ b/test/fixtures/test-runner/output/test-runner-watch-spec.mjs @@ -0,0 +1,46 @@ +import { run } from 'node:test'; +import { spec } from 'node:test/reporters'; +import tmpdir from '../../../common/tmpdir.js'; +import { writeFileSync } from 'node:fs'; + + +const fixtureContent = { + 'dependency.js': 'module.exports = {};', + 'dependency.mjs': 'export const a = 1;', + 'test.js': ` + const test = require('node:test'); + require('./dependency.js'); + import('./dependency.mjs'); + import('data:text/javascript,'); + test('test has ran');`, + 'failing-test.js': ` + const test = require('node:test'); + test('failing test', () => { + throw new Error('failed'); + });`, +}; + +tmpdir.refresh(); + +const fixturePaths = Object.keys(fixtureContent) + .reduce((acc, file) => ({ ...acc, [file]: tmpdir.resolve(file) }), {}); +Object.entries(fixtureContent) + .forEach(([file, content]) => writeFileSync(fixturePaths[file], content)); + +const controller = new AbortController(); +const { signal } = controller; + +const stream = run({ + watch: true, + cwd: tmpdir.path, + signal, +}); + + +stream.compose(spec).pipe(process.stdout); + +for await (const event of stream) { + if (event.type === 'test:watch:drained') { + controller.abort(); + } +} diff --git a/test/fixtures/test-runner/output/test-runner-watch-spec.snapshot b/test/fixtures/test-runner/output/test-runner-watch-spec.snapshot new file mode 100644 index 00000000000000..c0af6b179c20b7 --- /dev/null +++ b/test/fixtures/test-runner/output/test-runner-watch-spec.snapshot @@ -0,0 +1,30 @@ +✖ failing test (*ms) +✔ test has ran (*ms) +ℹ tests 2 +ℹ suites 0 +ℹ pass 1 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms * + +✖ failing tests: + +* +✖ failing test (*ms) + Error: failed + * + * + * + * + * + * +ℹ tests 0 +ℹ suites 0 +ℹ pass 0 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms * diff --git a/test/parallel/test-runner-output.mjs b/test/parallel/test-runner-output.mjs index 767c08334843c3..df45456a7eb428 100644 --- a/test/parallel/test-runner-output.mjs +++ b/test/parallel/test-runner-output.mjs @@ -235,6 +235,10 @@ const tests = [ name: 'test-runner/output/test-runner-plan.js', flags: ['--test-reporter=tap'], }, + { + name: 'test-runner/output/test-runner-watch-spec.mjs', + transform: specTransform, + }, process.features.inspector ? { name: 'test-runner/output/coverage_failure.js', flags: ['--test-reporter=tap', '--test-coverage-exclude=!test/**'], From 666cb91c69649cdfb59583f2af92954f90015faf Mon Sep 17 00:00:00 2001 From: Pietro Marchini Date: Tue, 4 Feb 2025 21:51:50 +0100 Subject: [PATCH 2/2] test_runner: avoid unnecessary variable declaration --- lib/internal/test_runner/reporter/spec.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/internal/test_runner/reporter/spec.js b/lib/internal/test_runner/reporter/spec.js index 7c4452d53d139c..e03c8df9e82489 100644 --- a/lib/internal/test_runner/reporter/spec.js +++ b/lib/internal/test_runner/reporter/spec.js @@ -52,9 +52,8 @@ class SpecReporter extends Transform { ArrayPrototypePush(results, formattedErr); } - const output = ArrayPrototypeJoin(results, '\n'); this.#failedTests = []; // Clean up the failed tests - return output; + return ArrayPrototypeJoin(results, '\n'); ; } #handleTestReportEvent(type, data) { const subtest = ArrayPrototypeShift(this.#stack); // This is the matching `test:start` event