Testing with Supertest in expressjs

advance · Express.js — Web APIs & middleware

Supertest is a high-level abstraction library for testing HTTP servers in Node.js. It allows you to simulate requests to your Express application without actually starting a network server, making it fast, reliable, and essential for Integration Testing . 1. The Theory: Why Integration Testing? Theory: While Unit Tests check individual functions (like a Service or a Model), Integration Tests verify that the entire "stack" works together. The Chain: It ensures that a request passes through the Route , triggers the Middleware (like validation or auth), reaches the Controller , and interacts with the Service correctly. Response Validation: You aren't just checking if a function returns data; you are checking if the server returns the correct HTTP Status Code , Headers , and JSON Structure . 2. Setting Up Supertest Theory: Supertest works best when your Express app is defined in one file but the server is "started" ( app.listen() ) in another. This allows the test runner to take control of the app instance without binding to a real port. // app.test.js const request = require('supertest'); const app = require('../app'); // Import your Express instance describe('GET /api/users', () => {   it('should return all users and a 200 status', async () => {     const response = await request(app).get('/api/users');          expect(response.statusCode).toBe(200);     expect(response.body).toBeInstanceOf(Array);     expect(response.headers['content-type']).toMatch(/json/);   }); }); 3. Testing Protected Routes and Payloads Theory: Supertest allows you to simulate complex scenarios, such as sending headers for authentication or passing JSON bodies for POST requests. Testing POST with Validation it('should fail if email is missing (Validation Check)', async () => {   const res = await request(app)     .post('/api/register')     .send({ name: 'Tharun' }); // Missing email   expect(res.statusCode).toBe(400);   expect(res.body.message).toContain('email'); }); Testing Auth Headers it('should return 401 if no token is provided', async () => {   const res = await request(app)     .get('/api/profile')     .set('Authorization', 'Bearer invalid-token');   expect(res.statusCode).toBe(401); }); 4. Best Practices: Mocking and Databases Theory: To keep tests fast and predictable, you should avoid hitting your production database during integration tests. Test Database: Use a separate "Test" database (e.g., a local MongoDB instance or an in-memory DB) that is wiped clean before each test run. Mocking Services: If a route triggers an expensive operation (like sending an email or an external API call), you can "mock" that specific service while still testing the rest of the Express flow.

Back to Express.js — Web APIs & middleware

Browse all study material on Careeroza