Belajar Playwright - Data-driven & Parameterized Testing
Episode 9 of 23

Belajar Playwright - Data-driven & Parameterized Testing

Episode ini membahas parameterized test dengan test.each, sumber data eksternal seperti CSV dan JSON, menjalankan skenario yang sama dengan banyak dataset, serta best practice agar coverage mudah diulang dan dipertahankan.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Sebagian besar bug nyata ditemukan bukan karena alur gagal total, tapi karena satu kombinasi input tertentu yang tidak terpikirkan. Episode 9 ini membahas data-driven testing: menjalankan satu skenario test dengan banyak dataset, sehingga satu definisi test bisa memverifikasi puluhan kasus — valid, tidak valid, dan tepi.

Pendekatan ini mengubah keseimbangan antara jumlah kode dan jumlah coverage. Dengan test.each, kalian menulis logika sekali dan mendorong data melalui tabel. Hasilnya: lebih sedikit duplikasi, coverage lebih luas, dan ketika aplikasi berubah, cukup perbaiki satu logika test untuk memperbaiki seluruh variannya.

Parameterized Test dengan test.each

Dasar-Dasar test.each

test.each menerima array data dan menjalankan fungsi test sekali untuk setiap baris data:

JStest.each dengan array sederhana
import { test, expect } from '@playwright/test';
 
const dataLogin = [
  { email: 'user@example.com', password: 'rahasia123', status: 'success' },
  { email: 'salah@example.com', password: 'rahasia123', status: 'failed' },
];
 
for (const data of dataLogin) {
  test(`login dengan ${data.email} menghasilkan ${data.status}`, async ({ page }) => {
    await page.goto('/login');
    await page.getByLabel('Email').fill(data.email);
    await page.getByLabel('Password').fill(data.password);
    await page.getByRole('button', { name: 'Masuk' }).click();
    if (data.status === 'success') {
      await expect(page).toHaveURL(/dashboard/);
    } else {
      await expect(page.getByText('Kredensial salah')).toBeVisible();
    }
  });
}

Perhatikan nama test yang dinamis — login dengan ${data.email} menghasilkan ${data.status}. Nama yang deskriptif membuat report mudah dibaca dan kegagalan langsung terlihat kombinasi mana yang bermasalah.

Sintaks Inline dengan Template String

Untuk dataset kecil, test.each juga bisa dipakai dengan sintaks inline di mana nilai dimasukkan ke dalam nama test:

JStest.each dengan sintaks template
test.each([
  ['admin@example.com', 'dashboard'],
  ['pengguna@example.com', 'profil'],
])('pengguna %s diarahkan ke %s', async ({ page }, email, tujuan) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill(email);
  await page.getByRole('button', { name: 'Masuk' }).click();
  await expect(page).toHaveURL(new RegExp(tujuan));
});

Sintaks %s menjadi placeholder posisi dalam nama test. Pendekatan ini ringkas untuk skenario yang sederhana, sementara for...of memberikan fleksibilitas penuh untuk struktur data yang lebih kompleks.

Sumber Data Eksternal: CSV, JSON, dan Fixtures

Data dari File JSON

Ketika dataset tumbuh besar, pisahkan data ke file eksternal agar mudah diedit tanpa menyentuh kode test:

data/login.json
[
  { "email": "user@example.com", "password": "rahasia123", "status": "success" },
  { "email": "kosong@example.com", "password": "", "status": "validation" }
]
JSMemakai data JSON dalam test
import { test, expect } from '@playwright/test';
import dataLogin from '../data/login.json';
 
for (const data of dataLogin) {
  test(`kasus login: ${data.email}`, async ({ page }) => {
    await page.goto('/login');
    await page.getByLabel('Email').fill(data.email);
    await page.getByLabel('Password').fill(data.password);
    await page.getByRole('button', { name: 'Masuk' }).click();
  });
}

import dataLogin from '../data/login.json' memuat dataset dalam bentuk array. Dengan pemisahan ini, tim non-developer pun bisa menambah kasus uji hanya dengan mengedit file JSON.

Parsing CSV

Untuk data yang sudah tersimpan dalam CSV, kalian bisa membaca dan mengurai file tersebut pada waktu test dimuat. Library csv-parse adalah pilihan yang umum dipakai, atau gunakan parser sederhana untuk format yang stabil. Data CSV cocok untuk kasus uji yang berasal dari spreadsheet atau laporan tim.

Menjalankan Skenario yang Sama dengan Banyak Dataset

Test Describes untuk Pengelompokan

Saat skenario berbeda memakai dataset berbeda, test.describe membantu mengelompokkan dan menambahkan konfigurasi bersama:

JSMengelompokkan data per skenario
test.describe('Checkout', () => {
  test.describe.configure({ mode: 'serial' });
 
  for (const metode of ['transfer', 'va', 'kartu']) {
    test(`checkout dengan metode ${metode}`, async ({ page }) => {
      await page.goto('/checkout');
      await page.getByRole('radio', { name: metode }).check();
      await page.getByRole('button', { name: 'Bayar' }).click();
      await expect(page.getByText('Pesanan dibuat')).toBeVisible();
    });
  }
});

test.describe.configure({ mode: 'serial' }) menjalankan test di dalam kelompok secara berurutan. Pengelompokan ini membuat struktur suite mencerminkan domain aplikasi, bukan sekadar daftar datar test.

Menangani State Antar Data

Satu hal yang wajib diwaspadai: test dalam satu loop berbagi konfigurasi project tapi tidak berbagi state browser — setiap test mendapat context baru. Jangan mengasumsikan urutan eksekusi antar test; setiap kasus data harus berdiri sendiri dan menyiapkan prasyaratnya masing-masing.

Best Practice untuk Coverage yang Dapat Diulang

Prinsip Setiap Dataset Independen

Aturan emas data-driven testing: setiap baris data harus bisa dijalankan sendiri tanpa bergantung pada baris lain. Jika satu kasus bergantung pada kasus sebelumnya, suite akan rapuh dan sulit diparalelkan.

Memilih Kasus Tepi yang Bernilai

Lebih baik sedikit dataset yang relevan daripada banyak dataset yang berlebihan. Pilih kombinasi yang memaksimalkan coverage:

  • Satu kasus valid (happy path).
  • Satu kasus input kosong atau melewati batas.
  • Satu kasus format salah atau karakter khusus.
  • Satu kasus data duplikat yang memicu error bisnis.
Jalankan hanya subset data
npx playwright test -g "login"

Perintah npx playwright test -g "login" menjalankan test yang namanya mengandung kata login — cara cepat menjalankan subset data-driven suite saat mengembangkan fitur baru.

Menjaga Readability Report

Karena satu skenario menghasilkan banyak test, nama test harus memuat nilai data yang membedakannya. Hindari nama generik seperti test data ke-1; sertakan nilai kunci (email, metode pembayaran, status) agar report langsung bercerita.

Penutup

Episode 9 mengajarkan cara memperluas coverage tanpa melipatgandakan kode: test.each dan loop for...of mengubah satu skenario menjadi banyak kasus data, sumber data eksternal JSON dan CSV memisahkan data dari logika, dan prinsip independensi menjamin suite tetap paralel dan mudah dirawat.

Inti yang harus dibawa pulang:

  • test.each menjalankan satu skenario untuk banyak dataset dengan satu definisi test.
  • Nama test dinamis memuat nilai data agar report mudah dibaca.
  • Pindahkan dataset besar ke file JSON atau CSV yang terpisah dari kode.
  • Setiap baris data harus independen dan bisa dijalankan sendiri.
  • Fokus pada kasus tepi yang bernilai, bukan jumlah dataset semata.

Di episode 10 selanjutnya kita akan membahas cross-browser dan device testing — menjalankan test di Chromium, Firefox, dan WebKit, browser contexts dengan mobile emulation dan geolocation, pengujian responsive layout, serta penggunaan real device clouds.