Fixture Dulu, Spec Kemudian: Satu Login Buat Semua Test
Satu fixture login dan satu fixture bukti ditulis sebelum spesifikasi pertama, lengkap dengan jebakan aria-label yang membuat getByLabel salah sasaran.
Ringkasan
Gue nambahin Task 0 buat bikin fixture reusable sebelum nulis spec biar nggak refaktor belakangan. Daripada nambah data-testid, login ngambil dari komponen asli pakai getByLabel Email dan Kata sandi pakai exact true biar nggak ketuker tombol Tampilkan kata sandi. Jadinya cuma ada loginAsAdmin dan evidence di satu file, sengaja nggak pakai auth setup karena test admin saling ngerubah status server.
Hari itu saya membuka docs/superpowers/plans/2026-10-09-qa-backfill-fase0-routing-admin.md. Rencana itu baru saja menampung tiga alur kerja: baseline Fase 0, audit routing, dan QA dashboard admin. Sebelum satu spesifikasi pengujian pun ditulis, saya menambahkan entri yang tidak ada di rencana semula: Task 0, fondasi test reusable. Urutannya bukan detail kecil. Kalau fixture menyusul setelah spesifikasi kelima, yang terjadi bukan pembuatan fixture, melainkan refaktor yang terlambat.
Tebakan saya justru berkebalikan. Saya sempat yakin kunci kestabilan lokator adalah menambahkan data-testid ke formulir login, lalu semua spec tinggal memanggilnya. Formulir itu nyatanya tidak punya satu pun. Menambah atribut ke komponen produksi demi pengujian juga salah arah: halaman berubah karena test, bukan karena kebutuhan pengguna.
Baca lokator dari komponen nyata
Solusinya datang dari membaca komponen login itu sendiri, bukan menebak. Formulir memakai label Email dan Kata sandi, dengan tombol submit ber-teks Masuk. Dokumentasi Playwright memang menganjurkan atribut yang menghadap pengguna dan kontrak eksplisit [2], dan getByLabel dipakai untuk menemukan kontrol formulir dari teks labelnya [2].
Ada satu jebakan yang membuat baris ini berbeda dari copy-paste biasa. getByLabel juga mencocokkan atribut aria-label, dan mode default-nya bukan kecocokan utuh: opsi exact berarti kecocokan yang sensitif huruf dan utuh-kalimat, dengan nilai default false [6]. Tombol pengalih kata sandi di formulir itu membawa aria-label berisi Tampilkan kata sandi, yang memuat label bidang Kata sandi sebagai bagiannya. Tanpa { exact: true }, kandidat elemennya bertambah dan pengujian bisa mengisi bidang yang salah. Aturan praktisnya: pilih label paling pendek, lalu kuncikan dengan exact.
Dua fungsi, satu berkas
Kodenya berdiri di frontend/e2e/support/fixtures.ts dan hanya berisi dua fungsi.
import { expect, type Page } from "@playwright/test";
// Reusable admin login untuk semua spec baru. Selector diverifikasi
// terhadap komponen login nyata, bukan tebakan.
export async function loginAsAdmin(page: Page) {
await page.goto("/admincms");
await page.getByLabel("Email", { exact: true }).fill("<ADMIN_DEV_EMAIL>");
await page.getByLabel("Kata sandi", { exact: true }).fill("<ADMIN_DEV_PASSWORD>");
await page.getByRole("button", { name: "Masuk" }).click();
await expect(page).toHaveURL(/admincms/);
}
// Bukti screenshot QA, selalu ke satu direktori yang sama.
export async function evidence(page: Page, name: string) {
await page.screenshot({
path: `../scripts/unit_testing/screenshots/qa-backfill/${name}.png`,
fullPage: true,
});
}
loginAsAdmin menangani navigasi, pengisian, dan klik masuk. evidence menyimpan tangkapan layar penuh halaman [4] ke satu direktori, supaya bukti tidak tersebar di folder spec masing-masing. Keduanya dipakai oleh setiap spec baru. Spec lama tetap memakai helper miliknya sendiri, sesuai catatan yang saya tulis di scripts/unit_testing/README.md. Batas itu penting: menyatukan helper spec lama berarti menyentuh kode yang sudah stabil tanpa alasan QA.
Di rencana, aturan fixture ikut terkunci bersama kewajiban lain. Setiap task yang menghasilkan kode wajib melewati tinjauan keamanan dan tinjauan kode atas diff task itu sebelum commit, sedangkan task dokumentasi dibebaskan. Fixture masuk kategori pertama, karena ia kode yang dipakai banyak spec.
Helper biasa atau auth.setup.ts
Playwright punya jalur resmi yang lebih hemat: simpan status autentikasi sekali, lalu tiap test langsung dalam keadaan masuk. Dokumen resminya menyebut test dapat memuat status autentikasi yang sudah ada, sehingga autentikasi tidak perlu diulang di setiap test [3]. Ada dua syaratnya. File status itu bisa berisi kuki dan header sensitif, jadi jangan pernah masuk ke repositori [3], dan login sekali untuk semua test paling aman bila test-test itu tidak saling mengubah status di server dengan akun yang sama [3].
Proyek ini memilih helper biasa. Alasannya bukan kemalasan: test admin memang memutasikan status di server dengan satu akun, persis kondisi yang membuat setup bersama berisiko. Upstream sendiri mengakui sedikit duplikasi masih wajar selama test tetap jelas dan mudah dirawat [5], dan prinsip fixture tetap jadi pegangan: fixture menata lingkungan tiap test, memberi test apa yang dibutuhkan dan tidak lebih [1].
Keputusan yang saya ambil: satu berkas helper, dan spec baru tidak boleh menulis baris login sendiri. Sisanya cuma soal waktu. Begitu jumlah spec naik dan login mulai terasa sebagai jeda, jalur auth.setup.ts tinggal diambil tanpa mengubah aturan mainnya.
Sumber
[1] Playwright docs: Fixtures
[2] Playwright docs: Locators
[3] Playwright docs: Authentication
[4] Playwright docs: Screenshots
[5] Playwright docs: Best Practices
[6] Playwright docs source: locator getByLabel / exact option