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