Мокирование дочерних компонентов — важная техника в тестировании React-приложений с помощью React Testing Library (RTL). Она позволяет изолировать тестируемый компонент, не загружая реальную логику и поведение его потомков. Такой подход упрощает тесты, делает их быстрее и сосредоточенными на функциональности конкретного компонента.
Мокирование полезно в следующих случаях:
Примером может служить компонент Dashboard, который
использует UserProfile и Notifications. Чтобы
протестировать только Dashboard, логично заменить
UserProfile и Notifications на простые
моки.
Наиболее распространённый способ — это мокирование через Jest, который часто используется совместно с RTL.
import { render, screen } from '@testing-library/react';
import Dashboard from './Dashboard';
// Мокаем дочерний компонент
jest.mock('./UserProfile', () => () => <div data-testid="mocked-user-profile" />);
jest.mock('./Notifications', () => () => <div data-testid="mocked-notifications" />);
test('рендерит Dashboard с мокированными компонентами', () => {
render(<Dashboard />);
expect(screen.getByTestId('mocked-user-profile')).toBeInTheDocument();
expect(screen.getByTestId('mocked-notifications')).toBeInTheDocument();
});
Ключевые моменты:
jest.mock() заменяет реальный модуль на
функцию-заглушку.data-testid для удобного поиска
элементов в тестах.Иногда важно проверить, какие пропсы передаются дочернему компоненту. В этом случае мокающий компонент может сохранять полученные пропсы:
const mockUserProfile = jest.fn(() => <div>Mocked UserProfile</div>);
jest.mock('./UserProfile', () => props => {
mockUserProfile(props);
return <div data-testid="mocked-user-profile" />;
});
test('Dashboard передаёт правильные пропсы в UserProfile', () => {
render(<Dashboard user={{ name: 'Alice' }} />);
expect(mockUserProfile).toHaveBeenCalledWith(
expect.objectContaining({ user: { name: 'Alice' } }),
{}
);
});
Особенности:
jest.fn().expect.objectContaining позволяет проверять только
нужные поля пропсов.Иногда требуется замокировать только часть функциональности модуля,
оставив остальное нетронутым. Для этого используется
jest.requireActual:
jest.mock('./Notifications', () => {
const originalModule = jest.requireActual('./Notifications');
return {
__esModule: true,
...originalModule,
default: () => <div data-testid="mocked-notifications" />,
};
});
Такой подход полезен, когда компонент экспортирует несколько функций или компонентов, и требуется замокировать лишь один из них.
Если дочерний компонент использует useEffect для
загрузки данных, мок может быть синхронным и возвращать статический
результат:
jest.mock('./AsyncComponent', () => () => <div data-testid="mocked-async">Loaded</div>);
В тесте можно сразу проверять состояние родителя, не ожидая асинхронного рендера.
data-testid делает тесты проще и
устойчивее к изменениям разметки.jest.fn() для
отслеживания вызовов.Мокирование дочерних компонентов позволяет писать компактные, быстрые и предсказуемые тесты. Правильное использование этой техники обеспечивает высокое покрытие критичных функций родительских компонентов без лишней сложности.