Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як підміняти модулі, таймери й fetch у тестах Vitest: vi.fn, vi.spyOn, vi.mock і фейкові таймери?

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. Якщо в тесті замоковано все, він перевіряє лише те, що моки викликаються, а не те, що код працює.

Докладніше в документації: Vitest: моки

Схожі питання