Skip to content

Commit d92b981

Browse files
committed
test_runner: bootstrap reporters before running tests
1 parent 16aacfa commit d92b981

File tree

4 files changed

+29
-12
lines changed

4 files changed

+29
-12
lines changed

doc/api/test.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,9 @@ added:
684684
**Default:** `false`.
685685
* `files`: {Array} An array containing the list of files to run.
686686
**Default** matching files from [test runner execution model][].
687+
* `setup` {Function} A function that accepts the TestsStream instance
688+
and can be used to setup listeners before any tests are run.
689+
**Default:** `undefined`.
687690
* `signal` {AbortSignal} Allows aborting an in-progress test execution.
688691
* `timeout` {number} A number of milliseconds the test execution will
689692
fail after.

lib/internal/main/test_runner.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ if (isUsingInspector()) {
2222
inspectPort = process.debugPort;
2323
}
2424

25-
const testsStream = run({ concurrency, inspectPort, watch: getOptionValue('--watch') });
26-
testsStream.once('test:fail', () => {
25+
run({ concurrency, inspectPort, watch: getOptionValue('--watch'), setup: setupTestReporters })
26+
.once('test:fail', () => {
2727
process.exitCode = kGenericUserError;
2828
});
29-
setupTestReporters(testsStream);

lib/internal/test_runner/harness.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,29 +161,35 @@ function setup(root) {
161161
}
162162

163163
let globalRoot;
164+
let reportersSetup;
164165
function getGlobalRoot() {
165166
if (!globalRoot) {
166167
globalRoot = createTestTree();
167168
globalRoot.reporter.once('test:fail', () => {
168169
process.exitCode = kGenericUserError;
169170
});
170-
setupTestReporters(globalRoot.reporter);
171+
reportersSetup = setupTestReporters(globalRoot.reporter);
171172
}
172173
return globalRoot;
173174
}
174175

176+
async function startSubtest(subtest) {
177+
await reportersSetup;
178+
await subtest.start();
179+
}
180+
175181
function test(name, options, fn) {
176182
const parent = testResources.get(executionAsyncId()) || getGlobalRoot();
177183
const subtest = parent.createSubtest(Test, name, options, fn);
178-
return subtest.start();
184+
return startSubtest(subtest);
179185
}
180186

181187
function runInParentContext(Factory) {
182188
function run(name, options, fn, overrides) {
183189
const parent = testResources.get(executionAsyncId()) || getGlobalRoot();
184190
const subtest = parent.createSubtest(Factory, name, options, fn, overrides);
185191
if (parent === getGlobalRoot()) {
186-
subtest.start();
192+
startSubtest(subtest);
187193
}
188194
}
189195

lib/internal/test_runner/runner.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ const {
1313
ObjectAssign,
1414
ObjectKeys,
1515
PromisePrototypeThen,
16+
SafePromiseAll,
1617
SafePromiseAllReturnVoid,
1718
SafePromiseAllSettledReturnVoid,
19+
PromiseResolve,
1820
SafeMap,
1921
SafeSet,
2022
StringPrototypeIndexOf,
@@ -24,6 +26,7 @@ const {
2426

2527
const { spawn } = require('child_process');
2628
const { readdirSync, statSync } = require('fs');
29+
const { finished } = require('internal/streams/end-of-stream');
2730
// TODO(aduh95): switch to internal/readline/interface when backporting to Node.js 16.x is no longer a concern.
2831
const { createInterface } = require('readline');
2932
const { FilesWatcher } = require('internal/watch_mode/files_watcher');
@@ -33,7 +36,7 @@ const {
3336
ERR_TEST_FAILURE,
3437
},
3538
} = require('internal/errors');
36-
const { validateArray, validateBoolean } = require('internal/validators');
39+
const { validateArray, validateBoolean, validateFunction } = require('internal/validators');
3740
const { getInspectPort, isUsingInspector, isInspectorMessage } = require('internal/util/inspector');
3841
const { kEmptyObject } = require('internal/util');
3942
const { createTestTree } = require('internal/test_runner/harness');
@@ -299,7 +302,10 @@ function runTestFile(path, root, inspectPort, filesWatcher) {
299302
subtest.addToReport(ast);
300303
});
301304

302-
const { 0: code, 1: signal } = await once(child, 'exit', { signal: t.signal });
305+
const { 0: { 0: code, 1: signal } } = await SafePromiseAll([
306+
once(child, 'exit', { signal: t.signal }),
307+
finished(parser, { signal: t.signal }),
308+
]);
303309

304310
runningProcesses.delete(path);
305311
runningSubtests.delete(path);
@@ -348,14 +354,17 @@ function run(options) {
348354
if (options === null || typeof options !== 'object') {
349355
options = kEmptyObject;
350356
}
351-
const { concurrency, timeout, signal, files, inspectPort, watch } = options;
357+
const { concurrency, timeout, signal, files, inspectPort, watch, setup } = options;
352358

353359
if (files != null) {
354360
validateArray(files, 'options.files');
355361
}
356362
if (watch != null) {
357363
validateBoolean(watch, 'options.watch');
358364
}
365+
if (setup != null) {
366+
validateFunction(setup, 'options.setup');
367+
}
359368

360369
const root = createTestTree({ concurrency, timeout, signal });
361370
const testFiles = files ?? createTestFileList();
@@ -366,13 +375,13 @@ function run(options) {
366375
filesWatcher = watchFiles(testFiles, root, inspectPort);
367376
postRun = undefined;
368377
}
369-
370-
PromisePrototypeThen(SafePromiseAllSettledReturnVoid(testFiles, (path) => {
378+
const runFiles = () => SafePromiseAllSettledReturnVoid(testFiles, (path) => {
371379
const subtest = runTestFile(path, root, inspectPort, filesWatcher);
372380
runningSubtests.set(path, subtest);
373381
return subtest;
374-
}), postRun);
382+
});
375383

384+
PromisePrototypeThen(PromisePrototypeThen(PromiseResolve(setup?.(root.reporter)), runFiles), postRun);
376385

377386
return root.reporter;
378387
}

0 commit comments

Comments
 (0)