gotchatypescriptnoneMajor
Mocking Modules in Jest/Vitest: Hoisting and Factory Functions
Viewed 0 times
jest.mockvi.mockhoistingmodule mockfactory functionvi.hoisted
Error Messages
Problem
jest.mock() / vi.mock() calls appear to work but the mock isn't applied because the module was already imported before the mock was set up, or the factory function accesses variables not yet defined.
Solution
Understand hoisting and use factory functions correctly.
// Jest/Vitest hoists mock() calls to the top of the file
// But variables in the factory must be in scope BEFORE hoisting
// BAD: mockFn is not in scope when factory runs (hoisted before const)
const mockFn = jest.fn();
jest.mock('./api', () => ({ fetch: mockFn })); // ReferenceError!
// GOOD: use vi.fn() inside the factory
jest.mock('./api', () => ({
fetch: jest.fn().mockResolvedValue({ data: [] }),
}));
// GOOD: access the mock after import
import { fetch } from './api';
jest.mock('./api');
beforeEach(() => {
(fetch as jest.Mock).mockResolvedValue({ data: [] });
});
// GOOD in Vitest: use vi.hoisted() to define before hoisting
const mockFetch = vi.hoisted(() => vi.fn());
vi.mock('./api', () => ({ fetch: mockFetch }));Why
Babel/TypeScript transforms hoist jest.mock() / vi.mock() calls to before imports. Variables defined with const/let are not initialized at hoist time, causing ReferenceError in the factory.
Gotchas
- Variables prefixed with 'mock' are special in Jest — Babel allows them in factory closures.
- vi.hoisted() in Vitest explicitly declares a value that will be available before the mock factory runs.
- After calling jest.mock(), the module's exports are the mock — you still import them normally.
Revisions (0)
No revisions yet.