docs/guide/mocking.md
::: tip
New to mocking? Start with the Mock Functions tutorial for a hands-on introduction to vi.fn, vi.spyOn, and vi.mock.
:::
When writing tests it's only a matter of time before you need to create a "fake" version of an internal — or external — service. This is commonly referred to as mocking. Vitest provides utility functions to help you out through its vi helper. You can import it from vitest or access it globally if global configuration is enabled.
::: warning
Always remember to clear or restore mocks before or after each test run to undo mock state changes between runs! See mockReset docs for more info.
:::
If you are not familiar with vi.fn, vi.mock or vi.spyOn methods, check the API section first.
Vitest has a comprehensive list of guides regarding mocking:
For a simpler and quicker way to get started with mocking, you can check the Cheat Sheet below.
I want to…
export const getter = 'variable'
import * as exports from './example.js'
vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked')
::: warning This will not work in the Browser Mode. For a workaround, see Limitations. :::
vi.mock:::: warning
Don't forget that a vi.mock call is hoisted to top of the file. It will always be executed before all imports.
:::
export function method() {}
import { method } from './example.js'
vi.mock('./example.js', () => ({
method: vi.fn()
}))
vi.spyOn:import * as exports from './example.js'
vi.spyOn(exports, 'method').mockImplementation(() => {})
::: warning
vi.spyOn example will not work in the Browser Mode. For a workaround, see Limitations.
:::
class:export class SomeClass {}
import { SomeClass } from './example.js'
vi.mock(import('./example.js'), () => {
const SomeClass = vi.fn(class FakeClass {
someMethod = vi.fn()
})
return { SomeClass }
})
vi.spyOn:import * as mod from './example.js'
vi.spyOn(mod, 'SomeClass').mockImplementation(class FakeClass {
someMethod = vi.fn()
})
::: warning
vi.spyOn example will not work in the Browser Mode. For a workaround, see Limitations.
:::
export function useObject() {
return { method: () => true }
}
import { useObject } from './example.js'
const obj = useObject()
obj.method()
import { useObject } from './example.js'
vi.mock(import('./example.js'), () => {
let _cache
const useObject = () => {
if (!_cache) {
_cache = {
method: vi.fn(),
}
}
// now every time that useObject() is called it will
// return the same object reference
return _cache
}
return { useObject }
})
const obj = useObject()
// obj.method was called inside some-path
expect(obj.method).toHaveBeenCalled()
import { mocked, original } from './some-path.js'
vi.mock(import('./some-path.js'), async (importOriginal) => {
const mod = await importOriginal()
return {
...mod,
mocked: vi.fn()
}
})
original() // has original behaviour
mocked() // is a spy function
::: warning
Don't forget that this only mocks external access. In this example, if original calls mocked internally, it will always call the function defined in the module, not in the mock factory.
:::
To mock Date's time, you can use vi.setSystemTime helper function. This value will not automatically reset between different tests.
Beware that using vi.useFakeTimers also changes the Date's time.
const mockDate = new Date(2022, 0, 1)
vi.setSystemTime(mockDate)
const now = new Date()
expect(now.valueOf()).toBe(mockDate.valueOf())
// reset mocked time
vi.useRealTimers()
You can set global variable by assigning a value to globalThis or using vi.stubGlobal helper. When using vi.stubGlobal, it will not automatically reset between different tests, unless you enable unstubGlobals config option or call vi.unstubAllGlobals.
vi.stubGlobal('__VERSION__', '1.0.0')
expect(__VERSION__).toBe('1.0.0')
import.meta.env::: warning The environmental variable value will not automatically reset between different tests. :::
import { beforeEach, expect, it } from 'vitest'
// you can reset it in beforeEach hook manually
const originalViteEnv = import.meta.env.VITE_ENV
beforeEach(() => {
import.meta.env.VITE_ENV = originalViteEnv
})
it('changes value', () => {
import.meta.env.VITE_ENV = 'staging'
expect(import.meta.env.VITE_ENV).toBe('staging')
})
vi.stubEnv helper with the unstubEnvs config option enabled (or call vi.unstubAllEnvs manually in a beforeEach hook):import { expect, it, vi } from 'vitest'
// before running tests "VITE_ENV" is "test"
import.meta.env.VITE_ENV === 'test'
it('changes value', () => {
vi.stubEnv('VITE_ENV', 'staging')
expect(import.meta.env.VITE_ENV).toBe('staging')
})
it('the value is restored before running an other test', () => {
expect(import.meta.env.VITE_ENV).toBe('test')
})
export default defineConfig({
test: {
unstubEnvs: true,
},
})