jest.mock для компонентов

jest.mock — мощный инструмент Jest для создания поддельных (mock) модулей и компонентов в тестах. В контексте React Testing Library его основная задача — изолировать тестируемый компонент, заменяя зависимости заглушками, чтобы тесты были детерминированными и не зависели от внешних модулей, сетевых запросов или сложных дочерних компонентов.

Основы использования

Для замены модуля или компонента используется синтаксис:

jest.mock('путь/к/модулю', () => {
  return {
    __esModule: true, // важно для экспорта по умолчанию
    default: () => <div>Mocked Component</div>,
    namedExport: jest.fn()
  };
});
  • __esModule: true — требуется, если модуль экспортируется через export default.
  • default — замена default-экспорта компонента.
  • namedExport — можно мокать отдельные именованные экспорты.

После такого объявления, при импорте модуля внутри тестируемого файла будет использоваться мок, а не реальная реализация.

Мок компонентов React

Частая задача — заменить дочерний компонент, чтобы тестировать только родителя:

import { render, screen } from '@testing-library/react';
import ParentComponent from './ParentComponent';
import ChildComponent from './ChildComponent';

jest.mock('./ChildComponent', () => () => <div>Mocked Child</div>);

test('отображает родительский компонент с замещённым дочерним', () => {
  render(<ParentComponent />);
  expect(screen.getByText('Mocked Child')).toBeInTheDocument();
});

В этом примере реальная реализация ChildComponent не выполняется, что ускоряет тесты и предотвращает побочные эффекты.

Мок функций внутри компонента

Если компонент использует функции из других модулей, их также можно замокать:

import { fetchData } from './api';
import MyComponent from './MyComponent';

jest.mock('./api', () => ({
  fetchData: jest.fn(() => Promise.resolve({ data: 'mocked data' }))
}));

test('использует замоканную функцию fetchData', async () => {
  render(<MyComponent />);
  const item = await screen.findByText('mocked data');
  expect(item).toBeInTheDocument();
});
  • Используется jest.fn() для создания шпионов и замоканных реализаций.
  • Можно проверять вызовы функций через toHaveBeenCalled() и toHaveBeenCalledWith().

Автоматический мок с jest.mock()

Если не передавать второй аргумент, Jest автоматически создаст мок:

jest.mock('./ChildComponent');
  • Автоматический мок создаёт заглушку, где все функции — jest.fn().
  • Можно вручную доопределить поведение, если требуется:
import ChildComponent from './ChildComponent';

ChildComponent.mockImplementation(() => <div>Custom Mock</div>);

Мок классовых компонентов

Для классовых компонентов принцип такой же, но нужно правильно обработать методы:

jest.mock('./MyClassComponent', () => {
  return jest.fn().mockImplementation(() => ({
    render: () => <div>Mocked Class Component</div>
  }));
});
  • Важно, чтобы мок возвращал объект с методом render.
  • Можно также мокать внутренние методы класса через jest.fn().

Уточнение поведения мока

Иногда требуется менять поведение мока только для одного теста:

import ChildComponent from './ChildComponent';

test('разное поведение мока', () => {
  ChildComponent.mockImplementation(() => <div>First Mock</div>);
  render(<ParentComponent />);
  expect(screen.getByText('First Mock')).toBeInTheDocument();

  ChildComponent.mockImplementation(() => <div>Second Mock</div>);
  render(<ParentComponent />);
  expect(screen.getByText('Second Mock')).toBeInTheDocument();
});
  • mockImplementation позволяет динамически менять реализацию.
  • После теста можно сбросить мок с помощью jest.resetAllMocks() или mockRestore() для восстановления оригинальных реализаций.

Мок компонентов с пропсами

Можно использовать пропсы для проверки взаимодействий:

jest.mock('./Button', () => ({ onClick, label }) => (
  <button onCl ick={onClick}>{label}</button>
));

test('вызывает onClick у замоканного Button', () => {
  const handleClick = jest.fn();
  render(<MyComponent onCl ick={handleClick} />);
  const button = screen.getByText('Click me');
  button.click();
  expect(handleClick).toHaveBeenCalled();
});
  • Такой подход позволяет тестировать поведение родителя, не зависимо от внутренней логики дочернего компонента.
  • Можно проверять передачу пропсов и вызовы callback-функций.

Советы по использованию jest.mock с React Testing Library

  • Использовать моки для изоляции тестируемого компонента, особенно если дочерние компоненты сложные или зависят от внешних сервисов.
  • Избегать излишнего мока: если компонент простой и не делает сетевых запросов, лучше тестировать его реально.
  • Сочетать с mockImplementation для создания разных сценариев в тестах.
  • Всегда сбрасывать моки после теста, чтобы избежать побочных эффектов.

Использование jest.mock позволяет писать быстрые, надёжные и предсказуемые тесты, концентрируясь на поведении конкретного компонента, а не на реализации его зависимостей.