Skip to content

Commit aac5ad9

Browse files
authored
test_runner: add test:complete event to reflect execution order
PR-URL: #51909 Fixes: #51907 Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
1 parent 30c9181 commit aac5ad9

File tree

4 files changed

+84
-13
lines changed

4 files changed

+84
-13
lines changed

doc/api/test.md

+48
Original file line numberDiff line numberDiff line change
@@ -2438,6 +2438,9 @@ A successful call to [`run()`][] method will return a new {TestsStream}
24382438
object, streaming a series of events representing the execution of the tests.
24392439
`TestsStream` will emit events, in the order of the tests definition
24402440

2441+
Some of the events are guaranteed to be emitted in the same order as the tests
2442+
are defined, while others are emitted in the order that the tests execute.
2443+
24412444
### Event: `'test:coverage'`
24422445

24432446
* `data` {Object}
@@ -2484,6 +2487,34 @@ object, streaming a series of events representing the execution of the tests.
24842487

24852488
Emitted when code coverage is enabled and all tests have completed.
24862489

2490+
### Event: `'test:complete'`
2491+
2492+
* `data` {Object}
2493+
* `column` {number|undefined} The column number where the test is defined, or
2494+
`undefined` if the test was run through the REPL.
2495+
* `details` {Object} Additional execution metadata.
2496+
* `passed` {boolean} Whether the test passed or not.
2497+
* `duration_ms` {number} The duration of the test in milliseconds.
2498+
* `error` {Error|undefined} An error wrapping the error thrown by the test
2499+
if it did not pass.
2500+
* `cause` {Error} The actual error thrown by the test.
2501+
* `type` {string|undefined} The type of the test, used to denote whether
2502+
this is a suite.
2503+
* `file` {string|undefined} The path of the test file,
2504+
`undefined` if test was run through the REPL.
2505+
* `line` {number|undefined} The line number where the test is defined, or
2506+
`undefined` if the test was run through the REPL.
2507+
* `name` {string} The test name.
2508+
* `nesting` {number} The nesting level of the test.
2509+
* `testNumber` {number} The ordinal number of the test.
2510+
* `todo` {string|boolean|undefined} Present if [`context.todo`][] is called
2511+
* `skip` {string|boolean|undefined} Present if [`context.skip`][] is called
2512+
2513+
Emitted when a test completes its execution.
2514+
This event is not emitted in the same order as the tests are
2515+
defined.
2516+
The corresponding declaration ordered events are `'test:pass'` and `'test:fail'`.
2517+
24872518
### Event: `'test:dequeue'`
24882519

24892520
* `data` {Object}
@@ -2497,6 +2528,8 @@ Emitted when code coverage is enabled and all tests have completed.
24972528
* `nesting` {number} The nesting level of the test.
24982529

24992530
Emitted when a test is dequeued, right before it is executed.
2531+
This event is not guaranteed to be emitted in the same order as the tests are
2532+
defined. The corresponding declaration ordered event is `'test:start'`.
25002533

25012534
### Event: `'test:diagnostic'`
25022535

@@ -2511,6 +2544,8 @@ Emitted when a test is dequeued, right before it is executed.
25112544
* `nesting` {number} The nesting level of the test.
25122545

25132546
Emitted when [`context.diagnostic`][] is called.
2547+
This event is guaranteed to be emitted in the same order as the tests are
2548+
defined.
25142549

25152550
### Event: `'test:enqueue'`
25162551

@@ -2548,6 +2583,9 @@ Emitted when a test is enqueued for execution.
25482583
* `skip` {string|boolean|undefined} Present if [`context.skip`][] is called
25492584

25502585
Emitted when a test fails.
2586+
This event is guaranteed to be emitted in the same order as the tests are
2587+
defined.
2588+
The corresponding execution ordered event is `'test:complete'`.
25512589

25522590
### Event: `'test:pass'`
25532591

@@ -2569,6 +2607,9 @@ Emitted when a test fails.
25692607
* `skip` {string|boolean|undefined} Present if [`context.skip`][] is called
25702608

25712609
Emitted when a test passes.
2610+
This event is guaranteed to be emitted in the same order as the tests are
2611+
defined.
2612+
The corresponding execution ordered event is `'test:complete'`.
25722613

25732614
### Event: `'test:plan'`
25742615

@@ -2583,6 +2624,8 @@ Emitted when a test passes.
25832624
* `count` {number} The number of subtests that have ran.
25842625

25852626
Emitted when all subtests have completed for a given test.
2627+
This event is guaranteed to be emitted in the same order as the tests are
2628+
defined.
25862629

25872630
### Event: `'test:start'`
25882631

@@ -2599,6 +2642,7 @@ Emitted when all subtests have completed for a given test.
25992642
Emitted when a test starts reporting its own and its subtests status.
26002643
This event is guaranteed to be emitted in the same order as the tests are
26012644
defined.
2645+
The corresponding execution ordered event is `'test:dequeue'`.
26022646

26032647
### Event: `'test:stderr'`
26042648

@@ -2612,6 +2656,8 @@ defined.
26122656

26132657
Emitted when a running test writes to `stderr`.
26142658
This event is only emitted if `--test` flag is passed.
2659+
This event is not guaranteed to be emitted in the same order as the tests are
2660+
defined.
26152661

26162662
### Event: `'test:stdout'`
26172663

@@ -2625,6 +2671,8 @@ This event is only emitted if `--test` flag is passed.
26252671

26262672
Emitted when a running test writes to `stdout`.
26272673
This event is only emitted if `--test` flag is passed.
2674+
This event is not guaranteed to be emitted in the same order as the tests are
2675+
defined.
26282676

26292677
### Event: `'test:watch:drained'`
26302678

lib/internal/test_runner/test.js

+21-10
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,10 @@ class Test extends AsyncResource {
726726
this.mock?.reset();
727727

728728
if (this.parent !== null) {
729+
const report = this.getReportDetails();
730+
report.details.passed = this.passed;
731+
this.reporter.complete(this.nesting, this.loc, this.testNumber, this.name, report.details, report.directive);
732+
729733
this.parent.activeSubtests--;
730734
this.parent.addReadySubtest(this);
731735
this.parent.processReadySubtestRange(false);
@@ -806,13 +810,7 @@ class Test extends AsyncResource {
806810
return Number(this.endTime - this.startTime) / 1_000_000;
807811
}
808812

809-
report() {
810-
countCompletedTest(this);
811-
if (this.subtests.length > 0) {
812-
this.reporter.plan(this.subtests[0].nesting, this.loc, this.subtests.length);
813-
} else {
814-
this.reportStarted();
815-
}
813+
getReportDetails() {
816814
let directive;
817815
const details = { __proto__: null, duration_ms: this.duration() };
818816

@@ -825,12 +823,25 @@ class Test extends AsyncResource {
825823
if (this.reportedType) {
826824
details.type = this.reportedType;
827825
}
826+
if (!this.passed) {
827+
details.error = this.error;
828+
}
829+
return { __proto__: null, details, directive };
830+
}
831+
832+
report() {
833+
countCompletedTest(this);
834+
if (this.subtests.length > 0) {
835+
this.reporter.plan(this.subtests[0].nesting, this.loc, this.subtests.length);
836+
} else {
837+
this.reportStarted();
838+
}
839+
const report = this.getReportDetails();
828840

829841
if (this.passed) {
830-
this.reporter.ok(this.nesting, this.loc, this.testNumber, this.name, details, directive);
842+
this.reporter.ok(this.nesting, this.loc, this.testNumber, this.name, report.details, report.directive);
831843
} else {
832-
details.error = this.error;
833-
this.reporter.fail(this.nesting, this.loc, this.testNumber, this.name, details, directive);
844+
this.reporter.fail(this.nesting, this.loc, this.testNumber, this.name, report.details, report.directive);
834845
}
835846

836847
for (let i = 0; i < this.diagnostics.length; i++) {

lib/internal/test_runner/tests_stream.js

+12
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ class TestsStream extends Readable {
5353
});
5454
}
5555

56+
complete(nesting, loc, testNumber, name, details, directive) {
57+
this[kEmitMessage]('test:complete', {
58+
__proto__: null,
59+
name,
60+
nesting,
61+
testNumber,
62+
details,
63+
...loc,
64+
...directive,
65+
});
66+
}
67+
5668
plan(nesting, loc, count) {
5769
this[kEmitMessage]('test:plan', {
5870
__proto__: null,

test/parallel/test-runner-reporters.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ describe('node:test reporters', { concurrency: true }, () => {
9696
testFile]);
9797
assert.strictEqual(child.stderr.toString(), '');
9898
const stdout = child.stdout.toString();
99-
assert.match(stdout, /{"test:enqueue":5,"test:dequeue":5,"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/);
99+
assert.match(stdout, /{"test:enqueue":5,"test:dequeue":5,"test:complete":5,"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/);
100100
assert.strictEqual(stdout.slice(0, filename.length + 2), `${filename} {`);
101101
});
102102
});
@@ -108,7 +108,7 @@ describe('node:test reporters', { concurrency: true }, () => {
108108
assert.strictEqual(child.stderr.toString(), '');
109109
assert.match(
110110
child.stdout.toString(),
111-
/^package: reporter-cjs{"test:enqueue":5,"test:dequeue":5,"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/,
111+
/^package: reporter-cjs{"test:enqueue":5,"test:dequeue":5,"test:complete":5,"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/,
112112
);
113113
});
114114

@@ -119,7 +119,7 @@ describe('node:test reporters', { concurrency: true }, () => {
119119
assert.strictEqual(child.stderr.toString(), '');
120120
assert.match(
121121
child.stdout.toString(),
122-
/^package: reporter-esm{"test:enqueue":5,"test:dequeue":5,"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/,
122+
/^package: reporter-esm{"test:enqueue":5,"test:dequeue":5,"test:complete":5,"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/,
123123
);
124124
});
125125

0 commit comments

Comments
 (0)