Мокирование внешних компонентов и модулей из
node_modules является критически важным при написании
unit-тестов на React. Оно позволяет изолировать тестируемый компонент,
ускоряет выполнение тестов и снижает вероятность возникновения
непредсказуемых побочных эффектов. Рассмотрим этот процесс подробно.
Мок (mock) — это объект или функция, которые имитируют поведение настоящего модуля. В контексте React Testing Library это чаще всего:
react-router-dom, antd,
material-ui);lodash,
axios и др.).Мокирование позволяет заменить сложную реализацию простыми заглушками, которые возвращают предсказуемый результат.
jest.mockСамый распространённый способ — использование функции
jest.mock. Синтаксис:
jest.mock('имя_модуля', () => ({
// Экспортируем необходимые функции или компоненты
}));
Пример: мокирование компонента Button
из @mui/material:
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
import React from 'react';
jest.mock('@mui/material', () => {
const originalModule = jest.requireActual('@mui/material');
return {
...originalModule,
Button: (props) => <button {...props} />,
};
});
test('рендерит кнопку', () => {
render(<MyComponent />);
expect(screen.getByRole('button')).toBeInTheDocument();
});
Ключевые моменты:
jest.requireActual для сохранения
неизменных экспоротов модуля.props для
совместимости с тестируемым компонентом.Помимо компонентов, часто требуется мокировать функции:
import axios from 'axios';
import { fetchData } from './api';
jest.mock('axios');
test('fetchData возвращает данные', async () => {
axios.get.mockResolvedValue({ data: { name: 'React' } });
const result = await fetchData();
expect(result).toEqual({ name: 'React' });
});
Особенности:
mockResolvedValue для промисов,
mockReturnValue для синхронных функций.__mocks__Для крупных проектов удобно создавать папку __mocks__
рядом с node_modules или внутри проекта. Jest автоматически
подхватывает моки из неё.
Пример структуры:
project/
├─ __mocks__/
│ └─ axios.js
└─ src/
└─ api.js
Содержимое __mocks__/axios.js:
export default {
get: jest.fn(() => Promise.resolve({ data: {} })),
};
Такой подход позволяет централизованно управлять всеми моками, упрощает поддержку тестов и делает их более предсказуемыми.
Иногда компонент импортирует другие компоненты из
node_modules, которые, в свою очередь, зависят от
глобальных контекстов или стилей. В таких случаях:
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
Link: ({ children }) => <a>{children}</a>,
}));
Особенности:
useNavigate, useParams), чтобы тесты не
ломались.<a>
вместо <Link>) предотвращает ошибки рендеринга.В реальных проектах часто требуется одновременно мокировать несколько модулей:
jest.mock('axios');
jest.mock('@mui/material', () => ({
Button: (props) => <button {...props} />,
TextField: (props) => <input {...props} />,
}));
Советы:
@testing-library/react и мокировать только критические
зависимости.При работе с TypeScript важно корректно типизировать моки:
import axios, { AxiosResponse } from 'axios';
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
mockedAxios.get.mockResolvedValue({ data: { id: 1 } } as AxiosResponse);
Это предотвращает ошибки компиляции и обеспечивает автодополнение в IDE.
jest.resetAllMocks() или
jest.clearAllMocks() между тестами для предотвращения
утечек состояния.Мокирование node_modules компонентов является основой
стабильного и быстрого тестирования в React. Оно обеспечивает контроль
над внешними зависимостями, уменьшает количество фейлов в тестах и
позволяет сосредоточиться на поведении собственного кода.