vi.fn() - функція-шпигун: запам'ятовує виклики й може повертати задане значення.
const onSave = vi.fn();
saveForm({ name: 'Олена' }, onSave);
expect(onSave).toHaveBeenCalledOnce();
expect(onSave).toHaveBeenCalledWith({ name: 'Олена' });
vi.spyOn() - стежити за методом існуючого об'єкта чи підмінити його:
const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
// ...
expect(spy).toHaveBeenCalled();
vi.mock() - замінити весь модуль:
import { getRates } from './api';
import { convert } from './converter';
vi.mock('./api', () => ({
getRates: vi.fn().mockResolvedValue({ USD: 41.5 }),
}));
it('конвертує за курсом', async () => {
expect(await convert(100, 'USD')).toBe(4150);
});
vi.mock піднімається на початок файлу - він виконується до імпортів, навіть якщо записаний нижче. Тому всередині фабрики не можна використовувати змінні з файлу: для цього є vi.hoisted().
fetch - підмінити глобальну функцію:
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ id: 1 }),
}));
Для багатьох запитів зручніше MSW (Mock Service Worker): він перехоплює запити на мережевому рівні, і код працює зі справжнім fetch.
Фейкові таймери - не чекати по-справжньому:
it('зберігає чернетку через 2 секунди', () => {
vi.useFakeTimers();
const save = vi.fn();
const autosave = debounce(save, 2000);
autosave('текст');
vi.advanceTimersByTime(1999);
expect(save).not.toHaveBeenCalled();
vi.advanceTimersByTime(1);
expect(save).toHaveBeenCalledWith('текст');
vi.useRealTimers();
});
vi.setSystemTime(new Date('2026-10-04')) фіксує «поточну» дату - для коду, що залежить від Date.now().
Прибирати за собою: моки, що «протікають» між тестами, - головна причина тестів, які падають лише в певному порядку:
afterEach(() => {
vi.restoreAllMocks();
vi.unstubAllGlobals();
});
Або в конфігурації: restoreMocks: true.
Міра: мокайте межі системи - мережу, час, сховище, сторонні SDK. Якщо в тесті замоковано все, він перевіряє лише те, що моки викликаються, а не те, що код працює.