React Testing Basics
React Testing Basics
Testing React applications ensures that your UI behaves as expected, prevents regressions when you add new features, and serves as living documentation for how your components are supposed to work.
The Testing Stack
In the React ecosystem, testing usually involves a combination of three types of tools:
-
Test Runner / Assertion Library: (e.g., Jest, Vitest)
These tools execute your test files, provide functions to structure your tests (describe,it,test), and provide assertions to verify outcomes (expect(x).toBe(y)). -
DOM Environment Simulator: (e.g., JSDOM)
React components render to a DOM. Because Node.js doesn’t have a DOM (nowindowordocument), tools like JSDOM simulate a browser environment entirely in JavaScript so your tests can run quickly in the terminal without launching a real browser like Chrome. -
React Testing Utilities: (e.g., React Testing Library)
These libraries provide specific functions to render React components into the simulated DOM, interact with them (click buttons, type text), and query the resulting output.
A Basic Test Example
Let’s look at a basic test for a <Button /> component using Vitest and React Testing Library.
// Button.jsx
export function Button({ label, onClick }) {
return <button onClick={onClick}>{label}</button>;
}
// Button.test.jsx
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import { Button } from './Button';
// 'describe' groups related tests together
describe('Button Component', () => {
// 'it' or 'test' defines a single test case
it('renders the correct label', () => {
// 1. Render the component into the simulated DOM
render(<Button label="Click Me" />);
// 2. Query the DOM for an element containing the text
const buttonElement = screen.getByText('Click Me');
// 3. Assert that it exists
expect(buttonElement).toBeInTheDocument();
});
it('calls the onClick handler when clicked', () => {
// Create a "spy" function to track if it was called
const handleClick = vi.fn();
render(<Button label="Submit" onClick={handleClick} />);
// Simulate a user clicking the button
fireEvent.click(screen.getByText('Submit'));
// Assert that our spy function was triggered exactly once
expect(handleClick).toHaveBeenCalledTimes(1);
});
});
The Arrange, Act, Assert (AAA) Pattern
Almost all good tests follow the AAA pattern, which makes them easy to read:
- Arrange: Set up the initial state, create mocks, and render the component.
- Act: Perform an action on the component (e.g., click a button, type in an input).
- Assert: Verify that the component’s state or the DOM output matches your expectations.
Interview Questions
Q: What is the standard “AAA” pattern in testing?
A:
- Arrange: Set up the test data, mock APIs, and render the components into the virtual DOM.
- Act: Simulate user interactions (like clicking buttons or typing into inputs).
- Assert: Verify that the UI updated correctly or that the expected functions were called.