11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci ArrayPrototypeJoin, 51cb0ef41Sopenharmony_ci ArrayPrototypePop, 61cb0ef41Sopenharmony_ci ArrayPrototypePush, 71cb0ef41Sopenharmony_ci ArrayPrototypeShift, 81cb0ef41Sopenharmony_ci ArrayPrototypeUnshift, 91cb0ef41Sopenharmony_ci hardenRegExp, 101cb0ef41Sopenharmony_ci RegExpPrototypeSymbolSplit, 111cb0ef41Sopenharmony_ci SafeMap, 121cb0ef41Sopenharmony_ci StringPrototypeRepeat, 131cb0ef41Sopenharmony_ci} = primordials; 141cb0ef41Sopenharmony_ciconst assert = require('assert'); 151cb0ef41Sopenharmony_ciconst Transform = require('internal/streams/transform'); 161cb0ef41Sopenharmony_ciconst { inspectWithNoCustomRetry } = require('internal/errors'); 171cb0ef41Sopenharmony_ciconst { green, blue, red, white, gray, shouldColorize } = require('internal/util/colors'); 181cb0ef41Sopenharmony_ciconst { kSubtestsFailed } = require('internal/test_runner/test'); 191cb0ef41Sopenharmony_ciconst { getCoverageReport } = require('internal/test_runner/utils'); 201cb0ef41Sopenharmony_ciconst { relative } = require('path'); 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ciconst inspectOptions = { __proto__: null, colors: shouldColorize(process.stdout), breakLength: Infinity }; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ciconst colors = { 251cb0ef41Sopenharmony_ci '__proto__': null, 261cb0ef41Sopenharmony_ci 'test:fail': red, 271cb0ef41Sopenharmony_ci 'test:pass': green, 281cb0ef41Sopenharmony_ci 'test:diagnostic': blue, 291cb0ef41Sopenharmony_ci}; 301cb0ef41Sopenharmony_ciconst symbols = { 311cb0ef41Sopenharmony_ci '__proto__': null, 321cb0ef41Sopenharmony_ci 'test:fail': '\u2716 ', 331cb0ef41Sopenharmony_ci 'test:pass': '\u2714 ', 341cb0ef41Sopenharmony_ci 'test:diagnostic': '\u2139 ', 351cb0ef41Sopenharmony_ci 'test:coverage': '\u2139 ', 361cb0ef41Sopenharmony_ci 'arrow:right': '\u25B6 ', 371cb0ef41Sopenharmony_ci 'hyphen:minus': '\uFE63 ', 381cb0ef41Sopenharmony_ci}; 391cb0ef41Sopenharmony_ciclass SpecReporter extends Transform { 401cb0ef41Sopenharmony_ci #stack = []; 411cb0ef41Sopenharmony_ci #reported = []; 421cb0ef41Sopenharmony_ci #indentMemo = new SafeMap(); 431cb0ef41Sopenharmony_ci #failedTests = []; 441cb0ef41Sopenharmony_ci #cwd = process.cwd(); 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci constructor() { 471cb0ef41Sopenharmony_ci super({ __proto__: null, writableObjectMode: true }); 481cb0ef41Sopenharmony_ci } 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci #indent(nesting) { 511cb0ef41Sopenharmony_ci let value = this.#indentMemo.get(nesting); 521cb0ef41Sopenharmony_ci if (value === undefined) { 531cb0ef41Sopenharmony_ci value = StringPrototypeRepeat(' ', nesting); 541cb0ef41Sopenharmony_ci this.#indentMemo.set(nesting, value); 551cb0ef41Sopenharmony_ci } 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci return value; 581cb0ef41Sopenharmony_ci } 591cb0ef41Sopenharmony_ci #formatError(error, indent) { 601cb0ef41Sopenharmony_ci if (!error) return ''; 611cb0ef41Sopenharmony_ci const err = error.code === 'ERR_TEST_FAILURE' ? error.cause : error; 621cb0ef41Sopenharmony_ci const message = ArrayPrototypeJoin( 631cb0ef41Sopenharmony_ci RegExpPrototypeSymbolSplit( 641cb0ef41Sopenharmony_ci hardenRegExp(/\r?\n/), 651cb0ef41Sopenharmony_ci inspectWithNoCustomRetry(err, inspectOptions), 661cb0ef41Sopenharmony_ci ), `\n${indent} `); 671cb0ef41Sopenharmony_ci return `\n${indent} ${message}\n`; 681cb0ef41Sopenharmony_ci } 691cb0ef41Sopenharmony_ci #formatTestReport(type, data, prefix = '', indent = '', hasChildren = false) { 701cb0ef41Sopenharmony_ci let color = colors[type] ?? white; 711cb0ef41Sopenharmony_ci let symbol = symbols[type] ?? ' '; 721cb0ef41Sopenharmony_ci const { skip, todo } = data; 731cb0ef41Sopenharmony_ci const duration_ms = data.details?.duration_ms ? ` ${gray}(${data.details.duration_ms}ms)${white}` : ''; 741cb0ef41Sopenharmony_ci let title = `${data.name}${duration_ms}`; 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci if (skip !== undefined) { 771cb0ef41Sopenharmony_ci title += ` # ${typeof skip === 'string' && skip.length ? skip : 'SKIP'}`; 781cb0ef41Sopenharmony_ci } else if (todo !== undefined) { 791cb0ef41Sopenharmony_ci title += ` # ${typeof todo === 'string' && todo.length ? todo : 'TODO'}`; 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci if (hasChildren) { 821cb0ef41Sopenharmony_ci // If this test has had children - it was already reported, so slightly modify the output 831cb0ef41Sopenharmony_ci return `${prefix}${indent}${color}${symbols['arrow:right']}${white}${title}\n`; 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci const error = this.#formatError(data.details?.error, indent); 861cb0ef41Sopenharmony_ci if (skip !== undefined) { 871cb0ef41Sopenharmony_ci color = gray; 881cb0ef41Sopenharmony_ci symbol = symbols['hyphen:minus']; 891cb0ef41Sopenharmony_ci } 901cb0ef41Sopenharmony_ci return `${prefix}${indent}${color}${symbol}${title}${white}${error}`; 911cb0ef41Sopenharmony_ci } 921cb0ef41Sopenharmony_ci #handleTestReportEvent(type, data) { 931cb0ef41Sopenharmony_ci const subtest = ArrayPrototypeShift(this.#stack); // This is the matching `test:start` event 941cb0ef41Sopenharmony_ci if (subtest) { 951cb0ef41Sopenharmony_ci assert(subtest.type === 'test:start'); 961cb0ef41Sopenharmony_ci assert(subtest.data.nesting === data.nesting); 971cb0ef41Sopenharmony_ci assert(subtest.data.name === data.name); 981cb0ef41Sopenharmony_ci } 991cb0ef41Sopenharmony_ci let prefix = ''; 1001cb0ef41Sopenharmony_ci while (this.#stack.length) { 1011cb0ef41Sopenharmony_ci // Report all the parent `test:start` events 1021cb0ef41Sopenharmony_ci const parent = ArrayPrototypePop(this.#stack); 1031cb0ef41Sopenharmony_ci assert(parent.type === 'test:start'); 1041cb0ef41Sopenharmony_ci const msg = parent.data; 1051cb0ef41Sopenharmony_ci ArrayPrototypeUnshift(this.#reported, msg); 1061cb0ef41Sopenharmony_ci prefix += `${this.#indent(msg.nesting)}${symbols['arrow:right']}${msg.name}\n`; 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci let hasChildren = false; 1091cb0ef41Sopenharmony_ci if (this.#reported[0] && this.#reported[0].nesting === data.nesting && this.#reported[0].name === data.name) { 1101cb0ef41Sopenharmony_ci ArrayPrototypeShift(this.#reported); 1111cb0ef41Sopenharmony_ci hasChildren = true; 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci const indent = this.#indent(data.nesting); 1141cb0ef41Sopenharmony_ci return `${this.#formatTestReport(type, data, prefix, indent, hasChildren)}\n`; 1151cb0ef41Sopenharmony_ci } 1161cb0ef41Sopenharmony_ci #handleEvent({ type, data }) { 1171cb0ef41Sopenharmony_ci switch (type) { 1181cb0ef41Sopenharmony_ci case 'test:fail': 1191cb0ef41Sopenharmony_ci if (data.details?.error?.failureType !== kSubtestsFailed) { 1201cb0ef41Sopenharmony_ci ArrayPrototypePush(this.#failedTests, data); 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci return this.#handleTestReportEvent(type, data); 1231cb0ef41Sopenharmony_ci case 'test:pass': 1241cb0ef41Sopenharmony_ci return this.#handleTestReportEvent(type, data); 1251cb0ef41Sopenharmony_ci case 'test:start': 1261cb0ef41Sopenharmony_ci ArrayPrototypeUnshift(this.#stack, { __proto__: null, data, type }); 1271cb0ef41Sopenharmony_ci break; 1281cb0ef41Sopenharmony_ci case 'test:stderr': 1291cb0ef41Sopenharmony_ci case 'test:stdout': 1301cb0ef41Sopenharmony_ci return data.message; 1311cb0ef41Sopenharmony_ci case 'test:diagnostic': 1321cb0ef41Sopenharmony_ci return `${colors[type]}${this.#indent(data.nesting)}${symbols[type]}${data.message}${white}\n`; 1331cb0ef41Sopenharmony_ci case 'test:coverage': 1341cb0ef41Sopenharmony_ci return getCoverageReport(this.#indent(data.nesting), data.summary, symbols['test:coverage'], blue, true); 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci } 1371cb0ef41Sopenharmony_ci _transform({ type, data }, encoding, callback) { 1381cb0ef41Sopenharmony_ci callback(null, this.#handleEvent({ __proto__: null, type, data })); 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci _flush(callback) { 1411cb0ef41Sopenharmony_ci if (this.#failedTests.length === 0) { 1421cb0ef41Sopenharmony_ci callback(null, ''); 1431cb0ef41Sopenharmony_ci return; 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci const results = [`\n${colors['test:fail']}${symbols['test:fail']}failing tests:${white}\n`]; 1461cb0ef41Sopenharmony_ci for (let i = 0; i < this.#failedTests.length; i++) { 1471cb0ef41Sopenharmony_ci const test = this.#failedTests[i]; 1481cb0ef41Sopenharmony_ci const relPath = relative(this.#cwd, test.file); 1491cb0ef41Sopenharmony_ci const formattedErr = this.#formatTestReport('test:fail', test); 1501cb0ef41Sopenharmony_ci const location = `test at ${relPath}:${test.line}:${test.column}`; 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci ArrayPrototypePush(results, location, formattedErr); 1531cb0ef41Sopenharmony_ci } 1541cb0ef41Sopenharmony_ci callback(null, ArrayPrototypeJoin(results, '\n')); 1551cb0ef41Sopenharmony_ci } 1561cb0ef41Sopenharmony_ci} 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_cimodule.exports = SpecReporter; 159