Panduan Praktis Testing di React dengan Vitest dan React Testing Library
Testing React bukan harus menyiksa. Dengan Vitest dan React Testing Library, kamu bisa menulis test yang bermakna dan cepat dalam waktu singkat.
Filosofi React Testing Library
RTL dibangun di atas satu prinsip: test your components the way users use them. Bukan test implementasi internal (state, lifecycle) — tapi test perilaku yang terlihat: apa yang dirender, apa yang terjadi saat user berinteraksi.
Setup Vitest + RTL di Project Vite/React
npm install -D vitest @testing-library/react @testing-library/user-event @testing-library/jest-dom jsdom
Update vite.config.ts:
export default defineConfig({
plugins: [react()],
test: {
environment: "jsdom",
setupFiles: ["./src/test/setup.ts"],
globals: true,
},
});
Buat file src/test/setup.ts:
import "@testing-library/jest-dom";
Test Pertama: Komponen Sederhana
// src/components/Greeting.tsx
export function Greeting({ name }: { name: string }) {
return Halo, {name}!
;
}
// src/components/Greeting.test.tsx
import { render, screen } from "@testing-library/react";
import { Greeting } from "./Greeting";
test("menampilkan nama dengan benar", () => {
render( );
expect(screen.getByRole("heading", { name: /halo, khalim/i })).toBeInTheDocument();
});
Test Interaksi User
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Counter } from "./Counter";
test("counter bertambah saat tombol diklik", async () => {
const user = userEvent.setup();
render( );
const button = screen.getByRole("button", { name: /tambah/i });
const count = screen.getByText(/hitungan: 0/i);
await user.click(button);
expect(screen.getByText(/hitungan: 1/i)).toBeInTheDocument();
});
Test Async: Fetch Data
import { render, screen, waitFor } from "@testing-library/react";
import { vi } from "vitest";
import { UserList } from "./UserList";
// Mock fetch
global.fetch = vi.fn(() =>
Promise.resolve({ ok: true, json: () => Promise.resolve([{ id: 1, name: "Khalim" }]) })
) as any;
test("menampilkan daftar user setelah loading", async () => {
render( );
expect(screen.getByText(/memuat/i)).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText("Khalim")).toBeInTheDocument();
});
});
Query yang Paling Direkomendasikan
Prioritas query dari yang paling direkomendasikan RTL:
getByRole— paling accessible, paling dekat ke cara user melihat halaman.getByLabelText— untuk form elements.getByPlaceholderText— jika tidak ada label.getByText— untuk konten teks.getByTestId— pilihan terakhir jika tidak ada cara lain.
Jalankan Test
npx vitest # watch mode
npx vitest run # sekali jalan
npx vitest --coverage # dengan laporan coverage