jest.clearAllMocks vs jest.resetAllMocks

В тестах React с использованием React Testing Library состояние моков напрямую влияет на изоляцию сценариев, предсказуемость ассертов и корректность проверок побочных эффектов. Два ключевых инструмента Jest для работы с этим состоянием — jest.clearAllMocks() и jest.resetAllMocks(). Несмотря на схожесть названий, их поведение принципиально различается.


jest.clearAllMocks(): очистка истории вызовов

jest.clearAllMocks() сбрасывает только информацию о вызовах всех моков:

  • количество вызовов (mock.calls)
  • результаты вызовов (mock.results)
  • контекст (mock.instances)

При этом:

  • реализация мока сохраняется
  • возвращаемые значения сохраняются
  • замены через jest.mock() остаются активными

Пример

const fetchData = jest.fn().mockResolvedValue({ data: [] });

fetchData();
fetchData();

expect(fetchData).toHaveBeenCalledTimes(2);

jest.clearAllMocks();

expect(fetchData).toHaveBeenCalledTimes(0);

// Реализация сохранена
await fetchData(); // по-прежнему возвращает { data: [] }

Практическое значение в React Testing Library

При тестировании компонентов часто требуется:

  • сохранить стаб мока (например, API-клиента)
  • очистить счётчики вызовов между тестами
  • избежать повторной конфигурации в каждом it

Типичный сценарий:

beforeEach(() => {
  jest.clearAllMocks();
});

Это позволяет писать тесты, где:

  • каждый кейс начинается с чистой историей вызовов
  • моки сервисов, хуков и утилит остаются настроенными

jest.resetAllMocks(): полный сброс моков

jest.resetAllMocks() выполняет полную перезагрузку всех моков:

  • очищает историю вызовов
  • удаляет реализацию
  • сбрасывает возвращаемые значения
  • приводит моки к состоянию jest.fn()

Фактически, это эквивалент вызова .mockReset() для каждого мока.

Пример

const fetchData = jest.fn().mockResolvedValue({ data: [] });

await fetchData();

jest.resetAllMocks();

await fetchData(); // возвращает undefined

Влияние на jest.mock()

Если модуль был замокан так:

jest.mock('../api', () => ({
  fetchUser: jest.fn().mockResolvedValue({ name: 'Alex' }),
}));

После jest.resetAllMocks():

  • fetchUser остаётся функцией-моком
  • но её реализация удаляется
  • fetchUser() возвращает undefined

Это критично при тестировании компонентов, которые ожидают конкретные данные:

render(<UserProfile />);

Компонент может упасть или перейти в некорректное состояние из-за отсутствия данных.


Сравнение поведения

Характеристика clearAllMocks resetAllMocks
Очистка истории вызовов
Сброс реализации
Сброс возвращаемых значений
Повторная настройка моков требуется
Подходит для beforeEach в RTL редко

Взаимодействие со spy (jest.spyOn)

jest.spyOn создаёт мок поверх существующей реализации.

const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
  • clearAllMocks() очистит количество вызовов
  • resetAllMocks() удалит mockImplementation, вернув исходную функцию

Это важно при проверке ошибок рендера:

expect(console.error).toHaveBeenCalled();

После resetAllMocks() такой ассерт может перестать работать, если реализация больше не заглушена.


Асинхронные моки и RTL

При тестировании асинхронного поведения:

api.fetchUsers.mockResolvedValueOnce([...]);
  • clearAllMocks() не удалит очередь mockResolvedValueOnce
  • resetAllMocks() очистит её полностью

Это может приводить к трудноотлавливаемым ошибкам, когда компонент в следующем тесте не получает ожидаемые данные.


Типичные ошибки

Потеря реализации между тестами

beforeEach(() => {
  jest.resetAllMocks();
});

При наличии глобальных моков API или кастомных хуков это приводит к:

  • undefined вместо данных
  • падению компонентов на этапе рендера
  • необходимости дублировать настройки в каждом тесте

Скрытая зависимость от порядка тестов

Использование clearAllMocks() при тестах, которые изменяют реализацию мока (mockImplementationOnce), может оставить остаточное состояние.

В таких случаях предпочтительнее:

  • локальный mockReset() конкретного мока
  • или явная перенастройка перед тестом

Рекомендованные паттерны

Для большинства RTL-тестов

beforeEach(() => {
  jest.clearAllMocks();
});

Для тестов, меняющих реализацию мока

afterEach(() => {
  someMock.mockReset();
});

Для полной изоляции тестового окружения

Используется редко, обычно в низкоуровневых unit-тестах:

afterEach(() => {
  jest.resetAllMocks();
});

Связь с философией React Testing Library

React Testing Library ориентирован на поведение пользователя, а не на внутренние детали реализации. Стабильные моки — часть этого подхода. Частый полный сброс моков противоречит идее тестирования через интерфейс компонента, увеличивает шум и снижает читаемость тестов.

jest.clearAllMocks() поддерживает:

  • предсказуемость окружения
  • минимизацию лишней конфигурации
  • фокус на результатах, а не на подготовке

jest.resetAllMocks() — инструмент точечного применения, требующий осознанного контроля.