Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vitest 3.x reference skill covering configuration, test/describe APIs, mocking, coverage, snapshots, and concurrency.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/features-mocking.md
1---2name: mocking3description: Mock functions, modules, timers, and dates with vi utilities4---56# Mocking78## Mock Functions910```ts11import { expect, vi } from 'vitest'1213// Create mock function14const fn = vi.fn()15fn('hello')1617expect(fn).toHaveBeenCalled()18expect(fn).toHaveBeenCalledWith('hello')1920// With implementation21const add = vi.fn((a, b) => a + b)22expect(add(1, 2)).toBe(3)2324// Mock return values25fn.mockReturnValue(42)26fn.mockReturnValueOnce(1).mockReturnValueOnce(2)27fn.mockResolvedValue({ data: true })28fn.mockRejectedValue(new Error('fail'))2930// Mock implementation31fn.mockImplementation((x) => x * 2)32fn.mockImplementationOnce(() => 'first call')33```3435## Spying on Objects3637```ts38const cart = {39getTotal: () => 100,40}4142const spy = vi.spyOn(cart, 'getTotal')43cart.getTotal()4445expect(spy).toHaveBeenCalled()4647// Mock implementation48spy.mockReturnValue(200)49expect(cart.getTotal()).toBe(200)5051// Restore original52spy.mockRestore()53```5455## Module Mocking5657```ts58// vi.mock is hoisted to top of file59vi.mock('./api', () => ({60fetchUser: vi.fn(() => ({ id: 1, name: 'Mock' })),61}))6263import { fetchUser } from './api'6465test('mocked module', () => {66expect(fetchUser()).toEqual({ id: 1, name: 'Mock' })67})68```6970### Partial Mock7172```ts73vi.mock('./utils', async (importOriginal) => {74const actual = await importOriginal()75return {76...actual,77specificFunction: vi.fn(),78}79})80```8182### Auto-mock with Spy8384```ts85// Keep implementation but spy on calls86vi.mock('./calculator', { spy: true })8788import { add } from './calculator'8990test('spy on module', () => {91const result = add(1, 2) // Real implementation92expect(result).toBe(3)93expect(add).toHaveBeenCalledWith(1, 2)94})95```9697### Manual Mocks (__mocks__)9899```100src/101__mocks__/102axios.ts # Mocks 'axios'103api/104__mocks__/105client.ts # Mocks './client'106client.ts107```108109```ts110// Just call vi.mock with no factory111vi.mock('axios')112vi.mock('./api/client')113```114115## Dynamic Mocking (vi.doMock)116117Not hoisted - use for dynamic imports:118119```ts120test('dynamic mock', async () => {121vi.doMock('./config', () => ({122apiUrl: 'http://test.local',123}))124125const { apiUrl } = await import('./config')126expect(apiUrl).toBe('http://test.local')127128vi.doUnmock('./config')129})130```131132## Mock Timers133134```ts135import { afterEach, beforeEach, vi } from 'vitest'136137beforeEach(() => {138vi.useFakeTimers()139})140141afterEach(() => {142vi.useRealTimers()143})144145test('timers', () => {146const fn = vi.fn()147setTimeout(fn, 1000)148149expect(fn).not.toHaveBeenCalled()150151vi.advanceTimersByTime(1000)152expect(fn).toHaveBeenCalled()153})154155// Other timer methods156vi.runAllTimers() // Run all pending timers157vi.runOnlyPendingTimers() // Run only currently pending158vi.advanceTimersToNextTimer() // Advance to next timer159```160161### Async Timer Methods162163```ts164test('async timers', async () => {165vi.useFakeTimers()166167let resolved = false168setTimeout(() => Promise.resolve().then(() => { resolved = true }), 100)169170await vi.advanceTimersByTimeAsync(100)171expect(resolved).toBe(true)172})173```174175## Mock Dates176177```ts178vi.setSystemTime(new Date('2024-01-01'))179expect(new Date().getFullYear()).toBe(2024)180181vi.useRealTimers() // Restore182```183184## Mock Globals185186```ts187vi.stubGlobal('fetch', vi.fn(() =>188Promise.resolve({ json: () => ({ data: 'mock' }) })189))190191// Restore192vi.unstubAllGlobals()193```194195## Mock Environment Variables196197```ts198vi.stubEnv('API_KEY', 'test-key')199expect(import.meta.env.API_KEY).toBe('test-key')200201// Restore202vi.unstubAllEnvs()203```204205## Clearing Mocks206207```ts208const fn = vi.fn()209fn()210211fn.mockClear() // Clear call history212fn.mockReset() // Clear history + implementation213fn.mockRestore() // Restore original (for spies)214215// Global216vi.clearAllMocks()217vi.resetAllMocks()218vi.restoreAllMocks()219```220221## Config Auto-Reset222223```ts224// vitest.config.ts225defineConfig({226test: {227clearMocks: true, // Clear before each test228mockReset: true, // Reset before each test229restoreMocks: true, // Restore after each test230unstubEnvs: true, // Restore env vars231unstubGlobals: true, // Restore globals232},233})234```235236## Hoisted Variables for Mocks237238```ts239const mockFn = vi.hoisted(() => vi.fn())240241vi.mock('./module', () => ({242getData: mockFn,243}))244245import { getData } from './module'246247test('hoisted mock', () => {248mockFn.mockReturnValue('test')249expect(getData()).toBe('test')250})251```252253## Key Points254255- `vi.mock` is hoisted - called before imports256- Use `vi.doMock` for dynamic, non-hoisted mocking257- Always restore mocks to avoid test pollution258- Use `{ spy: true }` to keep implementation but track calls259- `vi.hoisted` lets you reference variables in mock factories260261<!--262Source references:263- https://vitest.dev/guide/mocking.html264- https://vitest.dev/api/vi.html265-->266