React Testing with Jest and React Testing Library Guide

react
testing
jest
react-testing-library

Installation

npm install --save-dev jest @testing-library/react @testing-library/jest-dom

Basic Test Structure

import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
 
test('renders learn react link', () => {
  render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});

Commonly Used Queries

  • getByText: Find an element by its text content
  • getByRole: Find an element by its ARIA role
  • getByLabelText: Find a form element by its label
  • getByPlaceholderText: Find an input by its placeholder
  • getByAltText: Find an image by its alt text
  • getByTestId: Find an element by its data-testid attribute

Async Testing

test('loads items eventually', async () => {
  render(<Page />);
 
  // Wait for the items to be loaded
  const items = await screen.findAllByRole('listitem');
  expect(items).toHaveLength(3);
});

Simulating User Events

import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
 
test('clicking button increments counter', () => {
  render(<Counter />);
  const button = screen.getByText('Increment');
  
  fireEvent.click(button);
  
  expect(screen.getByText('Count: 1')).toBeInTheDocument();
});
 
// Using userEvent for more realistic user interactions
test('typing in a textbox', async () => {
  render(<InputComponent />);
  const input = screen.getByRole('textbox');
  
  await userEvent.type(input, 'Hello, World!');
  
  expect(input).toHaveValue('Hello, World!');
});

Mocking

// Mocking a module
jest.mock('./api', () => ({
  fetchData: jest.fn(() => Promise.resolve({ data: 'mocked data' })),
}));
 
// Mocking a function
const mockFn = jest.fn();
mockFn.mockReturnValue(42);
 
// Asserting on mocks
expect(mockFn).toHaveBeenCalledTimes(1);
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2');

Snapshot Testing

import renderer from 'react-test-renderer';
 
test('Component renders correctly', () => {
  const tree = renderer.create(<MyComponent />).toJSON();
  expect(tree).toMatchSnapshot();
});

Testing Hooks

import { renderHook, act } from '@testing-library/react-hooks';
import useCounter from './useCounter';
 
test('should increment counter', () => {
  const { result } = renderHook(() => useCounter());
 
  act(() => {
    result.current.increment();
  });
 
  expect(result.current.count).toBe(1);
});

Common Assertions

expect(element).toBeInTheDocument();
expect(element).toHaveTextContent('Expected text');
expect(element).toBeVisible();
expect(element).toBeDisabled();
expect(element).toHaveClass('example-class');
expect(element).toHaveAttribute('type', 'text');

Remember to always write tests that resemble how your software is used. Focus on testing behavior rather than implementation details.