0

I'm experiencing a persistent timeout issue with my Jest tests for an Express.js application using MongoDB Memory Server. The test appears to be successful (receiving a 200 status code) but Jest times out before completing, showing the error

"Cannot log after tests are done. Did you forget to wait for something async in your test?"

Here's the specific error output:

FAIL tests/post.controller.test.ts (14.057 s) ● Console console.log Starting ... at tests/post.controller.test.ts:6:13

● Post Controller › GET /posts should return a list of posts thrown: "Exceeded timeout of 10000 ms for a test. Add a timeout value to this test to increase the timeout, if this is a long-running test."

● Cannot log after tests are done. Did you forget to wait for something async in your test? Attempted to log "Awaiting ..: 200". The test is making a request to /posts endpoint which connects to MongoDB, but Jest detects an open handle (TCPSERVERWRAP) that prevents it from exiting cleanly.

My Setup Test file (tests/post.controller.test.ts): typescript

import request from 'supertest';
import app from '../src/app';

describe("Post Controller", () => {
  it("GET /posts should return a list of posts", async () => {
    console.log("Starting ...");
    const response = await request(app).get("/posts");
    console.log("Awaiting ..:", response.status);
    expect(response.status).toBe(200);
    expect(Array.isArray(response.body)).toBe(true);
  }, 10000);
});

Jest config (jest.config.js): javascript

export default {
  preset: "ts-jest",
  testEnvironment: "node",
  setupFiles: ["dotenv/config"],
  collectCoverage: true,
  coverageReporters: ["text", "html"],
  coverageDirectory: "<rootDir>/coverage/",
  setupFilesAfterEnv: ["<rootDir>/tests/setup.ts"],
  forceExit: true,
  detectOpenHandles: true,
};

Database setup (tests/db.ts): typescript

import mongoose from "mongoose";
import { MongoMemoryServer } from "mongodb-memory-server";

let mongod: MongoMemoryServer;

export const connect = async () => {
  if (mongoose.connection.readyState !== 0) {
    await mongoose.disconnect();
  }
  mongod = await MongoMemoryServer.create();
  const uri = mongod.getUri();
  await mongoose.connect(uri);
};

export const closeDatabase = async () => {
  if (mongoose.connection.readyState !== 0) {
    await mongoose.connection.dropDatabase();
    await mongoose.connection.close();
  }
  if (mongod) {
    await mongod.stop();
  }
};

Express app (src/app.ts): typescript

import express, { Express } from "express";
import router from "./routes/routes";

const app: Express = express();
app.use(express.json());
app.use("/", router);

export default app;

What I tried:

Increased the test timeout from 5000ms to 10000ms Added forceExit: true and detectOpenHandles: true to Jest config Added console.log statements to track test execution Created a database helper with MongoDB Memory Server for testing

What I expected:

The test should complete successfully within the timeout period Jest should exit cleanly without detecting open handles The database connection should be properly managed during testing

What actually happened:

The test receives a 200 response (visible in logs) but still times out Jest shows "Cannot log after tests are done" error An open TCPSERVERWRAP handle is detected, preventing clean exit The MongoDB Memory Server connection setup in tests/db.ts doesn't seem to be properly integrated with the test lifecycle

Questions

  1. How can I properly integrate MongoDB Memory Server with Jest test lifecycle?
  2. Why is the test timing out even though it appears to complete successfully?
  3. How do I ensure the database connection is properly closed after tests to avoid the open handle issue?
  4. Is there a better pattern for testing Express apps with MongoDB using Jest?

Environment

  • Node.js version: Latest
  • Jest version: Latest
  • MongoDB Memory Server
  • Express.js
  • TypeScript
  • Supertest for HTTP testing

1 Answer 1

0

The main issues are:

  • Database setup not integrated with test lifecycle
  • Your tests/db.ts file contains MongoDB Memory Server setup, but it's not being used in your tests
  • Open database connections
  • The MongoDB connection remains open after tests, preventing Jest from exiting
  • Missing test setup
  • No proper beforeAll/afterAll hooks to manage database lifecycle

Solution

  1. Fix your tests/setup.ts file typescript
import { connect, closeDatabase, clearDatabase } from './db';

// Setup before all tests
beforeAll(async () => {
  await connect();
});

// Cleanup after each test
afterEach(async () => {
  await clearDatabase();
});

// Cleanup after all tests
afterAll(async () => {
  await closeDatabase();
});
// Increase timeout for all tests
jest.setTimeout(30000);

  1. Update your Jest config javascript
export default {
  preset: "ts-jest",
  testEnvironment: "node",
  setupFiles: ["dotenv/config"],
  collectCoverage: true,
  coverageReporters: ["text", "html"],
  coverageDirectory: "<rootDir>/coverage/",
  setupFilesAfterEnv: ["<rootDir>/tests/setup.ts"],
  forceExit: true,
  detectOpenHandles: true,
  testTimeout: 30000, // Global timeout
};
  1. Simplify your test file typescript
import request from 'supertest';
import app from '../src/app';

describe("Post Controller", () => {
  it("GET /posts should return a list of posts", async () => {
    const response = await request(app).get("/posts");
    expect(response.status).toBe(200);
    expect(Array.isArray(response.body)).toBe(true);
  });
});
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.