Flaky Tests & Isolasi — Testing

Apa itu Flaky Test? Flaky test adalah test yang kadang lulus, kadang gagal — tanpa perubahan kode. Ini racun pelan-pelan: tim mulai mengabaikan kegagalan CI…

Apa itu Flaky Test?

Flaky test adalah test yang kadang lulus, kadang gagal — tanpa perubahan kode. Ini racun pelan-pelan: tim mulai mengabaikan kegagalan CI ("ah flaky, retry aja"), lalu bug asli lolos karena sudah terbiasa skip.

Penyebab Umum Flakiness

Fix #1: Kontrol Waktu dengan Fake Timers

import { vi, it, expect } from "vitest";

beforeEach(() => {
  vi.useFakeTimers();
  vi.setSystemTime(new Date("2025-01-15T10:00:00Z")); // deterministic
});

afterEach(() => vi.useRealTimers());

it("menampilkan 'hari ini'", () => {
  expect(formatDate(new Date())).toBe("15 Januari 2025");
});

Jangan pernah setTimeout/sleep asli di test — ganti dengan vi.advanceTimersByTime().

Fix #2: Isolasi State

// ❌ Bocor antar test
const cart = new Cart();

it("menambah item", () => { cart.add(item); expect(cart.size).toBe(1); });
it("kosong awalnya", () => { expect(cart.size).toBe(0); }); // GAGAL!

// ✅ Reset di beforeEach
let cart;
beforeEach(() => { cart = new Cart(); });

Di Laravel: RefreshDatabase bungkus tiap test dalam transaksi yang di-rollback. Pastikan cache, queue, dan static variable juga di-reset.

Fix #3: Hilangkan Network dengan Mock

// ❌ Flaky — butuh server benaran
it("fetch users", async () => {
  const users = await fetch("/api/users").then(r => r.json());
  expect(users).toHaveLength(3);
});

// ✅ Pakai MSW / Http::fake()
server.use(
  http.get("/api/users", () => HttpResponse.json([/* 3 users */]))
);

Fix #4: Deterministic Random

// ❌ Flaky
const id = Math.random();

// ✅ Seed faker di config test
fake()->seed(12345); // Laravel: FakerFactory::setDefaultSeed()
// atau suntik RNG sebagai dependency

Retry: Obat Sementara, Bukan Solusi

Playwright dan Vitest punya mekanisme retry:

// Vitest
it.retry(3)("operasi async", async () => { ... });

// Playwright — di config
export default defineConfig({
  retries: process.env.CI ? 2 : 0,
});

Peringatan: retry menyembunyikan flakiness, tidak memperbaikinya. Pakai retry hanya saat akar masalahnya di luar kendalimu (jaringan CI), dan catat test yang sering retry untuk dibenahi.

Debug Flaky Test Playwright

Root-Cause > Retry

Saat test flaky, tahan godaan untuk langsung retry. Langkah diagnosis:

  1. Reproduksi lokal dengan --repeat-each=20. Kalau hanya flaky di CI, cek perbedaan environment (timezone, resource).
  2. Identifikasi penyebab — timing, state, network?
  3. Fix akar masalah. Retry hanya dipakai untuk kasus eksternal yang benar-benar tidak bisa kamu kontrol.
  4. Tambah --repeat-each=50 di CI nightly untuk mendeteksi regresi flakiness baru.

Yang akan kamu pelajari