Back to Rules
React94% popularity

React Component Testing with Testing Library

Test behavior over implementation. Use Testing Library queries to interact with components as users would.

Kent C. DoddsUpdated Jan 28, 2024

Overview

React Testing Library fundamentally shifts the paradigm from testing component internals to testing user-facing behavior. The guiding principle "The more your tests resemble the way your software is used, the more confidence they can give you" informs every API decision and best practice in the library. Traditional testing approaches often led to brittle tests that broke when implementation details changed, even when the component's behavior remained correct. Testing Library addresses this by providing queries that prioritize accessibility and user perspective over component internals. Queries like getByRole, getByLabelText, and getByPlaceholderText simulate how users actually interact with the interface through assistive technologies. The fireEvent and userEvent APIs simulate real user interactions including keyboard navigation, mouse clicks, and form inputs. userEvent is preferred in most cases as it provides more realistic simulation of user behavior, including proper timing between keystrokes and handling of special keys. The waitFor and findBy queries handle asynchronous operations naturally, waiting for elements to appear rather than relying on arbitrary timeouts. Testing Library integrates seamlessly with Jest and other test runners, and its companion library jest-dom provides custom Jest matchers for DOM elements. These matchers like toBeInTheDocument, toHaveValue, and toHaveAttribute make assertions more semantic and the error messages when tests fail much more actionable. The setupFilesAfterEnv configuration ensures these matchers are available in every test file without explicit imports.

Code Example

.reactrules
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { LoginForm } from './LoginForm';

describe('LoginForm', () => {
  const mockOnSubmit = jest.fn();

  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('submits the form with valid credentials', async () => {
    const user = userEvent.setup();
    render(<LoginForm onSubmit={mockOnSubmit} />);

    await user.type(screen.getByLabelText(/email/i), 'developer@example.com');
    await user.type(screen.getByLabelText(/password/i), 'securePassword123');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    expect(mockOnSubmit).toHaveBeenCalledWith({
      email: 'developer@example.com',
      password: 'securePassword123',
    });
  });

  it('displays validation errors for invalid email', async () => {
    const user = userEvent.setup();
    render(<LoginForm onSubmit={mockOnSubmit} />);

    await user.type(screen.getByLabelText(/email/i), 'invalid-email');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    expect(screen.getByText(/please enter a valid email/i)).toBeInTheDocument();
    expect(mockOnSubmit).not.toHaveBeenCalled();
  });

  it('shows password requirements on focus', async () => {
    render(<LoginForm onSubmit={mockOnSubmit} />);

    const passwordInput = screen.getByLabelText(/password/i);
    fireEvent.focus(passwordInput);

    await waitFor(() => {
      expect(screen.getByText(/password must contain/i)).toBeInTheDocument();
    });
  });
});

More React Rules

REACT
96%

React Server Components Data Fetching Patterns

Master async/await patterns in Server Components for efficient data loading and caching.

reactserver-componentsdata-fetching
import { db } from '@/lib/db';
import { cache } from 'next/cache';
import { Suspense } from 'react';
import { Skeleton } from '@/components/ui/skeleto...
Feb 10, 2024by React Team
View Rule
REACT
95%

React Performance Optimization Patterns

Use React.memo, useMemo, and useCallback correctly to prevent unnecessary re-renders.

reactperformanceoptimization
import React, { useState, useMemo, useCallback, memo, useEffect } from 'react';

// Expensive calculation helper
function calculateExpensiveValue(item...
Jan 25, 2024by Dan Abramov
View Rule
REACT
96%

React Form Handling with React Hook Form

Build performant forms with React Hook Form using uncontrolled components and validation.

reactformsreact-hook-form
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import DatePick...
Mar 22, 2024by Beier(Bill) Luo
View Rule