React Testing Library Patterns That Actually Work

React Testing Library encourages testing behavior over implementation. But without good patterns, tests become brittle and hard to maintain. Here are the patterns I have found most effective.
Test What Users See, Not Implementation
Query elements the way users find them — by role, label, and text content:
// Bad: testing implementation details
const button = container.querySelector(".submit-btn");
// Good: testing what users see
const button = screen.getByRole("button", { name: /submit/i });
const input = screen.getByLabelText(/email address/i);
const heading = screen.getByRole("heading", { name: /contact us/i });
The Arrange-Act-Assert Pattern
Every test follows the same structure:
test("shows error when email is invalid", async () => {
// Arrange: render component
render(<ContactForm />);
// Act: simulate user behavior
await userEvent.type(screen.getByLabelText(/email/i), "not-an-email");
await userEvent.click(screen.getByRole("button", { name: /submit/i }));
// Assert: verify the outcome
expect(screen.getByText(/please enter a valid email/i)).toBeInTheDocument();
});
Mock External Dependencies, Not Components
Mock API calls and browser APIs, but render real components:
// Mock the API, not the component
vi.mock("../lib/api", () => ({
fetchProjects: vi.fn().mockResolvedValue([
{ id: 1, title: "Project A" },
{ id: 2, title: "Project B" },
]),
}));
IntersectionObserver Mock
For components with scroll-triggered animations, mock the observer:
beforeEach(() => {
const mockIntersectionObserver = vi.fn();
mockIntersectionObserver.mockReturnValue({
observe: vi.fn(),
unobserve: vi.fn(),
disconnect: vi.fn(),
});
window.IntersectionObserver = mockIntersectionObserver;
});
These patterns keep tests focused, readable, and resistant to refactoring. If a test breaks because you renamed a CSS class, that test was testing the wrong thing.
Written by
Adrian Saycon
A developer with a passion for emerging technologies, Adrian Saycon focuses on transforming the latest tech trends into great, functional products.
Discussion (0)
Sign in to join the discussion
No comments yet. Be the first to share your thoughts.
Related Articles

Building and Deploying Full-Stack Apps with AI Assistance
A weekend project walkthrough: building a full-stack task manager from architecture planning to deployment, with AI as t

AI-Assisted Database Design and Query Optimization
How to use AI for schema design, index recommendations, N+1 detection, and query optimization in PostgreSQL and MySQL.

Automating Repetitive Tasks with AI Scripts
Practical patterns for using AI to generate automation scripts for data migration, file processing, and scheduled tasks.