npm install -D vitest supertest @types/supertest
sqlite3 for in-memory testing
Write integration tests using supertest to test the full HTTP request-response cycle.
1 import { describe, it, expect, beforeAll, afterAll } from 'vitest'; 2 import request from 'supertest'; 3 import express from 'express'; 4 5 // Simple in-memory store for testing 6 const users: Array<{ id: string; name: string; email: string }> = []; 7 8 const app = express(); 9 app.use(express.json()); 10 11 app.post('/users', (req, res) => { 12 const { name, email } = req.body; 13 if (!name || !email) { 14 return res.status(400).json({ error: 'name and email required' }); 15 } 16 if (users.find(u => u.email === email)) { 17 return res.status(409).json({ error: 'Email already exists' }); 18 } 19 const user = { id: crypto.randomUUID(), name, email }; 20 users.push(user); 21 return res.status(201).json(user); 22 }); 23 24 app.get('/users/:id', (req, res) => { 25 const user = users.find(u => u.id === req.params.id); 26 if (!user) return res.status(404).json({ error: 'Not found' }); 27 return res.json(user); 28 }); 29 30 beforeAll(() => { users.length = 0; }); // clean state 31 32 describe('POST /users', () => { 33 it('creates user and returns 201', async () => { 34 const res = await request(app) 35 .post('/users') 36 .send({ name: 'Alice', email: 'alice@test.com' }); 37 38 expect(res.status).toBe(201); 39 expect(res.body.id).toBeDefined(); 40 expect(res.body.email).toBe('alice@test.com'); 41 }); 42 43 it('returns 409 for duplicate email', async () => { 44 await request(app).post('/users').send({ name: 'Bob', email: 'dup@test.com' }); 45 const res = await request(app).post('/users').send({ name: 'Bob2', email: 'dup@test.com' }); 46 47 expect(res.status).toBe(409); 48 expect(res.body.error).toMatch(/already exists/i); 49 }); 50 51 it('returns 400 for missing fields', async () => { 52 const res = await request(app).post('/users').send({ name: 'NoEmail' }); 53 expect(res.status).toBe(400); 54 expect(res.body.error).toContain('required'); 55 }); 56 });
POST /users returns 201 with user; duplicate returns 409; missing fields return 400
Sign in to share your feedback and join the discussion.