diff options
author | Moshe Atlow <moshe@atlow.co.il> | 2023-02-19 21:15:03 +0200 |
---|---|---|
committer | Michaƫl Zasso <targos@protonmail.com> | 2023-03-14 07:54:15 +0100 |
commit | 6d32a16319f4b6628b66146517c49931065af11a (patch) | |
tree | 7f8e2d0f7cde8befd9ade7b21140620bc4f07e21 | |
parent | ffa86f7fa92d7156fe2a9586cef86d0207971c8b (diff) | |
download | node-new-6d32a16319f4b6628b66146517c49931065af11a.tar.gz |
test_runner: bootstrap reporters before running tests
PR-URL: https://github.com/nodejs/node/pull/46737
Fixes: https://github.com/nodejs/node/issues/46747
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
-rw-r--r-- | doc/api/test.md | 3 | ||||
-rw-r--r-- | lib/internal/main/test_runner.js | 5 | ||||
-rw-r--r-- | lib/internal/test_runner/harness.js | 12 | ||||
-rw-r--r-- | lib/internal/test_runner/runner.js | 21 |
4 files changed, 29 insertions, 12 deletions
diff --git a/doc/api/test.md b/doc/api/test.md index 57753556a0..da6ba355fe 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -705,6 +705,9 @@ added: v18.9.0 **Default:** `false`. * `files`: {Array} An array containing the list of files to run. **Default** matching files from [test runner execution model][]. + * `setup` {Function} A function that accepts the `TestsStream` instance + and can be used to setup listeners before any tests are run. + **Default:** `undefined`. * `signal` {AbortSignal} Allows aborting an in-progress test execution. * `timeout` {number} A number of milliseconds the test execution will fail after. diff --git a/lib/internal/main/test_runner.js b/lib/internal/main/test_runner.js index 658aab0332..9a209eb189 100644 --- a/lib/internal/main/test_runner.js +++ b/lib/internal/main/test_runner.js @@ -22,8 +22,7 @@ if (isUsingInspector()) { inspectPort = process.debugPort; } -const testsStream = run({ concurrency, inspectPort, watch: getOptionValue('--watch') }); -testsStream.once('test:fail', () => { +run({ concurrency, inspectPort, watch: getOptionValue('--watch'), setup: setupTestReporters }) +.once('test:fail', () => { process.exitCode = kGenericUserError; }); -setupTestReporters(testsStream); diff --git a/lib/internal/test_runner/harness.js b/lib/internal/test_runner/harness.js index 17b1e586ba..84660b541c 100644 --- a/lib/internal/test_runner/harness.js +++ b/lib/internal/test_runner/harness.js @@ -170,21 +170,27 @@ function setup(root) { } let globalRoot; +let reportersSetup; function getGlobalRoot() { if (!globalRoot) { globalRoot = createTestTree(); globalRoot.reporter.once('test:fail', () => { process.exitCode = kGenericUserError; }); - setupTestReporters(globalRoot.reporter); + reportersSetup = setupTestReporters(globalRoot.reporter); } return globalRoot; } +async function startSubtest(subtest) { + await reportersSetup; + await subtest.start(); +} + function test(name, options, fn) { const parent = testResources.get(executionAsyncId()) || getGlobalRoot(); const subtest = parent.createSubtest(Test, name, options, fn); - return subtest.start(); + return startSubtest(subtest); } function runInParentContext(Factory) { @@ -192,7 +198,7 @@ function runInParentContext(Factory) { const parent = testResources.get(executionAsyncId()) || getGlobalRoot(); const subtest = parent.createSubtest(Factory, name, options, fn, overrides); if (parent === getGlobalRoot()) { - subtest.start(); + startSubtest(subtest); } } diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index d73b14868b..2e0c62505f 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -13,8 +13,10 @@ const { ObjectAssign, ObjectKeys, PromisePrototypeThen, + SafePromiseAll, SafePromiseAllReturnVoid, SafePromiseAllSettledReturnVoid, + PromiseResolve, SafeMap, SafeSet, StringPrototypeIndexOf, @@ -24,6 +26,7 @@ const { const { spawn } = require('child_process'); const { readdirSync, statSync } = require('fs'); +const { finished } = require('internal/streams/end-of-stream'); // TODO(aduh95): switch to internal/readline/interface when backporting to Node.js 16.x is no longer a concern. const { createInterface } = require('readline'); const { FilesWatcher } = require('internal/watch_mode/files_watcher'); @@ -33,7 +36,7 @@ const { ERR_TEST_FAILURE, }, } = require('internal/errors'); -const { validateArray, validateBoolean } = require('internal/validators'); +const { validateArray, validateBoolean, validateFunction } = require('internal/validators'); const { getInspectPort, isUsingInspector, isInspectorMessage } = require('internal/util/inspector'); const { kEmptyObject } = require('internal/util'); const { createTestTree } = require('internal/test_runner/harness'); @@ -299,7 +302,10 @@ function runTestFile(path, root, inspectPort, filesWatcher) { subtest.addToReport(ast); }); - const { 0: code, 1: signal } = await once(child, 'exit', { signal: t.signal }); + const { 0: { 0: code, 1: signal } } = await SafePromiseAll([ + once(child, 'exit', { signal: t.signal }), + finished(parser, { signal: t.signal }), + ]); runningProcesses.delete(path); runningSubtests.delete(path); @@ -348,7 +354,7 @@ function run(options) { if (options === null || typeof options !== 'object') { options = kEmptyObject; } - const { concurrency, timeout, signal, files, inspectPort, watch } = options; + const { concurrency, timeout, signal, files, inspectPort, watch, setup } = options; if (files != null) { validateArray(files, 'options.files'); @@ -356,6 +362,9 @@ function run(options) { if (watch != null) { validateBoolean(watch, 'options.watch'); } + if (setup != null) { + validateFunction(setup, 'options.setup'); + } const root = createTestTree({ concurrency, timeout, signal }); const testFiles = files ?? createTestFileList(); @@ -366,13 +375,13 @@ function run(options) { filesWatcher = watchFiles(testFiles, root, inspectPort); postRun = undefined; } - - PromisePrototypeThen(SafePromiseAllSettledReturnVoid(testFiles, (path) => { + const runFiles = () => SafePromiseAllSettledReturnVoid(testFiles, (path) => { const subtest = runTestFile(path, root, inspectPort, filesWatcher); runningSubtests.set(path, subtest); return subtest; - }), postRun); + }); + PromisePrototypeThen(PromisePrototypeThen(PromiseResolve(setup?.(root.reporter)), runFiles), postRun); return root.reporter; } |