Membangun jaring pengaman kualitas dengan testing: piramida testing, unit test dengan Vitest, component testing dengan Testing Library, dan end-to-end dengan Playwright atau Cypress — dipraktikkan pada fitur keranjang TokoKita

Semakin besar aplikasi TokoKita, semakin besar juga ketakutannya: "kalau aku mengubah ini, apa yang rusak?". Episode 13 menjawabnya dengan testing — praktik menulis kode yang memverifikasi kode lain. Di tim profesional, tidak ada perubahan signifikan yang masuk tanpa test.
Mengapa testing wajib dikuasai frontend developer? Karena test bukan hanya pengaman — ia juga dokumentasi yang bisa dieksekusi dan desain yang memaksa kalian menulis kode yang testable. Di 2026, lowongan frontend serius hampir selalu menanyakan pengalaman testing. Episode ini membangun fondasinya.
Strateginya: banyak unit test di dasar, sedikit e2e di puncak. Kalian bisa menulis semua sebagai e2e, tetapi biaya dan flaknya akan menghancurkan tim.
Vitest adalah test runner modern (berbasis Vite — episode 14) yang cepat dan terasa "native" di ekosistem.
import { describe, expect, it } from "vitest";
import { cartTotal } from "./cart";
describe("cartTotal", () => {
it("menjumlahkan harga dikali kuantitas", () => {
const items = [
{ product: { price: 85000 }, quantity: 2 },
{ product: { price: 45000 }, quantity: 1 },
];
expect(cartTotal(items)).toBe(215000);
});
it("mengembalikan 0 untuk keranjang kosong", () => {
expect(cartTotal([])).toBe(0);
});
});Fokus unit test adalah logika murni — fungsi tanpa efek samping jaringan/DOM. Jika fungsi itu sulit ditest, itu sinyal kode perlu di-refactor agar testable.
Testing Library menguji komponen dari sudut pandang pengguna: query berdasarkan teks dan role, bukan class internal.
import { render, screen } from "@testing-library/react";
import { ProductCard } from "./ProductCard";
describe("ProductCard", () => {
it("menampilkan nama dan harga produk", () => {
render(<ProductCard product={{ id: 1, name: "Kopi", price: 85000 }} />);
expect(screen.getByRole("heading", { name: "Kopi" })).toBeInTheDocument();
expect(screen.getByText("Rp85.000")).toBeInTheDocument();
});
});getByRole("heading", { name: "Kopi" }) memperlakukan komponen seperti pengguna (screen reader) — bukan seperti developer yang menghafal class CSS.
Important
Aturan emas Testing Library: jangan menguji detail implementasi. Query lewat getByTestId hanya saat tidak ada alternatif yang lebih "manusiawi". Test yang menguji inner workings menjadi rapuh dan menghambat refactor — kebalikan dari tujuan testing.
E2E menguji alur lengkap di browser nyata. Playwright menjadi pilihan utama (diikuti Cypress):
import { test, expect } from "@playwright/test";
test("user bisa menambahkan produk ke keranjang", async ({ page }) => {
await page.goto("/products/kopi-arabika");
await page.getByRole("button", { name: "Tambah ke keranjang" }).click();
await expect(page.getByRole("status")).toContainText("1 item");
});Playwright otomatis menunggu elemen (auto-waiting), berjalan multi-browser, dan punya mode video/trace untuk debugging. Idealnya e2e menutup alur kritis bisnis: checkout, login, pembayaran.
Urutan membangun test suite:
vitest untuk unit/component, @playwright/test untuk e2e.cartTotal, helper format harga, logika filter.ProductCard, CartButton (render + interaksi).bunx vitest run
bunx playwright test| Kesalahan | Dampak | Perbaikan |
|---|---|---|
| Semua test jadi e2e | Lambat & flaky | Piramida: banyak unit, sedikit e2e |
| Test detail implementasi | Rapuh saat refactor | Testing Library: test perilaku |
| Mock API berlebihan | Uji diri sendiri | Mock di batas (fetch), bukan logika |
| Tidak ada test untuk bug | Bug muncul lagi | Tulis test dulu (regression) |
| Test "satu besar" | Error tidak jelas | Test kecil per perilaku |
Inti yang harus dibawa pulang:
Di episode 14 selanjutnya kita membedah mesin di balik semua ini: build tools & bundlers — Vite, esbuild, Turbopack, dan pipeline build yang mengubah kode kalian menjadi artefak produksi. Sampai jumpa di episode 14!