Introduction to Testing
Testing is like checking your work before submitting it. It catches mistakes before your users do. In React, testing ensures your components behave correctly as you add features and fix bugs.
Good tests act as documentation. They show exactly how your code is supposed to work. Future developers (including you) can read tests to understand the intended behavior.
Why Testing Matters
Without tests, every code change is a gamble. Did you break something? You will not know until a user complains. Tests give you confidence to refactor and add features without fear.
Tests also save time long-term. Yes, writing them takes effort upfront. But debugging a mysterious production issue at 2 AM takes far more. Invest now, save later.
Types of Tests
There are three main types of tests, each serving a different purpose. Think of them as layers of a pyramid.
// Unit test - tests one small piece in isolation
test('adds two numbers', () => {
expect(add(1, 2)).toBe(3)
})
// Integration test - tests how pieces work together
test('form submits user data', async () => {
render(<ContactForm />)
await userEvent.type(screen.getByLabelText('Name'), 'Alice')
await userEvent.click(screen.getByText('Submit'))
expect(mockSubmit).toHaveBeenCalledWith({ name: 'Alice' })
})
// End-to-end test - tests the whole user journey
test('user can sign up and see dashboard', async () => {
await page.goto('/signup')
await page.fill('#email', 'test@example.com')
await page.click('#signup-btn')
expect(await page.textContent('h1')).toBe('Dashboard')
})
Unit tests are fast and focused. Integration tests verify component interactions. End-to-end tests simulate real user behavior across your entire app.
Setting Up Testing
React Testing Library is the standard for testing React components. It focuses on testing behavior rather than implementation details. You test what users see and do, not internal state.
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import Greeting from './Greeting'
test('displays greeting with user name', () => {
render(<Greeting name="Alice" />)
expect(screen.getByText('Hello, Alice!')).toBeInTheDocument()
})
Notice how the test reads like English. Render the component, find the text, assert it exists. Testing Library encourages this readable style.
Try it Yourself →