patterntypescriptTip
API testing with Supertest: test Express handlers without binding to a port
Viewed 0 times
supertestexpress testingapi testinghttp integrationmiddleware testing
Problem
Testing Express routes by starting the server on a real port creates port conflicts in parallel test runs, requires teardown, and introduces flakiness when the port is in use. Mocking the HTTP layer loses route, middleware, and error handler coverage.
Solution
Use
supertest to call Express app handlers directly without binding to a port. supertest(app).get('/users').expect(200) passes the request through the full Express middleware stack and returns a promise that resolves to the response.Why
Supertest uses Node's
http.createServer internally and binds to a random ephemeral port per request. No port management is needed. All middleware, validation, auth, and error handlers run, giving full coverage of the HTTP layer.Gotchas
- Supertest does not start the server permanently — do not use it for WebSocket tests or keep-alive scenarios
- Database calls in handlers hit the real DB unless mocked; use testcontainers or a test database for integration tests
- JWT or session cookies must be passed in the Authorization header or as a cookie using
.set()or.agent() - Supertest agent (
supertest.agent(app)) maintains cookies between requests, useful for session-based auth flows
Code Snippets
Supertest with JWT authentication
import request from 'supertest';
import app from '../app';
it('returns 401 when unauthenticated', async () => {
await request(app).get('/api/profile').expect(401);
});
it('returns user profile when authenticated', async () => {
const token = generateTestToken({ userId: 1 });
const res = await request(app)
.get('/api/profile')
.set('Authorization', `Bearer ${token}`)
.expect(200);
expect(res.body.userId).toBe(1);
});Revisions (0)
No revisions yet.