diff --git a/doc/api/test.md b/doc/api/test.md index e520e18e3d8431..42c77e696043f7 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -1459,6 +1459,16 @@ object, streaming a series of events representing the execution of the tests. Emitted when code coverage is enabled and all tests have completed. +### Event: `'test:dequeue'` + +* `data` {Object} + * `file` {string|undefined} The path of the test file, + undefined if test is not ran through a file. + * `name` {string} The test name. + * `nesting` {number} The nesting level of the test. + +Emitted when a test is dequeued, right before it is executed. + ### Event: `'test:diagnostic'` * `data` {Object} @@ -1469,6 +1479,16 @@ Emitted when code coverage is enabled and all tests have completed. Emitted when [`context.diagnostic`][] is called. +### Event: `'test:enqueue'` + +* `data` {Object} + * `file` {string|undefined} The path of the test file, + undefined if test is not ran through a file. + * `name` {string} The test name. + * `nesting` {number} The nesting level of the test. + +Emitted when a test is enqueued for execution. + ### Event: `'test:fail'` * `data` {Object} @@ -1518,7 +1538,9 @@ Emitted when all subtests have completed for a given test. * `name` {string} The test name. * `nesting` {number} The nesting level of the test. -Emitted when a test starts. +Emitted when a test starts reporting its own and its subtests status. +This event is guaranteed to be emitted in the same order as the tests are +defined. ### Event: `'test:stderr'` diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index a6601fe6e79d71..c926d3c07f10cf 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -311,7 +311,9 @@ class Test extends AsyncResource { async processPendingSubtests() { while (this.pendingSubtests.length > 0 && this.hasConcurrency()) { const deferred = ArrayPrototypeShift(this.pendingSubtests); - await deferred.test.run(); + const test = deferred.test; + this.reporter.dequeue(test.nesting, kFilename, test.name); + await test.run(); deferred.resolve(); } } @@ -469,6 +471,7 @@ class Test extends AsyncResource { // If there is enough available concurrency to run the test now, then do // it. Otherwise, return a Promise to the caller and mark the test as // pending for later execution. + this.reporter.enqueue(this.nesting, kFilename, this.name); if (!this.parent.hasConcurrency()) { const deferred = createDeferredPromise(); @@ -477,6 +480,7 @@ class Test extends AsyncResource { return deferred.promise; } + this.reporter.dequeue(this.nesting, kFilename, this.name); return this.run(); } diff --git a/lib/internal/test_runner/tests_stream.js b/lib/internal/test_runner/tests_stream.js index 89fff7f28e586c..20e7d458704b20 100644 --- a/lib/internal/test_runner/tests_stream.js +++ b/lib/internal/test_runner/tests_stream.js @@ -49,6 +49,14 @@ class TestsStream extends Readable { return { __proto__: null, todo: reason ?? true }; } + enqueue(nesting, file, name) { + this[kEmitMessage]('test:enqueue', { __proto__: null, nesting, file, name }); + } + + dequeue(nesting, file, name) { + this[kEmitMessage]('test:dequeue', { __proto__: null, nesting, file, name }); + } + start(nesting, file, name) { this[kEmitMessage]('test:start', { __proto__: null, nesting, file, name }); } diff --git a/test/parallel/test-runner-reporters.js b/test/parallel/test-runner-reporters.js index a9746733fe6975..f25e1a18b9d78d 100644 --- a/test/parallel/test-runner-reporters.js +++ b/test/parallel/test-runner-reporters.js @@ -97,7 +97,7 @@ describe('node:test reporters', { concurrency: true }, () => { testFile]); assert.strictEqual(child.stderr.toString(), ''); const stdout = child.stdout.toString(); - assert.match(stdout, /{"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/); + assert.match(stdout, /{"test:enqueue":5,"test:dequeue":5,"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/); assert.strictEqual(stdout.slice(0, filename.length + 2), `${filename} {`); }); }); @@ -109,7 +109,7 @@ describe('node:test reporters', { concurrency: true }, () => { assert.strictEqual(child.stderr.toString(), ''); assert.match( child.stdout.toString(), - /^package: reporter-cjs{"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/, + /^package: reporter-cjs{"test:enqueue":5,"test:dequeue":5,"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/, ); }); @@ -120,7 +120,7 @@ describe('node:test reporters', { concurrency: true }, () => { assert.strictEqual(child.stderr.toString(), ''); assert.match( child.stdout.toString(), - /^package: reporter-esm{"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/, + /^package: reporter-esm{"test:enqueue":5,"test:dequeue":5,"test:start":4,"test:pass":2,"test:fail":2,"test:plan":2,"test:diagnostic":\d+}$/, ); });