Testing an Express application means testing HTTP behavior: status codes, response bodies, and headers. This lesson covers combining Jest with Supertest to test Express routes without starting a real server on a real port.
Testing Routes with Supertest
Supertest wraps your Express app object directly, letting you make simulated HTTP requests against it in-process, without binding to an actual network port. This keeps route tests fast and avoids port conflicts in CI.
You export the Express app (without calling .listen() in the testable module) so both your real server entry point and your tests can import and use the same app instance.
.send(body) attaches a JSON (or form) request body to POST/PUT/PATCH requests.
.set(header, value) sets custom request headers, like Authorization.
response.body is automatically parsed JSON when the response's content type is JSON.
Chain .expect(statusCode) directly for a shorthand status assertion, if preferred over response.status.
Jest + Express Cheat Sheet
Common Supertest patterns for testing Express apps.
Goal
Pattern
GET request
await request(app).get('/path')
POST with a body
request(app).post('/path').send({...})
Set a header
.set('Authorization', 'Bearer token')
Assert status code
expect(response.status).toBe(200)
Assert JSON body
expect(response.body).toEqual({...})
Chainable status assertion
.expect(201)
Testing Middleware in Isolation
Middleware functions take (req, res, next). You can test simple middleware directly by calling it with mock req/res objects and a jest.fn() for next, without needing a full Express app or Supertest at all.
Test both the success and failure paths of every route — an invalid input should return the correct status code (usually 400) and a helpful error message, and unexpected server errors should return a 500 without leaking internal details.
Calling app.listen() inside the module used by tests, causing port conflicts across test files.
Testing only the happy path and skipping validation/error-handling routes entirely.
Testing middleware only through full HTTP requests when a direct unit test would be simpler.
Forgetting await before Supertest requests, since they return promises.
Key Takeaways
Supertest makes in-process HTTP requests against an Express app without a real network port.
Export your Express app separately from the code that calls .listen().
Middleware can be unit tested directly with mock req/res/next objects.
Always test both success and error-handling paths for every route.
Pro Tip
Structure your Express project so app.js exports the configured app and a separate server.js calls app.listen(). This single separation is what makes clean, port-free Supertest testing possible.
You now know how to test Express.js applications. Next, explore broader API testing strategies beyond a single framework.