Testing React
The three layers of testing in modern React applications: Unit (logic), Component (behavior), and End-to-End (user flows).
The Testing Pyramid
Testing ensures your code works and prevents regressions when you make changes. In React, we generally think about three layers:
**1. Unit Testing:** Testing pure functions in isolation (e.g., calculateTotal(items)). Fast and cheap. Usually done with **Vitest** or Jest.
**2. Component Testing:** Testing a single React component (e.g., <CheckoutForm />). We test how it behaves, not how it's written. Usually done with **React Testing Library**.
**3. End-to-End (E2E) Testing:** Spinning up a real browser and clicking through the app like a real user (e.g., adding an item to cart and checking out). Slow but highly confident. Done with **Playwright** or Cypress.
Testing Behavior, Not Implementation
Historically, developers tested React components by checking their internal state (e.g., expect(wrapper.state('isOpen')).toBe(true)).
This was fragile. If you refactored the component to use useReducer instead of useState, the test would break even if the UI worked perfectly.
**React Testing Library (RTL)** changed the paradigm. It forces you to test what the user sees: expect(screen.getByText('Hello')).toBeInTheDocument().
Writing an RTL Test
A typical component test follows the AAA pattern: Arrange, Act, Assert.
**Arrange:** render(<LoginForm />)
**Act:** fireEvent.change(screen.getByLabelText('Email'), { target: { value: 'test@test.com' } })
**Assert:** expect(screen.getByRole('button', { name: 'Submit' })).toBeEnabled()
The Automated Test Runner
Watch a simulated React Testing Library test run. The test runner executes the code on the left line-by-line, which automatically interacts with the rendered component on the right, verifying its behavior without a human.
render(<LoginForm/>);
const input = screen.getByLabelText('Email');
expect(screen.getByRole('button')).toBeEnabled();
Login
A visualization of a React Testing Library execution. The test runner interacts with the DOM exactly as a user would (finding inputs by their label, typing characters, and asserting button states).
Check yourself
Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.
Remember this
- Unit Tests (Vitest) are for pure functions.
- Component Tests (RTL) are for isolated UI behavior.
- E2E Tests (Playwright) are for full user flows in a real browser.
- React Testing Library forces you to test the DOM (what the user sees), not the implementation (how it's coded).
- Use MSW to cleanly mock API requests during component tests.
Done with this concept?
Mark it complete to track your progress. No login needed.