diff --git a/lib/internal/test_runner/reporter/spec.js b/lib/internal/test_runner/reporter/spec.js index 75b4d9773c4161..b93405872f278c 100644 --- a/lib/internal/test_runner/reporter/spec.js +++ b/lib/internal/test_runner/reporter/spec.js @@ -14,19 +14,11 @@ const { const assert = require('assert'); const Transform = require('internal/streams/transform'); const { inspectWithNoCustomRetry } = require('internal/errors'); -const { green, blue, red, white, gray, shouldColorize } = require('internal/util/colors'); +const colors = require('internal/util/colors'); const { kSubtestsFailed } = require('internal/test_runner/test'); const { getCoverageReport } = require('internal/test_runner/utils'); const { relative } = require('path'); -const inspectOptions = { __proto__: null, colors: shouldColorize(process.stdout), breakLength: Infinity }; - -const colors = { - '__proto__': null, - 'test:fail': red, - 'test:pass': green, - 'test:diagnostic': blue, -}; const symbols = { '__proto__': null, 'test:fail': '\u2716 ', @@ -42,9 +34,19 @@ class SpecReporter extends Transform { #indentMemo = new SafeMap(); #failedTests = []; #cwd = process.cwd(); + #inspectOptions; + #colors; constructor() { super({ __proto__: null, writableObjectMode: true }); + colors.refresh(); + this.#inspectOptions = { __proto__: null, colors: colors.shouldColorize(process.stdout), breakLength: Infinity }; + this.#colors = { + '__proto__': null, + 'test:fail': colors.red, + 'test:pass': colors.green, + 'test:diagnostic': colors.blue, + }; } #indent(nesting) { @@ -62,15 +64,15 @@ class SpecReporter extends Transform { const message = ArrayPrototypeJoin( RegExpPrototypeSymbolSplit( hardenRegExp(/\r?\n/), - inspectWithNoCustomRetry(err, inspectOptions), + inspectWithNoCustomRetry(err, this.#inspectOptions), ), `\n${indent} `); return `\n${indent} ${message}\n`; } #formatTestReport(type, data, prefix = '', indent = '', hasChildren = false) { - let color = colors[type] ?? white; + let color = this.#colors[type] ?? colors.white; let symbol = symbols[type] ?? ' '; const { skip, todo } = data; - const duration_ms = data.details?.duration_ms ? ` ${gray}(${data.details.duration_ms}ms)${white}` : ''; + const duration_ms = data.details?.duration_ms ? ` ${colors.gray}(${data.details.duration_ms}ms)${colors.white}` : ''; let title = `${data.name}${duration_ms}`; if (skip !== undefined) { @@ -82,13 +84,13 @@ class SpecReporter extends Transform { if (hasChildren) { // If this test has had children - it was already reported, so slightly modify the output const err = data.details?.error?.failureType === 'subtestsFailed' ? '' : error; - return `${prefix}${indent}${color}${symbols['arrow:right']}${white}${title}\n${err}`; + return `${prefix}${indent}${color}${symbols['arrow:right']}${colors.white}${title}\n${err}`; } if (skip !== undefined) { - color = gray; + color = colors.gray; symbol = symbols['hyphen:minus']; } - return `${prefix}${indent}${color}${symbol}${title}${white}${error}`; + return `${prefix}${indent}${color}${symbol}${title}${colors.white}${error}`; } #handleTestReportEvent(type, data) { const subtest = ArrayPrototypeShift(this.#stack); // This is the matching `test:start` event @@ -130,9 +132,9 @@ class SpecReporter extends Transform { case 'test:stdout': return data.message; case 'test:diagnostic': - return `${colors[type]}${this.#indent(data.nesting)}${symbols[type]}${data.message}${white}\n`; + return `${this.#colors[type]}${this.#indent(data.nesting)}${symbols[type]}${data.message}${colors.white}\n`; case 'test:coverage': - return getCoverageReport(this.#indent(data.nesting), data.summary, symbols['test:coverage'], blue, true); + return getCoverageReport(this.#indent(data.nesting), data.summary, symbols['test:coverage'], colors.blue, true); } } _transform({ type, data }, encoding, callback) { @@ -143,7 +145,7 @@ class SpecReporter extends Transform { callback(null, ''); return; } - const results = [`\n${colors['test:fail']}${symbols['test:fail']}failing tests:${white}\n`]; + const results = [`\n${this.#colors['test:fail']}${symbols['test:fail']}failing tests:${colors.white}\n`]; for (let i = 0; i < this.#failedTests.length; i++) { const test = this.#failedTests[i]; const relPath = relative(this.#cwd, test.file); diff --git a/test/fixtures/test-runner/output/arbitrary-output-colored.js b/test/fixtures/test-runner/output/arbitrary-output-colored.js index b09eeeb9971cf6..af23e674cb361e 100644 --- a/test/fixtures/test-runner/output/arbitrary-output-colored.js +++ b/test/fixtures/test-runner/output/arbitrary-output-colored.js @@ -6,6 +6,7 @@ const fixtures = require('../../../common/fixtures'); (async function run() { const test = fixtures.path('test-runner/output/arbitrary-output-colored-1.js'); - await once(spawn(process.execPath, ['--test', test], { stdio: 'inherit', env: { FORCE_COLOR: 1 } }), 'exit'); - await once(spawn(process.execPath, ['--test', '--test-reporter', 'tap', test], { stdio: 'inherit', env: { FORCE_COLOR: 1 } }), 'exit'); + const reset = fixtures.path('test-runner/output/reset-color-depth.js'); + await once(spawn(process.execPath, ['-r', reset, '--test', test], { stdio: 'inherit' }), 'exit'); + await once(spawn(process.execPath, ['-r', reset, '--test', '--test-reporter', 'tap', test], { stdio: 'inherit' }), 'exit'); })().then(common.mustCall()); diff --git a/test/fixtures/test-runner/output/reset-color-depth.js b/test/fixtures/test-runner/output/reset-color-depth.js new file mode 100644 index 00000000000000..02c04b247ad4d9 --- /dev/null +++ b/test/fixtures/test-runner/output/reset-color-depth.js @@ -0,0 +1,5 @@ +'use strict'; + +// Make tests OS-independent by overriding stdio getColorDepth(). +process.stdout.getColorDepth = () => 8; +process.stderr.getColorDepth = () => 8;