How do you integration-test an Express API (e.g., with supertest)?

3 minintermediatenodejsexpresssupertestintegration-testingapi

Quick Answer

Use supertest to send real HTTP requests to your Express app object (no need to bind a port) and assert on status, headers, and body. Run middleware, routing, and handlers together against a test database so you verify the actual request/response path end-to-end within the service.

Detailed Answer

Answer: Integration tests exercise the real request pipeline — middleware, routing, handlers, and (ideally) a test database — through HTTP. supertest drives your Express app directly.

Export the app separately from the server so tests can import it without listening on a port:

// app.js — build and export the app
const app = express();
app.use(express.json());
app.use('/users', usersRouter);
module.exports = app;

// server.js — only this file calls listen()
require('./app').listen(3000);

Test with supertest:

const request = require('supertest');
const app = require('./app');

describe('POST /users', () => {
  test('creates a user and returns 201', async () => {
    const res = await request(app)
      .post('/users')
      .send({ name: 'Alice', email: 'alice@x.com' })
      .expect('Content-Type', /json/)
      .expect(201);

    expect(res.body).toMatchObject({ name: 'Alice' });
    expect(res.body.id).toBeDefined();
  });

  test('rejects invalid input with 400', async () => {
    await request(app).post('/users').send({}).expect(400);
  });
});

Good practices:

  • Use a dedicated test database (or an in-memory/containerized one), reset between tests (beforeEach truncate, or wrap each test in a rolled-back transaction).
  • Test the contract: status codes, response shape, validation errors, auth (send/omit tokens), and edge cases — not just the happy path.
  • Mock only truly external third parties (payment gateways, email); keep your own DB real so you catch query/serialization bugs.
  • supertest calls app in-process (it starts an ephemeral server), so no port management or flakiness from a separately running server.