Tantangan Testing Async
Kode asinkron (async/await, Promise, setTimeout) membutuhkan penanganan khusus saat testing. Tanpa penanganan yang benar, test bisa selesai sebelum operasi async selesai — menghasilkan false positive.
Testing Async/Await
Cara paling sederhana: tandai callback test sebagai async dan gunakan await:
import { describe, it, expect } from "vitest";
async function ambilData() {
const response = await fetch("/api/data");
return response.json();
}
it("mengambil data dari API", async () => {
const data = await ambilData();
expect(data).toBeDefined();
expect(data.status).toBe("ok");
});
resolves & rejects Matcher
Untuk test yang lebih ekspresif terhadap Promise:
function ambilNama(id) {
if (id === 1) return Promise.resolve("Budi");
return Promise.reject(new Error("User tidak ditemukan"));
}
it("resolve dengan nama yang benar", async () => {
await expect(ambilNama(1)).resolves.toBe("Budi");
});
it("reject jika user tidak ditemukan", async () => {
await expect(ambilNama(99)).rejects.toThrow("User tidak ditemukan");
});
Fake Timers
Untuk kode yang menggunakan setTimeout, setInterval, atau Date:
import { vi, it, expect, beforeEach, afterEach } from "vitest";
function delayedGreeting(callback) {
setTimeout(() => {
callback("Halo!");
}, 3000);
}
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
it("memanggil callback setelah 3 detik", () => {
const callback = vi.fn();
delayedGreeting(callback);
expect(callback).not.toHaveBeenCalled();
vi.advanceTimersByTime(3000);
expect(callback).toHaveBeenCalledWith("Halo!");
});
Mocking Fetch / API Calls
import { vi, it, expect } from "vitest";
// Mock global fetch
global.fetch = vi.fn();
it("menangani response API", async () => {
const mockResponse = { users: [{ id: 1, nama: "Budi" }] };
fetch.mockResolvedValueOnce({
ok: true,
json: async () => mockResponse,
});
const response = await fetch("/api/users");
const data = await response.json();
expect(fetch).toHaveBeenCalledWith("/api/users");
expect(data.users).toHaveLength(1);
});
waitFor Pattern
Untuk menunggu kondisi tertentu terpenuhi (sering dipakai dengan testing library):
import { waitFor } from "@testing-library/react";
it("menampilkan data setelah loading", async () => {
render(<UserList />);
// Tunggu sampai elemen muncul
await waitFor(() => {
expect(screen.getByText("Budi")).toBeInTheDocument();
});
});
Tips Testing Async
- Selalu
awaitassertion async — tanpa await, test bisa pass padahal seharusnya fail - Gunakan
vi.useFakeTimers()untuk timer — jangan pernah pakaisetTimeoutasli di test - Reset mock setelah setiap test dengan
vi.restoreAllMocks()