Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9ec0a4e
test_runner: avoid swallowing of asynchronously thrown errors
fossamagna Nov 7, 2022
7201845
test_runner: add reporters
MoLow Dec 19, 2022
a34809a
module: move test reporter loading
GeoffreyBooth Dec 22, 2022
b628161
test_runner: report `file` in test runner events
MoLow Jan 2, 2023
6d9ec6c
test_runner: make built in reporters internal
cjihrig Jan 6, 2023
6cb8f02
test_runner: add initial code coverage support
cjihrig Dec 21, 2022
8ad7668
doc,lib,src,test: rename --test-coverage
cjihrig Jan 8, 2023
95250e1
test: fix tap escaping with and without --test
pulkit-30 Jan 28, 2023
e1f5a3a
test_runner: top-level diagnostics not ommited when running with --test
pulkit-30 Feb 2, 2023
f4264f0
test_runner: fix missing test diagnostics
MoLow Feb 2, 2023
9c49554
test: fix tap parser fails if a test logs a number
pulkit-30 Feb 6, 2023
1502aca
test_runner: allow nesting test within describe
MoLow Feb 17, 2023
f7d8bed
test_runner: flatten TAP output when running using `--test`
MoLow Feb 18, 2023
730f11f
test_runner: parse non-ascii character correctly
mertcanaltin Feb 18, 2023
4a63d24
test_runner: display skipped tests in spec reporter output
richiemccoll Feb 18, 2023
32a0802
test_runner: centralize CLI option handling
cjihrig Feb 20, 2023
b50cfb3
test_runner: emit test-only diagnostic warning
richiemccoll Feb 21, 2023
69100c9
test_runner: bootstrap reporters before running tests
MoLow Feb 19, 2023
6ef4886
test_runner: add `describe.only` and `it.only` shorthands
richiemccoll Feb 21, 2023
b7aefcb
test_runner: better handle async bootstrap errors
cjihrig Feb 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
test_runner: centralize CLI option handling
The test runner relies on a few CLI options. That code was spread
across a few locations. This commit centralizes that logic.

PR-URL: #46707
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
cjihrig authored and MoLow committed Feb 25, 2023
commit 32a080270327feaef500dcfb7636071d97c21c2c
22 changes: 14 additions & 8 deletions lib/internal/test_runner/harness.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ const {
},
} = require('internal/errors');
const { kEmptyObject } = require('internal/util');
const { getOptionValue } = require('internal/options');
const { kCancelledByParent, Test, ItTest, Suite } = require('internal/test_runner/test');
const { setupTestReporters } = require('internal/test_runner/utils');
const {
parseCommandLine,
setupTestReporters,
} = require('internal/test_runner/utils');
const { bigint: hrtime } = process.hrtime;

const isTestRunnerCli = getOptionValue('--test');
const testResources = new SafeMap();
const wasRootSetup = new SafeWeakSet();

Expand Down Expand Up @@ -54,8 +55,8 @@ function createProcessEventHandler(eventName, rootTest) {
};
}

function configureCoverage(rootTest) {
if (!getOptionValue('--experimental-test-coverage')) {
function configureCoverage(rootTest, globalOptions) {
if (!globalOptions.coverage) {
return null;
}

Expand Down Expand Up @@ -96,6 +97,11 @@ function setup(root) {
if (wasRootSetup.has(root)) {
return root;
}

// Parse the command line options before the hook is enabled. We don't want
// global input validation errors to end up in the uncaughtException handler.
const globalOptions = parseCommandLine();

const hook = createHook({
init(asyncId, type, triggerAsyncId, resource) {
if (resource instanceof Test) {
Expand All @@ -120,7 +126,7 @@ function setup(root) {
createProcessEventHandler('uncaughtException', root);
const rejectionHandler =
createProcessEventHandler('unhandledRejection', root);
const coverage = configureCoverage(root);
const coverage = configureCoverage(root, globalOptions);
const exitHandler = () => {
root.coverage = collectCoverage(root, coverage);
root.postRun(new ERR_TEST_FAILURE(
Expand All @@ -140,8 +146,8 @@ function setup(root) {
process.on('uncaughtException', exceptionHandler);
process.on('unhandledRejection', rejectionHandler);
process.on('beforeExit', exitHandler);
// TODO(MoLow): Make it configurable to hook when isTestRunnerCli === false.
if (isTestRunnerCli) {
// TODO(MoLow): Make it configurable to hook when isTestRunner === false.
if (globalOptions.isTestRunner) {
process.on('SIGINT', terminationHandler);
process.on('SIGTERM', terminationHandler);
}
Expand Down
15 changes: 2 additions & 13 deletions lib/internal/test_runner/test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict';
const {
ArrayPrototypeMap,
ArrayPrototypePush,
ArrayPrototypeReduce,
ArrayPrototypeShift,
Expand Down Expand Up @@ -31,13 +30,12 @@ const {
},
AbortError,
} = require('internal/errors');
const { getOptionValue } = require('internal/options');
const { MockTracker } = require('internal/test_runner/mock');
const { TestsStream } = require('internal/test_runner/tests_stream');
const {
convertStringToRegExp,
createDeferredCallback,
isTestFailureError,
parseCommandLine,
} = require('internal/test_runner/utils');
const {
createDeferredPromise,
Expand Down Expand Up @@ -65,22 +63,13 @@ const kTestTimeoutFailure = 'testTimeoutFailure';
const kHookFailure = 'hookFailed';
const kDefaultTimeout = null;
const noop = FunctionPrototype;
const isTestRunner = getOptionValue('--test');
const testOnlyFlag = !isTestRunner && getOptionValue('--test-only');
const testNamePatternFlag = isTestRunner ? null :
getOptionValue('--test-name-pattern');
const testNamePatterns = testNamePatternFlag?.length > 0 ?
ArrayPrototypeMap(
testNamePatternFlag,
(re) => convertStringToRegExp(re, '--test-name-pattern')
) : null;
const kShouldAbort = Symbol('kShouldAbort');
const kFilename = process.argv?.[1];
const kHookNames = ObjectSeal(['before', 'after', 'beforeEach', 'afterEach']);
const kUnwrapErrors = new SafeSet()
.add(kTestCodeFailure).add(kHookFailure)
.add('uncaughtException').add('unhandledRejection');

const { testNamePatterns, testOnlyFlag } = parseCommandLine();

function stopTest(timeout, signal) {
if (timeout === kDefaultTimeout) {
Expand Down
55 changes: 49 additions & 6 deletions lib/internal/test_runner/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';
const {
ArrayPrototypeMap,
ArrayPrototypePush,
ObjectCreate,
ObjectGetOwnPropertyDescriptor,
Expand Down Expand Up @@ -149,8 +150,27 @@ async function getReportersMap(reporters, destinations) {


async function setupTestReporters(testsStream) {
const { reporters, destinations } = parseCommandLine();
const reportersMap = await getReportersMap(reporters, destinations);
for (let i = 0; i < reportersMap.length; i++) {
const { reporter, destination } = reportersMap[i];
compose(testsStream, reporter).pipe(destination);
}
}

let globalTestOptions;

function parseCommandLine() {
if (globalTestOptions) {
return globalTestOptions;
}

const isTestRunner = getOptionValue('--test');
const coverage = getOptionValue('--experimental-test-coverage');
const destinations = getOptionValue('--test-reporter-destination');
const reporters = getOptionValue('--test-reporter');
let testNamePatterns;
let testOnlyFlag;

if (reporters.length === 0 && destinations.length === 0) {
ArrayPrototypePush(reporters, kDefaultReporter);
Expand All @@ -161,15 +181,37 @@ async function setupTestReporters(testsStream) {
}

if (destinations.length !== reporters.length) {
throw new ERR_INVALID_ARG_VALUE('--test-reporter', reporters,
'must match the number of specified \'--test-reporter-destination\'');
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);
if (isTestRunner) {
testOnlyFlag = false;
testNamePatterns = null;
} else {
const testNamePatternFlag = getOptionValue('--test-name-pattern');
testOnlyFlag = getOptionValue('--test-only');
testNamePatterns = testNamePatternFlag?.length > 0 ?
ArrayPrototypeMap(
testNamePatternFlag,
(re) => convertStringToRegExp(re, '--test-name-pattern'),
) : null;
}

globalTestOptions = {
__proto__: null,
isTestRunner,
coverage,
testOnlyFlag,
testNamePatterns,
reporters,
destinations,
};

return globalTestOptions;
}

module.exports = {
Expand All @@ -178,5 +220,6 @@ module.exports = {
doesPathMatchFilter,
isSupportedFileType,
isTestFailureError,
parseCommandLine,
setupTestReporters,
};