new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Vitest · Guide · all subjects

mocking

106 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

vi.spyOn wraps an existing method

vi.spyOn() wraps an existing method on an object instead of creating a brand new function. The original implementation still works by default, but you can observe every call and optionally override the behavior with mockReturnValue or mockImplementation.

vi.fn() creates a basic mock function

vi.fn() creates a mock function that does nothing by default and returns undefined. It tracks every call made to it. A call to vi.fn() returns a tracked function that can be asserted on with expect statements like toHaveBeenCalled() and toHaveBeenCalledTimes().

Mock return values with mockReturnValue

mockReturnValue() makes a mock always return a specific value. mockReturnValueOnce() returns a specific value only once, then falls back to the default behavior. After using mockReturnValueOnce, subsequent calls return the value set by mockReturnValue if it was set, otherwise undefined.

Mock async function returns

For async functions, use mockResolvedValue() to control the resolved promise value and mockRejectedValue() to make the promise reject with an error.

mockImplementation provides custom function logic

mockImplementation() provides a full replacement function that runs when the mock is called. You can pass a function implementation directly to vi.fn() as a shorthand: vi.fn((a, b) => a + b).

Inspect mock calls with mock.calls and mock.results

The .mock property on a mock function gives access to full call history. .mock.calls is an array of argument arrays for each call. .mock.results is an array of objects with type ('return' or 'throw') and value properties showing what the mock returned or threw on each call.

Mock call inspection matchers

Use toHaveBeenCalledTimes(n) to assert the number of calls. Use toHaveBeenCalledWith(...args) to assert specific arguments were used. Use toHaveBeenNthCalledWith(n, ...args) to check arguments of a specific call by position. Use toHaveBeenLastCalledWith(...args) to check the most recent call.

mock.calls stores references not copies

mock.calls stores references to the original arguments, not copies. If you pass an object to a mock and mutate it afterwards, the recorded call will reflect the mutated state, not the state at the time of the call. To capture the original state, use mockImplementation with structuredClone to store a copy of the arguments.

Three levels of mock cleanup

mockClear() clears recorded call history and return values but keeps custom implementation. mockReset() does everything mockClear does and also removes custom implementation, returning the mock to default state. mockRestore() is for spies created with vi.spyOn and restores the original method; on vi.fn() mocks it behaves the same as mockReset.

vi.restoreAllMocks() cleans all mocks after each test

vi.restoreAllMocks() restores all mocks and spies to their original state. It is commonly used in afterEach hooks to prevent test state leakage.

restoreMocks configuration option

Set restoreMocks: true in the test configuration to automatically restore all mocks after each test, eliminating the need for manual afterEach cleanup.

vi.mock replaces entire module exports

vi.mock() replaces a module's exports with mock implementations. It takes an import statement and a factory function that returns mock implementations. vi.mock calls are hoisted to the top of the file and run before any imports, ensuring the mocked version is in place when tests run.

Use import() not string in vi.mock

Always pass import('./module.js') rather than a plain string './module.js' to vi.mock. Using import() allows TypeScript to infer module types for type-checking, enables automatic refactoring when files are moved or renamed, and allows importOriginal to return a correctly typed module.

vi.mocked() retrieves a mocked import

vi.mocked() retrieves the mocked version of an imported function or module. It is used after vi.mock to access the mock for setting up behavior like mockReturnValue.

Mock functions example

Example of creating and using a mock function: ```js import { expect, test, vi } from 'vitest' test('mock function basics', () => { const getApples = vi.fn() // Call it getApples() // Check it was called expect(getApples).toHaveBeenCalled() expect(getApples).toHaveBeenCalledTimes(1) // By default, a mock returns undefined expect(getApples()).toBeUndefined() }) ```

Mock return values example

Example of controlling mock return values: ```js import { expect, test, vi } from 'vitest' test('mock return values', () => { const getApples = vi.fn() // Always return this value getApples.mockReturnValue(10) expect(getApples()).toBe(10) // Return this value only once, then fall back to the default getApples.mockReturnValueOnce(20) expect(getApples()).toBe(20) // 20 (one-time) expect(getApples()).toBe(10) // back to default }) ```

Mock async return values example

Example of mocking async functions: ```js test('mock async return values', async () => { const fetchUser = vi.fn() fetchUser.mockResolvedValue({ name: 'Alice' }) const user = await fetchUser() expect(user.name).toBe('Alice') fetchUser.mockRejectedValue(new Error('Not found')) await expect(fetchUser()).rejects.toThrow('Not found') }) ```

Mock implementation example

Example of providing a custom implementation: ```js import { expect, test, vi } from 'vitest' test('mock with custom implementation', () => { const add = vi.fn() add.mockImplementation((a, b) => a + b) expect(add(1, 2)).toBe(3) expect(add(10, 20)).toBe(30) }) ```

Inspect mock calls example

Example of inspecting how a mock was called: ```js import { expect, test, vi } from 'vitest' test('inspecting mock calls', () => { const greet = vi.fn() greet('Alice') greet('Bob', 'Charlie') // Number of calls expect(greet).toHaveBeenCalledTimes(2) // Check specific arguments expect(greet).toHaveBeenCalledWith('Alice') expect(greet).toHaveBeenCalledWith('Bob', 'Charlie') // Check the arguments of a specific call by position expect(greet).toHaveBeenNthCalledWith(1, 'Alice') expect(greet).toHaveBeenLastCalledWith('Bob', 'Charlie') // Access the raw call data expect(greet.mock.calls).toEqual([ ['Alice'], ['Bob', 'Charlie'], ]) }) ```

Inspect mock results example

Example of inspecting mock results: ```js const double = vi.fn(x => x * 2) double(5) double(10) expect(double.mock.results).toEqual([ { type: 'return', value: 10 }, { type: 'return', value: 20 }, ]) ```

Spy on method example

Example of spying on an existing method: ```js import { expect, test, vi } from 'vitest' const calculator = { add(a, b) { return a + b }, } test('spy on a method', () => { const spy = vi.spyOn(calculator, 'add') // The original implementation still works expect(calculator.add(1, 2)).toBe(3) // But we can observe calls expect(spy).toHaveBeenCalledWith(1, 2) expect(spy).toHaveBeenCalledTimes(1) }) test('spy can override implementation', () => { const spy = vi.spyOn(calculator, 'add') spy.mockReturnValue(42) expect(calculator.add(1, 2)).toBe(42) }) ```

Automatic mock restoration example

Example of automatically restoring mocks after each test: ```js import { afterEach, expect, test, vi } from 'vitest' const calculator = { add: (a, b) => a + b, } afterEach(() => { vi.restoreAllMocks() }) test('spy is restored after the test', () => { const spy = vi.spyOn(calculator, 'add').mockReturnValue(42) expect(calculator.add(1, 2)).toBe(42) // afterEach will restore calculator.add to the original implementation }) ```

Mock a module example

Example of mocking an entire module: ```js import { expect, test, vi } from 'vitest' import { getUser } from './db.js' vi.mock(import('./db.js'), () => ({ getUser: vi.fn(), })) test('mock a module', () => { vi.mocked(getUser).mockReturnValue({ name: 'Alice' }) const user = getUser(1) expect(user.name).toBe('Alice') expect(getUser).toHaveBeenCalledWith(1) }) ```

Provide dependency information for mocking

If the code under test has dependencies that need mocking, share those files or at least their type signatures. The AI cannot write a useful mock for a module it has never seen.

Avoid over-mocking in AI-generated tests

AI tends to over-mock. If you see a test that mocks every dependency and then asserts that specific internal methods were called in a specific order, that is testing implementation details rather than behavior. These tests break when you refactor, even if behavior stays the same.

AI-generated tests often don't restore mocks

AI-generated tests often set up spies with vi.spyOn or replace modules with vi.mock but never restore them. If your config doesn't have restoreMocks: true, these mocks leak between tests and cause confusing failures. Enable restoreMocks globally to fix this.

Prefer vi.mock with import() over string paths

AI tools tend to mock modules using string paths (vi.mock('./module.js')) when the import() form (vi.mock(import('./module.js'))) is preferable for type safety and automatic refactoring.

AI uses Jest APIs instead of Vitest APIs

The most frequent issue with AI-generated Vitest tests is using wrong API surface. AI models trained on Jest code sometimes generate jest.fn() instead of vi.fn(), or jest.mock instead of vi.mock. These will fail immediately. Point the AI to the Vitest API reference or include it in context.

What not to mock

Do not mock the thing you are testing. If testing a UserService, do not mock the UserService itself. Instead, mock its dependencies like the database and email sender, and let the service run for real. Prefer real implementations when they are fast and reliable, such as simple in-memory data structures or pure functions. The closer tests are to real usage, the more confidence they provide.

When to mock: slow dependencies

Mock network requests, file system operations, and database calls to keep tests fast. These operations can make tests take seconds instead of milliseconds. For HTTP requests specifically, consider using Mock Service Worker instead of mocking fetch directly.

Mocking only for slow, flaky, or side-effect dependencies

Only reach for mocks when the real thing is slow, flaky, or has side effects you cannot control in a test.

When to mock: non-deterministic values

If code depends on the current date, a random number, or a UUID generator, mock those to make tests predictable. Vitest provides vi.useFakeTimers() and vi.setSystemTime() for controlling time in tests.

vi.mock is hoisted to top of file

vi.mock calls are hoisted to the top of the file. This means the vi.mock call will always be executed before all imports, regardless of where it appears in the file.

Environmental variable values do not auto-reset

Environmental variable values set directly to import.meta.env will not automatically reset between different tests.

Mock exported class implementation with vi.mock

To mock an exported class using vi.mock, return an object with a vi.fn() that wraps a fake class: vi.mock(import('./example.js'), () => { const SomeClass = vi.fn(class FakeClass { someMethod = vi.fn() }); return { SomeClass } }).

Mock exported class implementation with vi.spyOn

To mock an exported class using vi.spyOn, spy on the class and provide a mockImplementation with a fake class: vi.spyOn(mod, 'SomeClass').mockImplementation(class FakeClass { someMethod = vi.fn() }). This approach will not work in Browser Mode.

Spy on object returned from function using cache

To spy on an object returned from a function, use vi.mock to intercept the factory and cache the mock object. Each call to the function will return the same cached object reference, allowing you to assert that methods on it were called.

Mock exported function with vi.spyOn

To mock an exported function using vi.spyOn, import the module as namespace and spy on the function: vi.spyOn(exports, 'method').mockImplementation(() => {}). This approach will not work in Browser Mode.

Mock current date with vi.setSystemTime

To mock Date and Temporal time, use vi.setSystemTime helper function. This value will not automatically reset between tests. Using vi.useFakeTimers also changes the Date time. Example: vi.setSystemTime(new Date(2022, 0, 1)); const now = new Date(); expect(now.valueOf()).toBe(new Date(2022, 0, 1).valueOf()); Reset with vi.useRealTimers().

Mock global variable with vi.stubGlobal

To mock a global variable, use vi.stubGlobal('variableName', value). This will not automatically reset between tests unless you enable the unstubGlobals config option or call vi.unstubAllGlobals(). You can also assign directly to globalThis.

Mock import.meta.env with vi.stubEnv

To mock environmental variables, assign directly to import.meta.env (which will not auto-reset), or use vi.stubEnv helper with unstubEnvs config option enabled or call vi.unstubAllEnvs manually in a beforeEach hook. Example: vi.stubEnv('VITE_ENV', 'staging'); expect(import.meta.env.VITE_ENV).toBe('staging').

Module mocking only mocks external access

When mocking part of a module, only external access to that module is mocked. If the original function calls the mocked function internally, it will always call the function defined in the module, not the mock factory.

Mocking overview and vi helper

Mocking is creating a fake version of an internal or external service. Vitest provides utility functions through the vi helper, which can be imported from 'vitest' or accessed globally if global configuration is enabled.

Clear or restore mocks between test runs

Always remember to clear or restore mocks before or after each test run to undo mock state changes between runs. See mockReset documentation for more information.

Mocking guides available in Vitest

Vitest provides comprehensive guides for mocking: Mocking Classes, Mocking Dates, Mocking the File System, Mocking Functions, Mocking Globals, Mocking Modules, Mocking Requests, and Mocking Timers.

Mock exported variables with vi.spyOn

To mock an exported variable, use vi.spyOn with the 'get' option: vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked'). This approach will not work in Browser Mode.

Mock exported function with vi.mock

To mock an exported function using vi.mock, call vi.mock with the module path and a factory function that returns an object with mocked functions. For example: vi.mock('./example.js', () => ({ method: vi.fn() })). Remember that vi.mock is hoisted to the top of the file and executes before all imports.

Mock part of a module

To mock only part of a module, use vi.mock with importOriginal to get the original module, spread it into the return object, and selectively replace exports: vi.mock(import('./some-path.js'), async (importOriginal) => { const mod = await importOriginal(); return { ...mod, mocked: vi.fn() } }). Note that this only mocks external access; if the original function calls the mocked function internally, it will call the original, not the mock.

vi.setSystemTime() to set a specific date

Use vi.setSystemTime(date) to set the system time to a specific date object. After calling this, Date.now() and new Date() will return the mocked time instead of the real time.

vi.useRealTimers() to restore real time

Call vi.useRealTimers() to restore real timers and system time after mocking. Use this in afterEach hooks to clean up after tests that use fake timers.

vi.useFakeTimers() to mock time

Call vi.useFakeTimers() to enable mocked time control in tests. This allows you to manipulate system date and timers using @sinonjs/fake-timers under the hood.

Mocking dates example with business hours

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' const businessHours = [9, 17] function purchase() { const currentHour = new Date().getHours() const [open, close] = businessHours if (currentHour > open && currentHour < close) { return { message: 'Success' } } return { message: 'Error' } } describe('purchasing flow', () => { beforeEach(() => { vi.useFakeTimers() }) afterEach(() => { vi.useRealTimers() }) it('allows purchases within business hours', () => { const date = new Date(2000, 1, 1, 13) vi.setSystemTime(date) expect(purchase()).toEqual({ message: 'Success' }) }) it('disallows purchases outside of business hours', () => { const date = new Date(2000, 1, 1, 19) vi.setSystemTime(date) expect(purchase()).toEqual({ message: 'Error' }) }) }) This example shows how to use fake timers to test time-dependent code by setting the system time to specific hours and verifying behavior during and outside business hours.

File system mocking rationale

Mocking the file system ensures tests do not depend on the actual file system, making them more reliable and predictable. This isolation helps avoid side effects from previous tests and allows testing error conditions and edge cases that might be difficult or impossible to replicate with an actual file system, such as permission issues, disk full scenarios, or read/write errors.

Vitest file system mocking approach

Vitest does not provide a file system mocking API out of the box. While you can use vi.mock to mock the fs module manually, it is hard to maintain. Instead, the recommended approach is to use memfs to create an in-memory file system that simulates file system operations without touching the actual disk. This approach is fast and safe, avoiding potential side effects on the real file system.

Setting up memfs file system mocks

To automatically redirect every fs call to memfs, create __mocks__/fs.cjs at the root of your project with content: const { fs } = require('memfs'); module.exports = fs. Also create __mocks__/fs/promises.cjs with content: const { fs } = require('memfs'); module.exports = fs.promises. You can use import syntax, but then every export must be explicitly defined.

Using vi.mock to enable file system mocks

Call vi.mock('node:fs') and vi.mock('node:fs/promises') to tell Vitest to use the fs mock files from the __mocks__ folder. This can be done in a setup file if fs should always be mocked.

Resetting memfs state in tests

Use vol.reset() in a beforeEach hook to reset the state of the in-memory file system between tests.

Example: Basic memfs file write and read

To test file operations with memfs: import { beforeEach, expect, it, vi } from 'vitest'; import { fs, vol } from 'memfs'; import { readHelloWorld } from './read-hello-world.js'; vi.mock('node:fs'); vi.mock('node:fs/promises'); beforeEach(() => { vol.reset(); }); it('should return correct text', () => { const path = '/hello-world.txt'; fs.writeFileSync(path, 'hello world'); const text = readHelloWorld(path); expect(text).toBe('hello world'); });

Example: Using vol.fromJSON to define multiple files

You can use vol.fromJSON to define several files at once: vol.fromJSON({ './dir1/hw.txt': 'hello dir1', './dir2/hw.txt': 'hello dir2', }, '/tmp'). The first parameter is an object mapping file paths to their content, and the second parameter is the default current working directory.

vi.when() for conditional mocking

vi.when() lets you define argument-specific behaviors for mocks without writing if/else logic. It allows a mock to return different values depending on the arguments it receives.

Give your agent this brain