Episode ini mengupas mekanisme auto-waiting default Playwright, eksplisit wait dengan waitForResponse dan waitForLoadState, cara menangani konten dinamis dan update asinkron, serta strategi menjaga stabilitas test untuk aplikasi SPA dan real-time.

Salah satu penyebab terbesar test end-to-end gagal adalah masalah timing: elemen belum muncul saat aksi dijalankan, atau response belum kembali saat assertion dicek. Episode 5 ini membahas bagaimana Playwright menyelesaikan masalah ini secara otomatis, dan kapan kalian perlu menambahkan kontrol waktu secara eksplisit.
Filosofi Playwright sederhana: test tidak boleh bergantung pada guess timing. Semua mekanisme — auto-waiting, eksplisit wait, dan assertion yang retry-able — dirancang untuk menggantikan sleep acak yang sering dipakai di framework lama. Setelah episode ini, kalian akan tahu kapan cukup percaya pada default, dan kapan harus turun tangan.
Saat kalian memanggil click() atau fill(), Playwright menjalankan rangkaian pengecekan secara otomatis:
Hanya jika semua kondisi terpenuhi, aksi dieksekusi. Jika tidak, Playwright menunggu sampai batas waktu dan memberikan pesan timeout yang deskriptif.
Hal yang sama berlaku untuk assertion. expect(page.getByRole('button')).toBeVisible() tidak hanya mengecek sekali — dia menunggu hingga kondisi terpenuhi atau timeout expect.timeout tercapai. Inilah yang membuat test Playwright terasa tenang dibanding framework yang melempar error langsung.
Saat kalian butuh menunggu response dari request tertentu, pasang listener sebelum memicu aksi:
import { test, expect } from '@playwright/test';
test('menunggu response login', async ({ page }) => {
const responsePromise = page.waitForResponse(
(response) => response.url().includes('/api/login') &&
response.status() === 200
);
await page.getByRole('button', { name: 'Masuk' }).click();
const response = await responsePromise;
expect(response.ok()).toBeTruthy();
});page.waitForResponse() mengembalikan promise yang selesai saat response yang cocok tiba. Pola set listener dulu, baru aksi ini menghindari race condition klasik.
Untuk menunggu tahap loading halaman:
await page.goto('/produk');
await page.waitForLoadState('networkidle');
await page.waitForLoadState('domcontentloaded');Perlu diingat: networkidle dianggap tidak stabil untuk aplikasi yang terus menerus melakukan polling, karena network-nya tidak pernah benar-benar idle.
page.waitForTimeout() adalah jalur terakhir yang sebaiknya dihindari:
await page.waitForTimeout(3000);Alih-alih menebak waktu, tunggu kondisi yang menandakan konten muncul:
await expect(page.getByText('Pembayaran berhasil')).toBeVisible();
await expect(page.locator('.spinner')).toHaveCount(0);Menunggu elemen hasil — atau elemen loading yang hilang — jauh lebih deterministik daripada menebak durasi. Jika satu kondisi saja bisa dipantau, selalu pilih itu.
Untuk kasus di luar assertion, waitForSelector masih bisa dipakai:
await page.waitForSelector('#data-produk', { state: 'visible' });page.waitForSelector('#data-produk', { state: 'visible' }) menunggu elemen dengan state tertentu. Dalam banyak kasus, assertion berbasis locator lebih disarankan karena sekaligus memverifikasi — gunakan waitForSelector untuk logika non-assertion.
Aplikasi SPA (Single Page Application) dan aplikasi real-time — chat, dashboard live, notifikasi push — memicu masalah unik: DOM berubah terus-menerus, jaringan tidak pernah idle, dan konten muncul asinkron tanpa reload halaman. Test yang memakai sleep atau mengandalkan load event akan mudah patah.
Gunakan pola berikut untuk aplikasi dinamis:
npx playwright test --reporter=listnpx playwright test --reporter=list menampilkan durasi setiap test secara berurutan. Test yang sering mengalami timeout dekat batas adalah kandidat untuk investigasi sinkronisasi lebih lanjut.
Episode 5 menjelaskan mengapa Playwright jarang kalah melawan timing: auto-waiting default memastikan elemen actionable sebelum aksi, assertion bersifat retry-able, dan waitForResponse serta waitForLoadState memberi kendali eksplisit saat dibutuhkan. Untuk konten dinamis dan aplikasi real-time, kuncinya adalah menunggu kondisi, bukan menebak waktu.
Inti yang harus dibawa pulang:
waitForResponse sebelum memicu aksi untuk menghindari race condition.waitForTimeout dengan menunggu elemen hasil atau elemen loading hilang.networkidle pada aplikasi yang terus menerus polling.Di episode 6 selanjutnya kita akan membahas page object model dan test structure — mengorganisasi test dengan pola Page Object, membuat reusable page classes dan helper methods, menangani multi-page flows dan shared fixtures, serta menjaga maintainability dan readability test suite.