Vitest Cheatsheet
Spies
Use this Vitest reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
vi.spyOn() — Spy on Existing Methods
import { vi, expect } from 'vitest' const obj = { greet(name: string) { return `Hello, ${name}!` }, } const spy = vi.spyOn(obj, 'greet') obj.greet('Alice') expect(spy).toHaveBeenCalledWith('Alice') expect(spy).toHaveBeenCalledTimes(1) spy.mockRestore() // restore original
Spy vs Mock
vi.fn() | vi.spyOn() | |
|---|---|---|
| Creates from scratch | Yes | No |
| Wraps existing method | No | Yes |
| Calls through by default | No (returns undefined) | Yes (original runs) |
Supports .mockRestore() | No-op | Yes — restores original |
Spying Without Calling Through
const spy = vi.spyOn(obj, 'greet').mockReturnValue('Mocked!') obj.greet('Bob') // returns 'Mocked!', original NOT called
Spying on Module Exports
import * as mathModule from './math' const spy = vi.spyOn(mathModule, 'add') spy.mockImplementation((a, b) => a * b) // spy replaces add with multiply mathModule.add(2, 3) // returns 6, not 5 expect(spy).toHaveBeenCalledWith(2, 3) spy.mockRestore()
Requires the module to export as a mutable namespace (works with
* as ...imports in ESM).
Spying on Class Methods
class Logger { log(msg: string) { console.log(msg) } } const logger = new Logger() const spy = vi.spyOn(logger, 'log') logger.log('test') expect(spy).toHaveBeenCalledWith('test') spy.mockRestore()
Static methods:
const spy = vi.spyOn(Logger, 'create')
Spying on console
it('logs a warning', () => { const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) myFunction() // internally calls console.warn(...) expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('deprecated')) consoleSpy.mockRestore() })
Spying on Getters and Setters
const obj = { _value: 0 } Object.defineProperty(obj, 'value', { get() { return this._value }, set(v) { this._value = v }, configurable: true, }) const getSpy = vi.spyOn(obj, 'value', 'get').mockReturnValue(42) expect(obj.value).toBe(42) getSpy.mockRestore()
Checking Spy State
const spy = vi.spyOn(obj, 'method') obj.method('a', 'b') obj.method('c') spy.mock.calls // [['a', 'b'], ['c']] spy.mock.results // [{ type: 'return', value: ... }, ...] spy.mock.lastCall // ['c'] spy.mock.instances // [obj, obj]
One-Time Override then Pass-Through
const spy = vi.spyOn(api, 'fetchData') .mockResolvedValueOnce({ data: 'cached' }) // first call: fake // second call: real implementation runs await api.fetchData() // { data: 'cached' } await api.fetchData() // real network call
Tracking Return Values
const spy = vi.spyOn(obj, 'compute') obj.compute(5) obj.compute(10) spy.mock.results // [ // { type: 'return', value: 25 }, // { type: 'return', value: 100 }, // ]
When the spy throws:
// { type: 'throw', value: Error('...') }Restoring All Spies
afterEach(() => { vi.restoreAllMocks() })
Or in config:
export default defineConfig({ test: { restoreMocks: true } })
Spy on Async Methods
const spy = vi.spyOn(service, 'getData').mockResolvedValue({ result: 'ok' }) const data = await service.getData() expect(data).toEqual({ result: 'ok' }) expect(spy).toHaveBeenCalledTimes(1)
Checking Not Called
const spy = vi.spyOn(obj, 'expensiveOp') doSomethingCheap() expect(spy).not.toHaveBeenCalled()