supertest: ECONNRESET when running "many" tests
Hey there,
we run into random ECONNRESET
problems for weeks now and tried many things to mitigate the problem. We use supertest for e2e testing a GraphQL API built with Nest.js.
We run it like so:
GraphQLQuery.ts
:
export class GraphQlQuery {
private static _bindings: Map<string, supertest.SuperTest<supertest.Test>>;
static queryGraphQl(app: INestApplication, query: GraphQlQuery, token?: string): supertest.Test {
if (!GraphQlQuery._bindings) {
GraphQlQuery._bindings = new Map();
}
let binding = GraphQlQuery._bindings.get(app.getHttpServer().testHash);
if (!binding) {
binding = request(app.getHttpServer());
GraphQlQuery._bindings.set(app.getHttpServer().testHash, binding);
}
const req = binding.post("/graphql");
if (token) {
req.set({ Authorization: `Bearer ${token}` });
}
req.send({ operationName: null, query: query.build() })
.expect((response) => {
if (!response.ok) {
console.error(JSON.stringify(response, null, 2));
}
})
.expect(200);
return req;
}
// ...
}
Somewhere in the tests, we can then do
GraphQlQuery.queryGraphQl(app, query, jwt).then((response) => {
expect(response).toBe(something);
});
The reason we do all the GraphQLQuery._bindings
-stuff is because we are aware that those bindings should be reused. We create the Nest.js app in our beforeAll()
-hooks, where we also add the testHash
to the HTTP Server. It’s basically a UUID to ensure that we can map bindings to test-suites. We also run Jest with --runInBand
on the CI, so nothing should run concurrently. We have around 80 tests now which all rely on supertest and the more tests we build, the worse it gets. Up until to a point where we need to run the whole CI-step multiple times until ECONNRESET
doesn’t happen any more. Sometimes up to 10 times or so, with each pipeline needing ~5 minutes.
Unfortunately I didn’t find much information about our problems and since Nest.js recommends supertest (and I think I can say that on behalf of the team, we really like the approach), I am wondering what we’re missing.
Any help appreciated!
About this issue
- Original URL
- State: open
- Created 3 years ago
- Reactions: 7
- Comments: 27 (2 by maintainers)
It seems that when calling supertest many times in a concurrent manner this code https://github.com/visionmedia/supertest/blob/28116f9060c1904a433e7d69f1c14db32cf60279/lib/test.js#L61 will spin up multiple HTTP servers or start listening on multiple ports (?).
My solution is to call
app.getHttpServer().listen(0);
after test app initialization in the beforeAll hook. This way the HTTP server can warm up and all supertest calls use the same address.So far worked fine for me. Hope that helps in your case as well.
Also started experiencing this in tests while bumping our app to node v20 with many requests with array.map that returns many request-handlers awaited by a Promise.all(). Worked fine in node 18.
I wrote test to reproduce problem
There are may be different output in terminal after executions:
or
etc.
But i have no idea how to fix this 😦
What worked for us is:
I couldn’t figure out the exact reason but I suspected it was attempting to start another server so providing a URI instead somehow just fixed it.
Hopefully it’s useful for at least one person going through this difficult and painful time. 😅
FWIW, I also noticed this issue with Node 20 earlier. The test that ran into it worked fine with Node 18 so far, up to v18.17.1; as of v18.18.0, it’s also breaking there. Not sure if this helps at all, but maybe it’s useful for narrowing down the cause? 😄
And assign it to me I’ll fix it later on this week.
Another issue that @shadowgate15 @spence-s and I found was that port 5000 is being used by AirPlay receiver on macOS Monterey via https://developer.apple.com/forums/thread/682332. I believe that @shadowgate15 is changing tests to use
get-port
instead to launch port for ZUUL / server.listen.