18. Unit Testing with React Testing Library and Jest
Level: IntermediateDuration: 30m
Why Write Tests?
Testing helps prevent bugs, improves confidence when refactoring code, and ensures your components behave as expected. In React, we use Jest for testing logic and React Testing Library for testing UI behavior.
- Catch bugs early
- Prevent broken features
- Improve confidence when changing code
- Document expected behavior
Setting Up Jest and React Testing Library
bash
npm install --save-dev jest @testing-library/react @testing-library/jest-domReact projects created with Vite also need a test environment setup like Vitest, but Jest remains the most widely used testing framework for React.
Writing Your First Test
jsx
// Button.jsx
export default function Button({ label }) {
return <button>{label}</button>
}jsx
// Button.test.jsx
import { render, screen } from '@testing-library/react'
import Button from './Button'
test('renders button with label', () => {
render(<Button label="Click Me" />)
const buttonElement = screen.getByText(/Click Me/i)
expect(buttonElement).toBeInTheDocument()
})Testing User Interaction
jsx
// Counter.jsx
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
)
}jsx
// Counter.test.jsx
import { render, screen, fireEvent } from '@testing-library/react'
import Counter from './Counter'
test('increments counter on click', () => {
render(<Counter />)
const button = screen.getByText(/Increase/i)
fireEvent.click(button)
expect(screen.getByText(/Count: 1/i)).toBeInTheDocument()
})Jest Matchers
- `toBeInTheDocument()` — element exists
- `toHaveTextContent()` — check text inside element
- `toBeDisabled()` — check disabled button state
- `toContainElement()` — contains another element
Mini Project Step
Write a test for your FeatureList component to check that it renders a list of features correctly. Then, add a test to check that adding a new feature updates the list.