Script Valley
Node.js: The Complete Runtime
Databases, Testing, and DeploymentLesson 6.3

Integration testing Express APIs with Supertest

supertest setup, testing routes without starting a server, status code assertions, body assertions, authentication in tests, beforeAll/afterAll, test isolation

Test the Full HTTP Layer Without a Running Server

Supertest makes HTTP calls directly to your Express app in-process — no need to run a server on a port. This makes tests fast and isolated.

npm install supertest --save-dev
// app.js — export app without calling listen
const express = require('express');
const app = express();
app.use(express.json());
app.get('/api/health', (req, res) => res.json({ status: 'ok' }));
app.post('/api/users', (req, res) => {
  if (!req.body.name) return res.status(400).json({ error: 'Name required' });
  res.status(201).json({ id: 1, ...req.body });
});
module.exports = app;
// app.test.js
const request = require('supertest');
const app = require('./app');

describe('GET /api/health', () => {
  it('returns 200 with status ok', async () => {
    const res = await request(app).get('/api/health');
    expect(res.status).toBe(200);
    expect(res.body.status).toBe('ok');
  });
});

describe('POST /api/users', () => {
  it('creates a user with valid data', async () => {
    const res = await request(app)
      .post('/api/users')
      .send({ name: 'Alice', email: 'alice@test.com' });
    expect(res.status).toBe(201);
    expect(res.body).toMatchObject({ name: 'Alice' });
  });

  it('returns 400 when name is missing', async () => {
    const res = await request(app).post('/api/users').send({});
    expect(res.status).toBe(400);
  });
});

Up next

Logging and monitoring Node.js applications in production

Sign in to track progress