node.jsjestjssupertest

Jest test randomly fails with "read ECONNRESET" without stack trace


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:

I am using:


Solution

  • 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 the supertest docs to repeat the following pattern for each test:

    request(app)
      .get('/user')
      .status(200);
    

    The problem with this is that supertest is internally considering app.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:

    let server;
    beforeAll((done) => {
      server = app.listen(0, '127.0.0.1', done);
    });
    
    afterAll(() => {
      server.close();
    });
    
    test('Should get user', async () => {
      await request(server)
        .get('/user')
        .expect(200);
    });
    

    This way, the race condition mentioned above is eliminated and the READ ECONNRESET error should disappear.

    Issue #2 - incorrect port selection
    In addition to the READ ECONNRESET error, I also sometimes encountered a 400 status code with the WebSockets request was expected message.

    It turns out that by default supertest picks a random free port to start the server on. However, supertest looks for a free port on 0.0.0.0, while other services might use ports on a different host: 127.0.0.1.

    An example of this is the VSCode debugger. Because, it runs on a different host, supertest might 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 the server.

    The solution is to explicitly specify the host when starting up the server as mentioned in Issue #1 above:

    server = app.listen(0, '127.0.0.1', done);
    

    Because the hostname is now supplied, supertest will only use free ports on that hostname.

    This "port selection issue" was found by the same person who opened the Github issue mentioned above here.