Базовая идея
Верни или await асинхронную работу — иначе runner не знает, когда тест закончился. Проверяй и fulfilled, и rejected пути.
Правила
- Контролируй зависимости (не ходи в реальную сеть в unit).
- Для таймеров — fake timers, не
sleep.
- После теста восстанавливай timers, mocks, listeners, серверы.
import { it, expect, vi } from "vitest";
it("ретраит один раз при 503", async () => {
const fetchFn = vi
.fn()
.mockResolvedValueOnce({ status: 503 })
.mockResolvedValueOnce({ status: 200, json: async () => ({ ok: true }) });
const data = await fetchWithRetry("/api", { fetchFn });
expect(data.ok).toBe(true);
expect(fetchFn).toHaveBeenCalledTimes(2);
});
it("срабатывает debounce", () => {
vi.useFakeTimers();
const fn = vi.fn();
const d = debounce(fn, 300);
d();
d();
vi.advanceTimersByTime(300);
expect(fn).toHaveBeenCalledOnce();
vi.useRealTimers();
});
Vitest/Jest/Mocha поддерживают Promise/async. Callback + done — для legacy API.
Итог: await промис, фейковые таймеры, чистый teardown — без произвольных sleep.