Stop 12 · TestingTopics · 5/9

Supertest

Part of the Backend Developer Roadmap

In short

You've built an Express API. Supertest lets your tests fire real HTTP requests at it, without starting a server on a fixed port or opening Postman.

A library for testing HTTP endpoints directly — spins up your Express app and lets you make real requests against it in your test suite, asserting on status codes and response bodies.

The blob character tastes food at a counter while ticking a clipboard.

Think of it like this

The mystery shopper

A restaurant chain sends a mystery shopper who orders like any customer, tastes the food and ticks a checklist. No kitchen tour, just the real experience. Supertest is your API's mystery shopper: it sends real requests and checks the status, headers and body.

Watch it happen

Testing POST /auth/login

Test
Express app

request(app)

1/5Supertest takes your app and binds it to a temporary port behind the scenes.

The big ideas

What you need to know

No listen() needed

Pass the app object, not a running server. Export app from one file and call listen in another.

Chain expectations

.expect(200) and .expect("Content-Type", /json/) read neatly and fail with clear messages.

Agents keep cookies

request.agent(app) remembers cookies between calls, which is handy for testing session logins.

Pairs with any runner

Works with Jest, Vitest, Mocha or node:test. It only handles the HTTP part.

See it in code

Walk through the code

ts
1import request from "supertest";2import { app } from "../src/app";3 4describe("POST /auth/login", () => {5  test("returns a token for good credentials", async () => {6    const res = await request(app)7      .post("/auth/login")8      .send({ email: "riya@test.dev", password: "chai@123" })9      .expect(200)10      .expect("Content-Type", /json/);11    expect(typeof res.body.token).toBe("string");12  });13  test("rejects a wrong password", async () => {14    await request(app).post("/auth/login").send({ email: "riya@test.dev", password: "nope" }).expect(401);15  });16});

1/4Hand Supertest the app and send a POST with a JSON body.

Jest globals are used here. The test user would be seeded into a test database before the suite runs.

Save yourself the pain

Common mistakes

Oops

Calling app.listen(3000) inside app.ts, so tests fight over the port.

Do this instead

Export app from app.ts and call listen only in server.ts. Supertest handles ports itself.

Oops

Only testing the happy path.

Do this instead

Add tests for 400, 401 and 404 too. That's where real bugs and security holes hide.

Your mission

Test your auth routes

~30 min

Quick check

Why pass Supertest the app instead of a server you started yourself?

Go deeper

  1. 1Write a Supertest test that hits an endpoint and asserts on the status code and body.
  2. 2Test both a success case and a validation-error case for the same endpoint.
  3. 3Combine Supertest with a test database to write true integration tests.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge