UNPKG

test

Version:

Node.js 18's node:test, as an npm package

172 lines (138 loc) 4.6 kB
// https://github.com/nodejs/node/blob/4788c0d2a02a2e7c7088c6f39d9f13a4209ba863/lib/internal/test_runner/utils.js 'use strict' const { ArrayPrototypePush, ObjectGetOwnPropertyDescriptor, SafePromiseAllReturnArrayLike, RegExp, RegExpPrototypeExec, SafeMap } = require('#internal/per_context/primordials') const { basename } = require('path') const { createWriteStream } = require('fs') const { createDeferredPromise } = require('#internal/util') const { getOptionValue } = require('#internal/options') const { codes: { ERR_INVALID_ARG_VALUE, ERR_TEST_FAILURE }, kIsNodeError } = require('#internal/errors') const { compose } = require('readable-stream') const kMultipleCallbackInvocations = 'multipleCallbackInvocations' const kRegExpPattern = /^\/(.*)\/([a-z]*)$/ const kSupportedFileExtensions = /\.[cm]?js$/ const kTestFilePattern = /((^test(-.+)?)|(.+[.\-_]test))\.[cm]?js$/ function doesPathMatchFilter (p) { return RegExpPrototypeExec(kTestFilePattern, basename(p)) !== null } function isSupportedFileType (p) { return RegExpPrototypeExec(kSupportedFileExtensions, p) !== null } function createDeferredCallback () { let calledCount = 0 const { promise, resolve, reject } = createDeferredPromise() const cb = (err) => { calledCount++ // If the callback is called a second time, let the user know, but // don't let them know more than once. if (calledCount > 1) { if (calledCount === 2) { throw new ERR_TEST_FAILURE( 'callback invoked multiple times', kMultipleCallbackInvocations ) } return } if (err) { return reject(err) } resolve() } return { promise, cb } } function isTestFailureError (err) { return err?.code === 'ERR_TEST_FAILURE' && kIsNodeError in err } function convertStringToRegExp (str, name) { const match = RegExpPrototypeExec(kRegExpPattern, str) const pattern = match?.[1] ?? str const flags = match?.[2] || '' try { return new RegExp(pattern, flags) } catch (err) { const msg = err?.message throw new ERR_INVALID_ARG_VALUE( name, str, `is an invalid regular expression.${msg ? ` ${msg}` : ''}` ) } } const kBuiltinDestinations = new SafeMap([ ['stdout', process.stdout], ['stderr', process.stderr] ]) const kBuiltinReporters = new SafeMap([ ['spec', '#internal/test_runner/reporter/spec'], ['dot', '#internal/test_runner/reporter/dot'], ['tap', '#internal/test_runner/reporter/tap'] ]) const kDefaultReporter = 'tap' const kDefaultDestination = 'stdout' function tryBuiltinReporter (name) { const builtinPath = kBuiltinReporters.get(name) if (builtinPath === undefined) { return } return require(builtinPath) } async function getReportersMap (reporters, destinations) { return SafePromiseAllReturnArrayLike(reporters, async (name, i) => { const destination = kBuiltinDestinations.get(destinations[i]) ?? createWriteStream(destinations[i]) // Load the test reporter passed to --test-reporter let reporter = tryBuiltinReporter(name) if (reporter === undefined) { reporter = await import(name) } if (reporter?.default) { reporter = reporter.default } if (reporter?.prototype && ObjectGetOwnPropertyDescriptor(reporter.prototype, 'constructor')) { reporter = new reporter() // eslint-disable-line new-cap } if (!reporter) { throw new ERR_INVALID_ARG_VALUE('Reporter', name, 'is not a valid reporter') } return { __proto__: null, reporter, destination } }) } async function setupTestReporters (testsStream) { const destinations = getOptionValue('--test-reporter-destination') ?? [] const reporters = getOptionValue('--test-reporter') ?? [] if (reporters.length === 0 && destinations.length === 0) { ArrayPrototypePush(reporters, kDefaultReporter) } if (reporters.length === 1 && destinations.length === 0) { ArrayPrototypePush(destinations, kDefaultDestination) } if (destinations.length !== reporters.length) { throw new ERR_INVALID_ARG_VALUE('--test-reporter', reporters, 'must match the number of specified \'--test-reporter-destination\'') } const reportersMap = await getReportersMap(reporters, destinations) for (let i = 0; i < reportersMap.length; i++) { const { reporter, destination } = reportersMap[i] compose(testsStream, reporter).pipe(destination) } } module.exports = { convertStringToRegExp, createDeferredCallback, doesPathMatchFilter, isSupportedFileType, isTestFailureError, setupTestReporters }