What to Test
What to Test
Integration tests verify multiple units work together.
Integration vs Unit
| Aspect | Unit | Integration |
|---|---|---|
| Scope | Single function | Multiple components |
| Speed | Fast | Slower |
| Isolation | Fully isolated | Some dependencies |
| Confidence | Low | High |
What to Cover
- Component interactions
- API calls
- State management flows
- Form submissions
- Navigation
Testing Components Together
// Test components that work together
describe('ShoppingCart', () => {
it('should add item and update total', async () => {
render(
<CartProvider>
<ProductList />
<CartSummary />
</CartProvider>
);
// Add item
fireEvent.click(screen.getByText('Add to Cart'));
// Verify cart updates
expect(screen.getByText('1 item')).toBeInTheDocument();
expect(screen.getByText('$29.99')).toBeInTheDocument();
});
});
Testing Forms
describe('LoginForm', () => {
it('should submit form with valid data', async () => {
const onSubmit = jest.fn();
render(<LoginForm onSubmit={onSubmit} />);
fireEvent.change(screen.getByLabelText('Email'), {
target: { value: 'test@example.com' },
});
fireEvent.change(screen.getByLabelText('Password'), {
target: { value: 'password123' },
});
fireEvent.click(screen.getByText('Sign In'));
await waitFor(() => {
expect(onSubmit).toHaveBeenCalledWith({
email: 'test@example.com',
password: 'password123',
});
});
});
});
Testing API Calls
Testing API Calls
Mock API responses for reliable tests.
MSW (Mock Service Worker)
// src/mocks/handlers.js
import { rest } from 'msw';
export const handlers = [
rest.get('/api/users', (req, res, ctx) => {
return res(
ctx.json([
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
])
);
}),
rest.post('/api/users', async (req, res, ctx) => {
const body = await req.json();
return res(ctx.json({ id: 3, ...body }));
}),
];
// src/mocks/server.js
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);
Test Setup
// src/test/setup.js
import { server } from '../mocks/server';
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Component Test
describe('UserList', () => {
it('should display users', async () => {
render(<UserList />);
// Wait for data to load
await waitFor(() => {
expect(screen.getByText('John')).toBeInTheDocument();
expect(screen.getByText('Jane')).toBeInTheDocument();
});
});
it('should handle API error', async () => {
server.use(
rest.get('/api/users', (req, res, ctx) => {
return res(ctx.status(500));
})
);
render(<UserList />);
await waitFor(() => {
expect(screen.getByText('Error loading users')).toBeInTheDocument();
});
});
});
Fetch Mock
// Simple fetch mock
beforeEach(() => {
global.fetch = jest.fn();
});
afterEach(() => {
jest.restoreAllMocks();
});
it('should fetch data', async () => {
global.fetch.mockResolvedValueOnce({
ok: true,
json: async () => ({ data: 'test' }),
});
const data = await fetchData();
expect(data).toEqual({ data: 'test' });
expect(global.fetch).toHaveBeenCalledWith('/api/data');
});
Testing User Flows
Testing User Flows
Test complete user journeys through the application.
Multi-Step Form
describe('Checkout Flow', () => {
it('should complete checkout', async () => {
render(<CheckoutPage />);
// Step 1: Shipping
fireEvent.change(screen.getByLabelText('Name'), {
target: { value: 'John Doe' },
});
fireEvent.change(screen.getByLabelText('Address'), {
target: { value: '123 Main St' },
});
fireEvent.click(screen.getByText('Continue'));
// Step 2: Payment
await waitFor(() => {
expect(screen.getByText('Payment')).toBeInTheDocument();
});
fireEvent.change(screen.getByLabelText('Card Number'), {
target: { value: '4242424242424242' },
});
fireEvent.click(screen.getByText('Place Order'));
// Step 3: Confirmation
await waitFor(() => {
expect(screen.getByText('Order Confirmed')).toBeInTheDocument();
});
});
});
Navigation Flow
describe('Navigation', () => {
it('should navigate through pages', async () => {
render(
<MemoryRouter>
<App />
</MemoryRouter>
);
// Start at home
expect(screen.getByText('Home')).toBeInTheDocument();
// Navigate to products
fireEvent.click(screen.getByText('Products'));
await waitFor(() => {
expect(screen.getByText('Product List')).toBeInTheDocument();
});
// Navigate to product detail
fireEvent.click(screen.getByText('Product 1'));
await waitFor(() => {
expect(screen.getByText('Product 1 Details')).toBeInTheDocument();
});
});
});
Search Flow
describe('Search', () => {
it('should search and filter results', async () => {
render(<SearchPage />);
// Type search query
fireEvent.change(screen.getByLabelText('Search'), {
target: { value: 'laptop' },
});
// Wait for results
await waitFor(() => {
expect(screen.getByText('Laptop Pro')).toBeInTheDocument();
});
// Apply filter
fireEvent.click(screen.getByText('Price: Low to High'));
// Verify sorted results
await waitFor(() => {
const prices = screen.getAllByText(/\\$\\d+/);
const priceValues = prices.map(el =>
parseInt(el.textContent.replace('$', ''))
);
expect(priceValues).toEqual([...priceValues].sort((a, b) => a - b));
});
});
});
Practice Problems
Create a reusable React component implementing Integration Testing. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for Integration Testing using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize Integration Testing for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. What is the difference between unit and integration tests?
2. What is MSW?
3. What is the primary purpose of Integration Testing?
4. What is a common mistake when implementing Integration Testing?
Flashcards
Question
What is integration testing?
Click to reveal answer
Answer
Testing multiple components working together, including API calls and user interactions.
Question
What is MSW?
Click to reveal answer
Answer
Mock Service Worker - intercepts API requests for realistic testing.
Question
What should integration tests cover?
Click to reveal answer
Answer
Component interactions, API calls, form submissions, and user flows.
Question
How do you test async operations?
Click to reveal answer
Answer
Use waitFor() to wait for async operations to complete.
Question
What is Integration Testing?
Click to reveal answer
Answer
Integration Testing is a key concept in frontend development.
Revision Notes
Key Takeaways
- 1.Integration tests verify multiple components working together
- 2.MSW provides realistic API mocking
- 3.Test complete user flows through the application
- 4.Use waitFor for async operations
- 5.Integration tests give higher confidence than unit tests
Interview Tips
- •Explain the difference between unit and integration tests
- •Discuss how to mock API calls for testing
- •Know how to test user flows
Cheat Sheet
Integration Testing Cheat Sheet
What to Test
- Component interactions
- API calls
- Form submissions
- User flows
- Navigation
MSW Setup
const server = setupServer(...handlers);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Common Patterns
- waitFor() for async
- fireEvent for events
- screen queries for elements