jest.mock — ключевой механизм Jest для изоляции
тестируемого кода от внешних зависимостей. В контексте React Testing
Library он используется для подмены модулей, которые:
Главная идея — тестировать поведение компонента, а не корректность работы его зависимостей.
jest.mockФункция jest.mock перехватывает импорт модуля и заменяет
его на mock-реализацию.
jest.mock('./api')
После этого любой импорт ./api внутри тестируемого файла
или импортируемых модулей будет заменён на mock.
Если не указать реализацию явно, Jest автоматически создаст
автоматический mock — объект с теми же ключами, но
функциями-заглушками (jest.fn()).
jest.mock на импорт модулейВажно понимать порядок выполнения:
jest.mock всплывает (hoisting) и
выполняется до импортовjest.mock('./userService')
import { getUser } from './userService'
Даже если jest.mock написан ниже, Jest всё равно
поднимет его вверх.
Для полного контроля используется фабричная функция:
jest.mock('./userService', () => ({
getUser: jest.fn(),
updateUser: jest.fn()
}))
Теперь:
getUser и updateUser — mock-функцииНаиболее распространённые методы:
getUser.mockReturnValue({ name: 'Alex' })
getUser.mockResolvedValue({ name: 'Alex' })
getUser.mockRejectedValue(new Error('Ошибка'))
Пример в контексте React Testing Library:
getUser.mockResolvedValue({ name: 'Alex' })
render(<Profile />)
expect(await screen.findByText('Alex')).toBeInTheDocument()
Асинхронные функции (fetch, axios, API-клиенты) всегда мокаются через
mockResolvedValue или mockRejectedValue.
jest.mock('./api', () => ({
fetchPosts: jest.fn()
}))
fetchPosts.mockResolvedValue([
{ id: 1, title: 'Post' }
])
Это позволяет:
fetchИногда требуется сохранить часть реальной реализации.
Используется jest.requireActual:
jest.mock('./utils', () => {
const actual = jest.requireActual('./utils')
return {
...actual,
formatDate: jest.fn(() => '01.01.2024')
}
})
Полезно, когда:
Компоненты часто подменяются упрощёнными заглушками.
jest.mock('./Header', () => () => <div>Header</div>)
Применяется для:
В RTL тестируется не внутреннее устройство компонента, а его влияние на DOM.
Частый сценарий — подмена кастомных хуков.
jest.mock('./useAuth', () => ({
useAuth: jest.fn()
}))
Затем:
useAuth.mockReturnValue({
isAuth: true,
user: { name: 'Admin' }
})
Это позволяет тестировать компонент в разных состояниях без сложной подготовки окружения.
Некоторые API отсутствуют в JSDOM или ведут себя иначе.
Примеры:
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: jest.fn()
}))
Или:
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(() => ({
matches: false,
addListener: jest.fn(),
removeListener: jest.fn()
}))
})
Mock-функции сохраняют историю вызовов.
Рекомендуемые практики:
afterEach(() => {
jest.clearAllMocks()
})
Различия методов:
clearAllMocks — очищает историю вызововresetAllMocks — сбрасывает реализациюrestoreAllMocks — возвращает оригинальные функции (для
spy)jest.mock
от jest.spyOnjest.mock:
jest.spyOn:
const spy = jest.spyOn(api, 'getUser')
spy.mockResolvedValue({ name: 'Alex' })
jest.mockМок после импорта
import { getUser } from './api'
jest.mock('./api') // не сработает ожидаемо
Несоответствие путей
jest.mock('../api') // путь должен совпадать с import
Забытый сброс состояния
jest.mock в философии React Testing LibraryReact Testing Library фокусируется на том, как пользователь взаимодействует с интерфейсом, а не на деталях реализации.
jest.mock в этой модели:
Моки используются не ради мока, а ради проверки отображения, поведения и реакций интерфейса на разные сценарии.