0
votes

I'm writing tests for an API using jest and supertest. The first test passes as expected but all the tests that follow fail with the following error:

Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.

My test suite looks like this:

const app = require('../../index.js');
const request = require('supertest');
const faker = require('faker');
const HttpStatus = require('http-status-codes');

const agent = request.agent(app);
const { truncateDatabase } = require('./helpers/truncateDatabase');

beforeEach(async (done) => {
    app.on("serverStarted", () => {
        done(); // Wait for tests to run until the server has started
    });
});

afterEach(async () => {
    await truncateDatabase();
});

describe('The register route', () => {
    it('Can run a happy flow and register a user', async (done) => {
        const firstname = faker.name.firstName();
        const lastname = faker.name.lastName();

        return agent.post('/register')
            .send({ firstname, lastname })
            .expect(HttpStatus.OK)
            .then((response) => {
                expect(response.body.message).toHaveProperty('firstname', firstname);
                expect(response.body.message).toHaveProperty('lastnamename', lastname);
                done();
            });
    });

    it('Can run a second test', async () => {
        expect(true).toBe(true);
    });
});

The first test takes an average of 500ms to complete, while the second test takes more than 5000ms. Thus throwing the timeout exception.

I have tried changing the request call by using async / await, like so:

const res = await agent.post('/v1/auth/register')
    .send({ firstname, lastname });

However, this did not solve the issue. Further things I've tried are:

  • Passing a third argument to the it function,
  • Increasing the timeout using jest.setTimeout(10000),
  • Calling done with the async / await version,
  • Called .end() at the end of the request,
  • Add --runInBand --detectOpenHandles to the jest test command,
  • Removed the describe wrapper from the it functions.

None of the above seemed to help, what can I do solve this issue? And more importantly, why is this happening?

Sidenotes: the API is using Sequelize as ORM with a separate test database. The /register endpoint is not evoked twice (I've tested it by placing a console.log() in the original code).

1

1 Answers

0
votes

async, raw promises and done shouldn't be mixed together in tests, this results in error-prone code. Promises are often left unchained. done is often used carelessly, doesn't handle errors and results in test timeout if it's unreachable.

Since second test is a no-op and cannot timeout by itself, it's beforeEach to blame. If there's only one application instance, it's not expected to trigger serverStarted multiple times. The way how serverStarted works wasn't shown.

If the intention is to keep instances separately, it should be reinitialized for every test:

let app, agent;

beforeEach(() => {
    jest.resetModules();
    app = require('../../index.js');
    agent = request.agent(app);
});

beforeEach((done) => {
    app.on("serverStarted", () => {
        // probably needs to handle errors
        done();
    });
});