Testing Kode Asinkron — Testing

Tantangan Testing Async Kode asinkron (async/await, Promise, setTimeout) membutuhkan penanganan khusus saat testing. Tanpa penanganan yang benar, test bisa sele

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

Yang akan kamu pelajari