UNPKG

nstdlib-nightly

Version:

Node.js standard library converted to runtime-agnostic ES modules.

115 lines (106 loc) 3.84 kB
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/test_runner/reporter/spec.js import * as assert from "nstdlib/lib/assert"; import Transform from "nstdlib/lib/internal/streams/transform"; import * as colors from "nstdlib/lib/internal/util/colors"; import { kSubtestsFailed } from "nstdlib/lib/internal/test_runner/test"; import { getCoverageReport } from "nstdlib/lib/internal/test_runner/utils"; import { relative } from "nstdlib/lib/path"; import { formatTestReport, indent, reporterColorMap, reporterUnicodeSymbolMap, } from "nstdlib/lib/internal/test_runner/reporter/utils"; class SpecReporter extends Transform { #stack = []; #reported = []; #failedTests = []; #cwd = process.cwd(); constructor() { super({ __proto__: null, writableObjectMode: true }); colors.refresh(); } #handleTestReportEvent(type, data) { const subtest = Array.prototype.shift.call(this.#stack); // This is the matching `test:start` event if (subtest) { assert(subtest.type === "test:start"); assert(subtest.data.nesting === data.nesting); assert(subtest.data.name === data.name); } let prefix = ""; while (this.#stack.length) { // Report all the parent `test:start` events const parent = Array.prototype.pop.call(this.#stack); assert(parent.type === "test:start"); const msg = parent.data; Array.prototype.unshift.call(this.#reported, msg); prefix += `${indent(msg.nesting)}${reporterUnicodeSymbolMap["arrow:right"]}${msg.name}\n`; } let hasChildren = false; if ( this.#reported[0] && this.#reported[0].nesting === data.nesting && this.#reported[0].name === data.name ) { Array.prototype.shift.call(this.#reported); hasChildren = true; } const indentation = indent(data.nesting); return `${formatTestReport(type, data, prefix, indentation, hasChildren)}\n`; } #handleEvent({ type, data }) { switch (type) { case "test:fail": if (data.details?.error?.failureType !== kSubtestsFailed) { Array.prototype.push.call(this.#failedTests, data); } return this.#handleTestReportEvent(type, data); case "test:pass": return this.#handleTestReportEvent(type, data); case "test:start": Array.prototype.unshift.call(this.#stack, { __proto__: null, data, type, }); break; case "test:stderr": case "test:stdout": return data.message; case "test:diagnostic": return `${reporterColorMap[type]}${indent(data.nesting)}${reporterUnicodeSymbolMap[type]}${data.message}${colors.white}\n`; case "test:coverage": return getCoverageReport( indent(data.nesting), data.summary, reporterUnicodeSymbolMap["test:coverage"], colors.blue, true, ); } } _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}`; Array.prototype.push.call(results, location); } Array.prototype.push.call(results, formattedErr); } callback(null, Array.prototype.join.call(results, "\n")); } } export default SpecReporter;