Тестирование компонентов React часто требует имитации различных сценариев работы с сетью, включая ошибки и сбои соединения. Это позволяет проверить устойчивость приложения, корректность обработки исключений и поведение UI при нештатных ситуациях. React Testing Library (RTL) сама по себе фокусируется на взаимодействии с DOM, поэтому для симуляции сетевых запросов используется комбинация RTL и инструментов для мокирования API, таких как MSW (Mock Service Worker) или jest-fetch-mock.
Для большинства приложений сетевые запросы выполняются через
fetch или axios. Чтобы имитировать ошибки:
1. Использование jest-fetch-mock
import { render, screen, waitFor } from '@testing-library/react';
import MyComponent from './MyComponent';
beforeEach(() => {
fetch.resetMocks();
});
test('показывает сообщение об ошибке при сбое fetch', async () => {
fetch.mockReject(() => Promise.reject('Network error'));
render(<MyComponent />);
await waitFor(() => {
expect(screen.getByText(/ошибка загрузки/i)).toBeInTheDocument();
});
});
Здесь fetch.mockReject позволяет имитировать сетевой
сбой, а waitFor гарантирует асинхронное ожидание обновления
DOM после обработки ошибки компонентом.
2. Использование axios с jest.mock
import { render, screen, waitFor } from '@testing-library/react';
import axios from 'axios';
import MyComponent from './MyComponent';
jest.mock('axios');
test('отображает ошибку при отказе axios', async () => {
axios.get.mockRejectedValue(new Error('Request failed'));
render(<MyComponent />);
await waitFor(() => {
expect(screen.getByText(/не удалось загрузить данные/i)).toBeInTheDocument();
});
});
Мокирование axios через jest.mock позволяет
контролировать ответы и эмулировать сетевые ошибки без изменения
оригинального кода компонента.
MSW позволяет создавать более реалистичные сценарии работы с сетью, включая ошибки, таймауты и задержки.
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { render, screen, waitFor } from '@testing-library/react';
import MyComponent from './MyComponent';
const server = setupServer(
rest.get('/api/data', (req, res, ctx) => {
return res(ctx.status(500), ctx.json({ message: 'Internal Server Error' }));
})
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
test('обрабатывает 500 ошибку сервера', async () => {
render(<MyComponent />);
await waitFor(() => {
expect(screen.getByText(/внутренняя ошибка сервера/i)).toBeInTheDocument();
});
});
Преимущества MSW:
ctx.delay().Таймауты часто приводят к состоянию ожидания (loading) и требуют проверки корректного отображения индикаторов загрузки.
server.use(
rest.get('/api/data', (req, res, ctx) => {
return res(ctx.delay(3000), ctx.json({ data: [] }));
})
);
test('отображает индикатор загрузки при медленном ответе', async () => {
render(<MyComponent />);
expect(screen.getByText(/загрузка/i)).toBeInTheDocument();
});
Здесь ctx.delay(3000) имитирует медленное соединение,
проверяя реакцию UI на длительные сетевые операции.
Правильная обработка ошибок предполагает:
toast,
alert, div с сообщением).Пример теста с повторной попыткой:
server.use(
rest.get('/api/data', (req, res, ctx) => res(ctx.status(500))),
);
test('позволяет повторить запрос после ошибки', async () => {
render(<MyComponent />);
await waitFor(() => {
expect(screen.getByText(/ошибка загрузки/i)).toBeInTheDocument();
});
server.use(
rest.get('/api/data', (req, res, ctx) => res(ctx.json({ items: [1,2,3] }))),
);
screen.getByText(/повторить/i).click();
await waitFor(() => {
expect(screen.getByText(/элемент 1/i)).toBeInTheDocument();
});
});
expect после render.Эти методы обеспечивают комплексное покрытие сценариев network failures, повышают надежность компонентов и делают тесты более реалистичными и устойчивыми к изменению API.