I have a Jest test suite using Supertest, containing around 300 tests. Most of the time they all pass. However, sometimes a test fails, which appears to be completely random.
It fails with the following message:
read ECONNRESET
Nothing else is shown, no stack trace nor anything else. I have tried:
The tests are interacting with a Postgres db, as well as Redis. The logs of both of these, show no errors
Thinking that it could be some sort of uncaught Node.js error I added the following, which also didn't catch anything:
process .on('unhandledRejection', (reason, p) => { console.error(reason, 'Unhandled Rejection at Promise', p); }) .on('uncaughtException', err => { console.error(err, 'Uncaught Exception thrown'); process.exit(1); });
I am using:
- Node.js: v18.18.2
- Jest: 29.7.0
- Supertest: 6.2.4
- OS: macOS 10.15.7
I have found that there are actually 2 issues with
supertest. One of them is related to Supertest's internals and one is related to the recommended usage of Supertest:Issue #1 - asynchronous startup
When starting up a server with
supertest, it is recommended by thesupertestdocs to repeat the following pattern for each test:The problem with this is that
supertestis internally consideringapp.listen()to be a "synchronous" event, while really it is "asynchronous". This can occasionally create a race condition, where the request reaches the server, before it is ready to accept any. This issue was already reported in this Github issue, but despite a good amount of upvotes, there seems to be no sign of this getting fixed.Luckily, it is pretty easy to workaround this issue, by starting the server in advance and manually controlling its lifecycle:
This way, the race condition mentioned above is eliminated and the
READ ECONNRESETerror should disappear.Issue #2 - incorrect port selection
In addition to the
READ ECONNRESETerror, I also sometimes encountered a400status code with theWebSockets request was expectedmessage.It turns out that by default
supertestpicks a random free port to start the server on. However,supertestlooks for a free port on0.0.0.0, while other services might use ports on a different host:127.0.0.1.An example of this is the
VSCodedebugger. Because, it runs on a different host,supertestmight select the same port the debugger is listening on. This results in the error above, as the request is now send to the debugger as opposed to theserver.The solution is to explicitly specify the
hostwhen starting up the server as mentioned inIssue #1above:Because the
hostnameis now supplied,supertestwill only use free ports on thathostname.This "port selection issue" was found by the same person who opened the Github issue mentioned above here.