React Testing Library & Vitest

0/2 in this phase0/36 across the roadmap

📖 Concept

Testing in React has shifted from testing implementation details (like state or internal methods) to testing User Behavior. React Testing Library (RTL) is designed to help you test components as a user would.

Vitest: The test runner (replacement for Jest). It is blazingly fast and shares the same configuration as Vite.

The RTL Philosophy: Instead of checking wrapper.state('count'), you check screen.getByText(/count: 1/i). If your test passes when you refactor the internal code but keep the UI behavior the same, you've written a good test.

Common Queries:

  • getBy...: Fails if element not found. Use for things that should be there.
  • queryBy...: Returns null if not found. Use for asserting something is not there.
  • findBy...: Returns a promise. Use for async elements (like data from an API).

💻 Code Example

codeTap to expand ⛶
1// Counter.test.tsx
2import { render, screen, fireEvent } from '@testing-library/react';
3import { expect, test } from 'vitest';
4import Counter from './Counter';
5
6test('increments counter when button is clicked', () => {
7 // 1. Render the component
8 render(<Counter />);
9
10 // 2. Find elements (prefer user-centric queries)
11 const button = screen.getByRole('button', { name: /increment/i });
12 const countDisplay = screen.getByText(/current count: 0/i);
13
14 // 3. Interact with the UI
15 fireEvent.click(button);
16
17 // 4. Assert the change
18 expect(screen.getByText(/current count: 1/i)).toBeInTheDocument();
19});
20
21test('starts with a custom initial value', () => {
22 render(<Counter initialValue={10} />);
23 expect(screen.getByText(/current count: 10/i)).toBeInTheDocument();
24});

🏋️ Practice Exercise

  1. Write tests for a 'LoginForm' component. Check that error messages appear when inputs are empty.
  2. Build a 'Toggle' component and test that its label changes when clicked.
  3. Use user-event instead of fireEvent to simulate more realistic user interactions (like typing).
  4. Research 'Snapshots' and discuss why they are often considered a 'lazy' testing pattern.

⚠️ Common Mistakes

  • Testing implementation details (like component state) instead of the UI.

  • Using container.querySelector instead of RTL's built-in queries (which are more accessible).

  • Not cleaning up tests (RTL does this automatically, but some setups might need manual cleanup).

  • Writing tests that are too specific and break on every minor CSS change.

💼 Interview Questions

🎤 Mock Interview

Practice a live interview for React Testing Library & Vitest