Integration Testing
Learn integration testing strategies to test how multiple components work together and interact with external systems. This is a foundational concept in component-based UI development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world React experience. Take your time with each section and practice the examples
Integration Testing Concepts
Integration testing verifies that different parts of your application work together correctly, including components, APIs, and external services.. This is an essential concept that every React developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Testing Component Integration
// Testing component integration
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
const renderWithRouter = (component) => {
return render(
<BrowserRouter>
{component}
</BrowserRouter>
);
};
test('complete user flow', async () => {
renderWithRouter(<App />);
// Navigate to login
fireEvent.click(screen.getByText('Login'));
// Fill login form
fireEvent.change(screen.getByLabelText(/email/i), {
target: { value: 'test@example.com' }
});
fireEvent.change(screen.getByLabelText(/password/i), {
target: { value: 'password123' }
});
// Submit form
fireEvent.click(screen.getByRole('button', { name: /login/i }));
// Verify navigation to dashboard
await waitFor(() => {
expect(screen.getByText('Dashboard')).toBeInTheDocument();
});
});API Integration Testing
// Testing API integration
import { render, screen, waitFor } from '@testing-library/react';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import UserList from './UserList';
const server = setupServer(
rest.get('/api/users', (req, res, ctx) => {
return res(ctx.json([
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Smith' }
]));
})
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
test('fetches and displays users', async () => {
render(<UserList />);
await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('Jane Smith')).toBeInTheDocument();
});
});Testing with Mock Service Worker
// MSW setup for API mocking
import { rest } from 'msw';
import { setupServer } from 'msw/node';
const handlers = [
rest.get('/api/users', (req, res, ctx) => {
return res(ctx.json({ users: [] }));
}),
rest.post('/api/users', (req, res, ctx) => {
return res(ctx.json({ id: 1, ...req.body }));
})
];
export const server = setupServer(...handlers);Testing Error Scenarios
// Testing error handling
test('handles API errors gracefully', async () => {
server.use(
rest.get('/api/users', (req, res, ctx) => {
return res(ctx.status(500), ctx.json({ error: 'Server error' }));
})
);
render(<UserList />);
await waitFor(() => {
expect(screen.getByText('Error loading users')).toBeInTheDocument();
});
});Mini-Project: Complete App Testing
// Complete integration test suite
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { BrowserRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from 'react-query';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import App from './App';
const server = setupServer(
rest.get('/api/users', (req, res, ctx) => {
return res(ctx.json([
{ id: 1, name: 'John Doe', email: 'john@example.com' }
]));
}),
rest.post('/api/users', (req, res, ctx) => {
return res(ctx.json({ id: 2, ...req.body }));
})
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
const renderApp = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false }
}
});
return render(
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<App />
</BrowserRouter>
</QueryClientProvider>
);
};
describe('App Integration Tests', () => {
test('complete user management flow', async () => {
const user = userEvent.setup();
renderApp();
// Navigate to users page
await user.click(screen.getByText('Users'));
// Wait for users to load
await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
});
// Add new user
await user.click(screen.getByRole('button', { name: /add user/i }));
await user.type(screen.getByLabelText(/name/i), 'Jane Smith');
await user.type(screen.getByLabelText(/email/i), 'jane@example.com');
await user.click(screen.getByRole('button', { name: /save/i }));
// Verify new user appears
await waitFor(() => {
expect(screen.getByText('Jane Smith')).toBeInTheDocument();
});
});
});