-
-
Notifications
You must be signed in to change notification settings - Fork 31.6k
Node 24 test runner module does not wait for subtests to finish #58227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This was also a breaking change for us. I also don't see a good way forwards where we can still cover node 18 -> node 24. I would also prefer it if this change was reverted as the only benefit it seems to bring is some developer convenience. I don't think it actually added any capabilities, right? |
A simplified example of one issues we now face:
import test from 'node:test';
import assert from 'node:assert';
await test('outer', async (t1) => {
let a = 1;
let b = 1;
await t1.test('inner 1', async () => {
await new Promise((resolve) => setTimeout(resolve, 50));
// Run initial assert provided by the test case
// This passes in Node 22 and earlier but fails in node 24 !!
assert.equal(a, b);
});
// run "after" callback provided by the test case
await new Promise((resolve) => {
b = 2;
resolve();
});
await t1.test('inner 2', async () => {
// Run some extra asserts
assert.ok(b);
});
});
nvm, that didn't work at all :D |
I just read through the issue (#56664) closed by the PR which created this breaking change in The most of discussion there is about one lint rule of one lint tool. The lint tool is actually looking at types of If it ain’t broke, don’t fix it. |
Anyone is free to open a revert and see how it is received. |
Just found the problem. I had to move setup and teardown to Here is the code which helped me to understand the problem: import assert from "node:assert";
import test from "node:test";
import { setTimeout } from "node:timers/promises";
let res = 0;
await test("top level test", async (t) => {
t.beforeEach(() => {
console.log("before");
res = 0;
});
t.afterEach(() => {
console.log("after");
res = 0;
});
console.log("setup");
for (const x of [2500, 500]) {
await t.test(`subtest ${x}`, async () => {
await setTimeout(x);
res = x;
console.log(`done ${x}`);
assert.strictEqual(res, x);
});
}
console.log("teardown");
}); Using Node 24 it logs:
Using Node 22 it logs:
@cjihrig Really sorry about the noise. Looks like there is only one test executed at the time. My assumptions were wrong and the problem was elsewhere. How do you think, perhaps is it worth adding a note to documentation? |
@mrazauskas Can you re-open this issue? The In our case we have:
Such work can no longer be orchestrated in Node 24. The only way to make things work is to move everything async outside of sub tests. |
Considering all the discussions I've seen since the release, I think we should provide a way to optionally roll back to the previous behavior. I'll take a look over the next few days. |
Do you mean having await test('outer', async (t1) => {
let a = 1;
let b = 1;
await t1.test('inner 1', async (t) => {
t.after(); // <- here it does not work? |
By carefully adding bogus sub tests and using But it is a pretty bad DX. Having to use |
Version
v24.0.0
Platform
Subsystem
No response
What steps will reproduce the bug?
Node 24 introduced breaking change in the test runner via #56664
Author of the PR has mentioned the following in #56664 (comment)
In my case a
for..of
loop creates subtests dynamically and the next test must started only after previous is finished. These tests are triggering event emitter with different data and to collect output the events must appear in predictable sequence.The example above is using
await
, but it has no effect. The execution move to the second subtests without waiting for the first one to finish.By the way, the releases notes claim that this change “makes writing tests more intuitive and reduces common errors related to unhandled promises.” Hm.. but this behaviour looks to me exactly like an unhandled promise and my intuition is rather lost: how to ensure order of execution?
Is there a chance to revert the change?
Or perhaps it makes sense adding an option that brings back the old behaviour? I use
run()
in the project that got broken. So passing one more option would be fine.How often does it reproduce? Is there a required condition?
Always.
What is the expected behavior? Why is that the expected behavior?
The test runner should only execute one test or subtest at a time within the same file. Or provide a mechanism to ensure such behaviour.
What do you see instead?
All subtest created by the
for..of
loop run at the same time.Additional information
Thank you for working on Node.js.
The text was updated successfully, but these errors were encountered: