Vitest Mocking: Isolating Code with `vi.mock`

Vitest's vi.mock replaces a module with a fake version, isolating your code for tests. This is key for preventing real network or database calls. The footgun: calls are "hoisted" to the top of the file, running before other code and breaking variable access.
Why it exists
Unit tests should be fast, predictable, and isolated. When a piece of code depends on another module—like an API client or database connector—it breaks that isolation. Mocking was created to solve this by letting you replace real dependencies with controlled, fake versions during tests.
The mental model
Think of vi.mock as a pre-emptive find-and-replace for your module imports. Before any code in your test file runs, Vitest scans for vi.mock calls and says, "For this test file, whenever import { X } from './api' is requested, I will provide this fake version instead of the real one."
How it works
Vitest statically analyzes your test file and "hoists" all vi.mock calls to the very top, executing them before any import statements. When the JavaScript module loader encounters an import for a mocked path, it serves the result of your mock factory instead of the actual module's code. This result is then cached for all subsequent imports of that path within the same test file. The factory function you provide defines the mock's exports. It can be async and can even access the original module's exports using the importOriginal helper if needed.
When to use it
Use vi.mock for standard, module-level mocking in unit tests. It's the default choice for replacing external services (APIs, databases), modules with side effects (like file system access), or any dependency you want to control. It is also useful for just spying on a function to see if it was called, using the { spy: true } option, which keeps the original implementation but tracks its usage.
When not to use it
Do not use vi.mock when your mock's behavior needs to change based on variables defined inside a test or beforeEach block. Because vi.mock is hoisted, it executes before that scope exists and cannot access those variables. For that dynamic use case, vi.doMock is the correct tool, as it is not hoisted. Also, vi.mock only works for ES Modules (import), not CommonJS (require).
One canonical example
Imagine a calculator.js module. To test a component that uses it, you can mock the calculator to control its output.
File: src/calculator.js export const add = (a, b) => a + b;
File: tests/component.test.js
import { vi } from 'vitest';
import { add } from '../src/calculator.js';// Tell Vitest to replace the real module with a fake one.
vi.mock('../src/calculator.js', () => ({// Provide a mock implementation for the 'add' export. add: vi.fn(() => 100), // Always returns 100 }));
test('should use the mocked add function', () => {const result = add(2, 3); // Calls the mock, not the original
expect(result).toBe(100);
});Interview question
Which statement accurately describes a fundamental characteristic of Vitest's `vi.mock`?
- a.It statically analyzes the test file and executes mock factories before any module imports.Correct
- b.It is primarily designed for mocking CommonJS modules, not ES Modules.
- c.It replaces the original module's code only after the test file has fully loaded and executed.
- d.It allows mock implementations to be defined dynamically within beforeEach hooks.
Why? this is the answer
The card states that Vitest statically analyzes the test file and "hoists" all vi.mock calls, executing them before any import statements. Option D is incorrect because hoisting prevents vi.mock from accessing variables defined in test or beforeEach blocks for dynamic mocking.
Just read this? Test yourself on what you have been reading.
Read the original → vitest.dev
- #testing
- #vitest
- #mocking
- #javascript
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on testing — each one lists the topics its interview covers.
See open roles