Unit tests check the pieces one at a time. Cool. So what happens when those pieces have to actually work together? That's the job of integration tests. They check that your components, APIs and databases play nice as a team.
Think about an orchestra. Every musician might sound PERFECT practicing alone in their bedroom. The real test is whether they sound any good together on stage, and integration testing is that test for your code.
Remember those 49 form notifications from the first lesson? The form submitted fine and the email system swore it delivered. Each piece looked healthy on its own, and the whole thing still failed where the pieces met. That's the flavor of problem integration tests exist for (even if nobody's test was ever gonna catch a surprise Microsoft update).
What Makes a Test an Integration Test?
An integration test checks how two or more parts of your system get along. Stuff like this.
A component that fetches data from an API
An API endpoint that reads from a database
A form that submits data and updates the UI
A service that calls another service
Example
import { describe, it, expect } from 'vitest';
// Your dev server needs to be running for this one
const BASE_URL = 'http://localhost:3000';
// Integration test: API endpoint + database
describe('POST /api/users', () => {
it('should create a user and return it', async () => {
const response = await fetch(`${BASE_URL}/api/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
});
const user = await response.json();
expect(response.status).toBe(201);
expect(user.name).toBe('Alice');
expect(user.id).toBeDefined();
});
});
Testing API Endpoints
For Next.js or Express APIs, you can test endpoints directly with tools like supertest or plain old fetch calls. One gotcha with fetch in a test file. Your tests run in Node, not a browser, so there's no page address to fill in the blanks. Give it the full URL (like http://localhost:3000/api/tasks) or it throws a "Failed to parse URL" error before your API ever gets a say.
Integration tests check that multiple parts work together the right way
Test your API endpoints with realistic requests and responses
Use fixtures so every test starts from the same data
Always clean up test data so tests don't trip over each other
Test the error cases too, like 404s, 400s, 401s and server errors
Use a separate test database to keep your development data safe
What's Next?
You can test single functions and you can test how the pieces fit together. Next up is testing React components, where clicks, typing and rendering bring a few new wrinkles to the party...