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.

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
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
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
Quick check
Why pass Supertest the app instead of a server you started yourself?
Go deeper
- 1Write a Supertest test that hits an endpoint and asserts on the status code and body.
- 2Test both a success case and a validation-error case for the same endpoint.
- 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.