Integration Testing
Testing multiple components together
Challenge
Section titled “Challenge”Test API endpoints, database interactions, and component integration without mocking.
Explanation
Section titled “Explanation”Integration tests verify that multiple components work together correctly in a realistic environment.
Supertest for API Testing
Section titled “Supertest for API Testing”npm install --save-dev supertestconst request = require('supertest');const app = require('../app');
describe('GET /users', () => { test('returns all users', async () => { const response = await request(app) .get('/users') .expect('Content-Type', /json/) .expect(200);
expect(response.body).toHaveProperty('users'); expect(Array.isArray(response.body.users)).toBe(true); });
test('returns user by ID', async () => { const response = await request(app) .get('/users/1') .expect(200);
expect(response.body).toHaveProperty('id', 1); });
test('returns 404 for non-existent user', async () => { await request(app) .get('/users/999') .expect(404); });});
describe('POST /users', () => { test('creates new user', async () => { const response = await request(app) .post('/users') .send({ name: 'John', email: 'john@example.com' }) .expect(201);
expect(response.body).toHaveProperty('id'); expect(response.body.name).toBe('John'); });
test('validates input', async () => { await request(app) .post('/users') .send({ name: 'John' }) .expect(400); });});Database Integration
Section titled “Database Integration”describe('User Database', () => { let db;
beforeAll(async () => { db = await connectToTestDatabase(); });
afterEach(async () => { await db.clear('users'); });
afterAll(async () => { await db.disconnect(); });
test('creates user in database', async () => { const user = await User.create({ name: 'John', email: 'john@example.com' });
const found = await User.findById(user.id); expect(found.email).toBe('john@example.com'); });
test('updates user', async () => { const user = await User.create({ name: 'John' }); await user.update({ name: 'Jane' });
const updated = await User.findById(user.id); expect(updated.name).toBe('Jane'); });});Test Fixtures
Section titled “Test Fixtures”async function createTestUser(overrides = {}) { return User.create({ name: 'Test User', email: 'test@example.com', ...overrides });}
async function seedDatabase() { await User.create({ name: 'User 1', email: 'user1@example.com' }); await User.create({ name: 'User 2', email: 'user2@example.com' }); return User.findAll();}
describe('User endpoints', () => { beforeEach(async () => { await seedDatabase(); });
test('lists users', async () => { const response = await request(app).get('/users'); expect(response.body.users).toHaveLength(2); });});Snapshot Testing
Section titled “Snapshot Testing”test('API response structure', async () => { const response = await request(app).get('/users/1');
expect(response.body).toMatchSnapshot({ id: expect.any(Number), created: expect.any(String) });});Performance Testing
Section titled “Performance Testing”describe('Performance', () => { test('returns users within 100ms', async () => { const start = Date.now();
await request(app) .get('/users') .expect(200);
const duration = Date.now() - start; expect(duration).toBeLessThan(100); });});Best Practices
Section titled “Best Practices”// 1. Use test databaseprocess.env.NODE_ENV = 'test';process.env.DATABASE_URL = 'postgresql://localhost/test_db';
// 2. Clear data between testsafterEach(async () => { await db.clear();});
// 3. Test both success and failuretest('handles errors', async () => { await request(app) .post('/users') .send({}) .expect(400);});
// 4. Test side effectstest('sends email on user creation', async () => { const sendEmailMock = jest.fn();
await request(app) .post('/users') .send({ name: 'John', email: 'john@example.com' }) .expect(201);
expect(sendEmailMock).toHaveBeenCalled();});