Skip to content

Commit af339fd

Browse files
committed
test_runner: change root test to be a suite
1 parent a5be448 commit af339fd

17 files changed

Lines changed: 285 additions & 40 deletions

lib/internal/test_runner/harness.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
const {
33
ArrayPrototypeForEach,
44
FunctionPrototypeBind,
5-
PromiseResolve,
65
SafeMap,
76
} = primordials;
87
const { getCallerLocation } = internalBinding('util');
@@ -23,12 +22,13 @@ const {
2322
parseCommandLine,
2423
setupTestReporters,
2524
} = require('internal/test_runner/utils');
25+
const { setImmediate } = require('timers');
2626
const { bigint: hrtime } = process.hrtime;
2727

2828
const testResources = new SafeMap();
2929

3030
function createTestTree(options = kEmptyObject) {
31-
return setup(new Test({ __proto__: null, ...options, name: '<root>' }));
31+
return setup(new Suite({ __proto__: null, ...options, name: '<root>' }));
3232
}
3333

3434
function createProcessEventHandler(eventName, rootTest) {
@@ -198,24 +198,24 @@ function getGlobalRoot() {
198198
}
199199
});
200200
reportersSetup = setupTestReporters(globalRoot);
201+
setImmediate(() => globalRoot.run());
201202
}
202203
return globalRoot;
203204
}
204205

205-
async function startSubtest(subtest) {
206+
async function startSubtest(subtest, parent) {
206207
await reportersSetup;
207208
getGlobalRoot().harness.bootstrapComplete = true;
208-
await subtest.start();
209+
if (!(parent instanceof Suite) || (parent.parent === null && parent.endTime !== null)) {
210+
await subtest.start();
211+
}
209212
}
210213

211214
function runInParentContext(Factory) {
212215
function run(name, options, fn, overrides) {
213216
const parent = testResources.get(executionAsyncId()) || getGlobalRoot();
214217
const subtest = parent.createSubtest(Factory, name, options, fn, overrides);
215-
if (!(parent instanceof Suite)) {
216-
return startSubtest(subtest);
217-
}
218-
return PromiseResolve();
218+
return startSubtest(subtest, parent);
219219
}
220220

221221
const test = (name, options, fn) => {

lib/internal/test_runner/runner.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ const {
1616
PromisePrototypeThen,
1717
SafePromiseAll,
1818
SafePromiseAllReturnVoid,
19-
SafePromiseAllSettledReturnVoid,
2019
PromiseResolve,
2120
SafeMap,
2221
SafeSet,
@@ -378,7 +377,9 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
378377
throw err;
379378
}
380379
});
381-
return subtest.start();
380+
if (filesWatcher) {
381+
return subtest.start();
382+
}
382383
}
383384

384385
function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) {
@@ -476,22 +477,27 @@ function run(options) {
476477
testFiles = ArrayPrototypeFilter(testFiles, (_, index) => index % shard.total === shard.index - 1);
477478
}
478479

479-
let postRun = () => root.postRun();
480480
let filesWatcher;
481481
if (watch) {
482482
filesWatcher = watchFiles(testFiles, root, inspectPort, signal, testNamePatterns);
483-
postRun = undefined;
484483
}
484+
485485
const runFiles = () => {
486486
root.harness.bootstrapComplete = true;
487-
return SafePromiseAllSettledReturnVoid(testFiles, (path) => {
488-
const subtest = runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns);
489-
filesWatcher?.runningSubtests.set(path, subtest);
490-
return subtest;
491-
});
487+
root.buildPhaseFinished = false;
488+
for (let i = 0; i < testFiles.length; i++) {
489+
const path = testFiles[i];
490+
const enqueued = runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns);
491+
filesWatcher?.runningSubtests.set(path, enqueued);
492+
}
493+
root.buildPhaseFinished = true;
494+
if (filesWatcher) {
495+
return root.processPendingSubtests();
496+
}
497+
return PromisePrototypeThen(root.run(), () => root.postRun());
492498
};
493499

494-
PromisePrototypeThen(PromisePrototypeThen(PromiseResolve(setup?.(root)), runFiles), postRun);
500+
PromisePrototypeThen(PromiseResolve(setup?.(root)), runFiles);
495501

496502
return root.reporter;
497503
}

lib/internal/test_runner/test.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ class SuiteContext {
198198
get name() {
199199
return this.#suite.name;
200200
}
201+
202+
diagnostic(message) {
203+
this.#suite.diagnostic(message);
204+
}
201205
}
202206

203207
class Test extends AsyncResource {
@@ -430,7 +434,7 @@ class Test extends AsyncResource {
430434

431435
// If this test has already ended, attach this test to the root test so
432436
// that the error can be properly reported.
433-
const preventAddingSubtests = this.finished || this.buildPhaseFinished;
437+
const preventAddingSubtests = (this.finished || this.buildPhaseFinished) && parent.parent !== null;
434438
if (preventAddingSubtests) {
435439
while (parent.parent !== null) {
436440
parent = parent.parent;
@@ -940,7 +944,7 @@ class Suite extends Test {
940944
return;
941945
}
942946

943-
if (this.parent.hooks.before.length > 0) {
947+
if (this.parent?.hooks.before.length > 0) {
944948
await this.parent.runHook('before', this.parent.getRunArgs());
945949
}
946950

@@ -965,7 +969,9 @@ class Suite extends Test {
965969
stopPromise?.[SymbolDispose]();
966970
}
967971

968-
this.postRun();
972+
if (this.parent !== null) {
973+
this.postRun();
974+
}
969975
}
970976
}
971977

test/fixtures/test-runner/output/abort.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
require('../../../common');
33
const test = require('node:test');
44

5-
test('promise timeout signal', { signal: AbortSignal.timeout(1) }, async (t) => {
5+
test('promise timeout signal', { signal: AbortSignal.timeout(100) }, async (t) => {
66
await Promise.all([
77
t.test('ok 1', async () => {}),
88
t.test('ok 2', () => {}),
@@ -22,7 +22,7 @@ test('promise abort signal', { signal: AbortSignal.abort() }, async (t) => {
2222
await t.test('should not appear', () => {});
2323
});
2424

25-
test('callback timeout signal', { signal: AbortSignal.timeout(1) }, (t, done) => {
25+
test('callback timeout signal', { signal: AbortSignal.timeout(100) }, (t, done) => {
2626
t.test('ok 1', async () => {});
2727
t.test('ok 2', () => {});
2828
t.test('ok 3', { signal: t.signal }, async () => {});
@@ -40,7 +40,7 @@ test('callback abort signal', { signal: AbortSignal.abort() }, (t, done) => {
4040
t.test('should not appear', done);
4141
});
4242

43-
// AbortSignal.timeout(1) doesn't prevent process from closing
43+
// AbortSignal.timeout doesn't prevent process from closing
4444
// thus we have to keep the process open to prevent cancelation
4545
// of the entire test tree
4646
setTimeout(() => {}, 1000);

test/fixtures/test-runner/output/abort.snapshot

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ TAP version 13
2828
failureType: 'cancelledByParent'
2929
error: 'test did not finish before its parent and was cancelled'
3030
code: 'ERR_TEST_FAILURE'
31+
stack: |-
32+
async Promise.all (index 0)
3133
...
3234
# Subtest: not ok 2
3335
not ok 6 - not ok 2
@@ -37,6 +39,8 @@ TAP version 13
3739
failureType: 'cancelledByParent'
3840
error: 'test did not finish before its parent and was cancelled'
3941
code: 'ERR_TEST_FAILURE'
42+
stack: |-
43+
async Promise.all (index 0)
4044
...
4145
# Subtest: not ok 3
4246
not ok 7 - not ok 3
@@ -165,6 +169,8 @@ not ok 2 - promise abort signal
165169
failureType: 'cancelledByParent'
166170
error: 'test did not finish before its parent and was cancelled'
167171
code: 'ERR_TEST_FAILURE'
172+
stack: |-
173+
async Promise.all (index 2)
168174
...
169175
# Subtest: not ok 2
170176
not ok 6 - not ok 2
@@ -174,6 +180,8 @@ not ok 2 - promise abort signal
174180
failureType: 'cancelledByParent'
175181
error: 'test did not finish before its parent and was cancelled'
176182
code: 'ERR_TEST_FAILURE'
183+
stack: |-
184+
async Promise.all (index 2)
177185
...
178186
# Subtest: not ok 3
179187
not ok 7 - not ok 3

test/fixtures/test-runner/output/abort_hooks.snapshot

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
TAP version 13
12
before
23
2.1
34
2.2
@@ -6,7 +7,6 @@ beforeEach
67
4.1
78
afterEach
89
4.2
9-
TAP version 13
1010
# Subtest: 1 before describe
1111
# Subtest: test 1
1212
not ok 1 - test 1
@@ -16,6 +16,8 @@ TAP version 13
1616
failureType: 'cancelledByParent'
1717
error: 'test did not finish before its parent and was cancelled'
1818
code: 'ERR_TEST_FAILURE'
19+
stack: |-
20+
async Promise.all (index 0)
1921
...
2022
# Subtest: test 2
2123
not ok 2 - test 2
@@ -25,6 +27,8 @@ TAP version 13
2527
failureType: 'cancelledByParent'
2628
error: 'test did not finish before its parent and was cancelled'
2729
code: 'ERR_TEST_FAILURE'
30+
stack: |-
31+
async Promise.all (index 0)
2832
...
2933
1..2
3034
not ok 1 - 1 before describe
@@ -133,6 +137,8 @@ not ok 3 - 3 beforeEach describe
133137
failureType: 'subtestsFailed'
134138
error: '2 subtests failed'
135139
code: 'ERR_TEST_FAILURE'
140+
stack: |-
141+
async Promise.all (index 2)
136142
...
137143
# Subtest: 4 afterEach describe
138144
# Subtest: test 1
@@ -186,6 +192,8 @@ not ok 4 - 4 afterEach describe
186192
failureType: 'subtestsFailed'
187193
error: '2 subtests failed'
188194
code: 'ERR_TEST_FAILURE'
195+
stack: |-
196+
async Promise.all (index 3)
189197
...
190198
1..4
191199
# tests 8

test/fixtures/test-runner/output/abort_suite.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
require('../../../common');
33
const { describe, it } = require('node:test');
44

5-
describe('describe timeout signal', { signal: AbortSignal.timeout(1) }, (t) => {
5+
describe('describe timeout signal', { signal: AbortSignal.timeout(100) }, (t) => {
66
it('ok 1', async () => {});
77
it('ok 2', () => {});
88
it('ok 3', { signal: t.signal }, async () => {});
@@ -20,7 +20,7 @@ describe('describe abort signal', { signal: AbortSignal.abort() }, () => {
2020
it('should not appear', () => {});
2121
});
2222

23-
// AbortSignal.timeout(1) doesn't prevent process from closing
23+
// AbortSignal.timeout doesn't prevent process from closing
2424
// thus we have to keep the process open to prevent cancelation
2525
// of the entire test tree
2626
setTimeout(() => {}, 1000);

test/fixtures/test-runner/output/abort_suite.snapshot

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ TAP version 13
2828
failureType: 'cancelledByParent'
2929
error: 'test did not finish before its parent and was cancelled'
3030
code: 'ERR_TEST_FAILURE'
31+
stack: |-
32+
async Promise.all (index 0)
3133
...
3234
# Subtest: not ok 2
3335
not ok 6 - not ok 2
@@ -37,6 +39,8 @@ TAP version 13
3739
failureType: 'cancelledByParent'
3840
error: 'test did not finish before its parent and was cancelled'
3941
code: 'ERR_TEST_FAILURE'
42+
stack: |-
43+
async Promise.all (index 0)
4044
...
4145
# Subtest: not ok 3
4246
not ok 7 - not ok 3

test/fixtures/test-runner/output/default_output.snapshot

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*[39m
99
*[39m
1010
*[39m
11+
at async Promise.all (index 0)
1112
*[39m
1213

1314
[90m﹣ should skip [90m(*ms)[39m # SKIP[39m
@@ -47,6 +48,7 @@
4748
*[39m
4849
*[39m
4950
*[39m
51+
at async Promise.all (index 0)
5052
*[39m
5153

5254
*

0 commit comments

Comments
 (0)