test: keep the suite runnable on Windows under Node 24+ - #361
Conversation
Every test ends with process.exit() right after fetching, which on Windows with Node 24 and later trips a libuv assertion in undici's socket teardown (nodejs/node#56645) and kills the process with exit code 3221226505. The harness runs each test through exec(), so that exit code rejects and every test reports as failed. The crash also drops whatever stdout was still buffered, so the captured output is unreliable even when a test did its work correctly. Preload a small module on win32 that lets the loop settle before exiting for real. Linux and macOS, and therefore CI, are untouched.
|
I tracked down the multer failure I mentioned above, and I was wrong to call it Windows-specific. It is a timing problem, fixed in #362. The test builds its 200kb file as It reaches CI green only because the runner serialises those parts faster than the timeout. A slower runner would fail it there too. With #362 applied, this branch gives 300 tests, 300 pass on Windows with Node 26.3. |
|
Correcting the number I gave in my previous comment: with #362 applied this branch gives 300 tests, 298 pass on Windows with Node 26.3, not 300. I had deduced the total instead of measuring it, and there was a second failure hiding behind the multer one.
let err = new Error('listen EADDRINUSE: address already in use :::' + port);which is the wording Node uses on Linux. On Windows Node reports the failure against I left it alone since it is a cosmetic difference in an error string, and making it platform-accurate means guessing at libuv wording per platform. Happy to send a patch if you would rather have it match. |
Running
npm teston Windows with Node 24 or later fails every single test, whatever the code does.Why
Each test ends with
process.exit()right after fetching. On Windows, Node 24 and later trip a libuv assertion when that happens while undici still holds keep-alive sockets:The process dies with exit code 3221226505, and since the harness runs tests through
exec(), that rejects and the test is reported as failed even though it did its work correctly. The crash also drops whatever stdout was still buffered, so the captured output is unreliable on top of the exit code, and comparisons against Express can silently be made against truncated text.It is not this project: it reproduces with plain
httpand no Express or uWS at all.Node 20.14 and 22.13 are fine, 24.0.2, 24.16, 25.0, 25.9 and 26.3 all crash on every run here. Upstream issue: nodejs/node#56645.
Fix
Preload a module on win32 that lets the loop settle before exiting for real. Linux and macOS, and therefore CI, do not load it and are untouched.
I measured the delay rather than guessing: 10ms still crashed 8 times out of 8, 50ms once out of 8, 100ms zero out of 8, so 100ms it is.
The tests that call
process.exit()do it as their last statement, exceptevents/event-finished.js, which calls it inside afinishhandler where nothing follows either, so delaying it does not let anything extra run.Result
Before: every test fails.
After, on Windows with Node 26.3: 300 tests, 298 pass, 2 fail. All categories pass except
middlewares, which fails onmulter.jsand takes the category with it.That multer failure is a separate, pre-existing problem, not something this change causes: on
mainits 200kb multipart upload fails with ECONNRESET 6 times out of 6 on Windows, while the same upload against Express 4 succeeds every time. It passes in CI, so it looks Windows-specific. I could not pin it down: a 200kb upload consumed withreq.on("data"), withreq.pipe(), or throughexpress.raw()all work, with and withoutcontent-length, and so does the same FormData request when consumed by hand rather than by multer. Worth its own issue.