Advanced React Testing
Learn React Testing Library for testing React components in a way that resembles how users interact with your application.
90 min•By Priygop Team•Last updated: Feb 2026
RTL Philosophy
React Testing Library focuses on testing components the way users would interact with them, making tests more reliable and maintainable.
Basic Component Testing
Example
// Basic component test
import { render, screen } from '@testing-library/react';
import Button from './Button';
test('renders button with text', () => {
render(<Button>Click me</Button>);
expect(screen.getByRole('button', { name: 'Click me' })).toBeInTheDocument();
});User Interactions
Example
// Testing user interactions
import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('increments counter on button click', () => {
render(<Counter />);
const button = screen.getByRole('button', { name: /increment/i });
const count = screen.getByText('Count: 0');
fireEvent.click(button);
expect(count).toHaveTextContent('Count: 1');
});Form Testing
Example
// Testing forms
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import LoginForm from './LoginForm';
test('submits form with valid data', async () => {
const onSubmit = jest.fn();
render(<LoginForm onSubmit={onSubmit} />);
fireEvent.change(screen.getByLabelText(/email/i), {
target: { value: 'test@example.com' }
});
fireEvent.change(screen.getByLabelText(/password/i), {
target: { value: 'password123' }
});
fireEvent.click(screen.getByRole('button', { name: /submit/i }));
await waitFor(() => {
expect(onSubmit).toHaveBeenCalledWith({
email: 'test@example.com',
password: 'password123'
});
});
});Custom Hooks Testing
Example
// Testing custom hooks
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';
test('useCounter hook', () => {
const { result } = renderHook(() => useCounter(0));
expect(result.current.count).toBe(0);
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});Mini-Project: Complete Component Test Suite
Example
// Complete test suite for a complex component
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { BrowserRouter } from 'react-router-dom';
import UserProfile from './UserProfile';
const renderWithRouter = (component) => {
return render(
<BrowserRouter>
{component}
</BrowserRouter>
);
};
describe('UserProfile Component', () => {
const mockUser = {
id: 1,
name: 'John Doe',
email: 'john@example.com',
avatar: 'avatar.jpg'
};
beforeEach(() => {
jest.clearAllMocks();
});
test('renders user information', () => {
renderWithRouter(<UserProfile user={mockUser} />);
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('john@example.com')).toBeInTheDocument();
});
test('handles edit mode toggle', async () => {
const user = userEvent.setup();
renderWithRouter(<UserProfile user={mockUser} />);
const editButton = screen.getByRole('button', { name: /edit/i });
await user.click(editButton);
expect(screen.getByDisplayValue('John Doe')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /save/i })).toBeInTheDocument();
});
test('saves user changes', async () => {
const onSave = jest.fn();
const user = userEvent.setup();
renderWithRouter(<UserProfile user={mockUser} onSave={onSave} />);
await user.click(screen.getByRole('button', { name: /edit/i }));
await user.clear(screen.getByDisplayValue('John Doe'));
await user.type(screen.getByDisplayValue(''), 'Jane Doe');
await user.click(screen.getByRole('button', { name: /save/i }));
await waitFor(() => {
expect(onSave).toHaveBeenCalledWith({
...mockUser,
name: 'Jane Doe'
});
});
});
});