-
Notifications
You must be signed in to change notification settings - Fork 299
Description
Node.js Version
v24.12.0
NPM Version
v11.6.2
Operating System
Darwin
Subsystem
Other
Description
There appears to be scenarios where the returned promise from suite causes the node test runner to hang.
I then found that I could drop the await from suite and it was good to go. I questioned why I was using await to begin with here, which lead me to the definitely typed types where the return of suite and test is documented as Promise<void>.
I then read through the documentation which showed that no await is ever used with suite in examples, and then I also see in node's own use of the test runner await is excluded.
I was looking through how suite was implemented to be sure that a promise was returned, and yeah, there is a path there from suite to a function that is async (Test.prototype.run, called by Test.prototype.start), this answers that the await is somewhat genuine still on these functions.
The actual question here I have for help is, is the return promise for these functions ever actually useful for a consumer of these tests? Or are they a foot-gun instead given things like concurrency being incoming (but experimental)?
Is there a reason why at least the top level suite wouldn't be void'd instead of the promise returned? Allowing then the process to receive any unhandled rejection or for the test runner to do its thing.
function run(name, options, fn, overrides) {
const parent = testResources.get(executionAsyncId()) || lazyBootstrapRoot();
const subtest = parent.createSubtest(Factory, name, options, fn, overrides);
if (parent instanceof Suite) {
return;
}
void startSubtestAfterBootstrap(subtest);
}I get test returning a promise and being usable where different tests need to be aligned, but it feels more of a job for sub tests within a test context.
PS. I haven't created a bug report here for the test-isolation flag causing the problem case where this question came up (I should open this though following this general help)
Minimal Reproduction
node --test-concurrency 1 --test-isolation none --test src/**/*.spec.js
src/index.await.spec.js:
import { suite, test } from "node:test";
await suite("Suite", async () => {
await test("Test", async (t) => {
await t.test("Subtest", async () => {
await fetch("https://example.com");
});
});
});src/index.no-await.spec.js:
import { suite, test } from "node:test";
suite("Suite", async () => {
test("Test", async (t) => {
await t.test("Subtest", async () => {
await fetch("https://example.com");
});
});
});Output
On force exiting the process:
$ node --test-concurrency 1 --test-isolation none --test src/index.await.spec.js
^C▶ Suite
✖ Test
✖ Suite
ℹ tests 1
ℹ suites 1
ℹ pass 0
ℹ fail 0
ℹ cancelled 1
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 11228.317959
✖ failing tests:
test at src/index.await.spec.js:4:9
✖ Test
'Promise resolution is still pending but the event loop has already resolved
When not including await:
$ node --test-concurrency 1 --test-isolation none --test src/index.no-await.spec.js
▶ Suite
▶ Test
✔ Subtest (734.810959ms)
✔ Test (735.376334ms)
✔ Suite (735.687584ms)
ℹ tests 2
ℹ suites 1
ℹ pass 2
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 820.4665
When using await and defaults:
$ node --test src/index.await.spec.js
▶ Suite
▶ Test
✔ Subtest (628.745958ms)
✔ Test (629.537417ms)
✔ Suite (629.883ms)
ℹ tests 2
ℹ suites 1
ℹ pass 2
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 742.470041
Before You Submit
- I have looked for issues that already exist before submitting this
- My issue follows the guidelines in the README file, and follows the 'How to ask a good question' guide at https://stackoverflow.com/help/how-to-ask