Belajar Playwright - Speed & Reliability Optimization
Episode 15 of 23

Belajar Playwright - Speed & Reliability Optimization

Episode ini membahas optimasi runtime dan paralelisme test, reuse contexts dan fixtures dengan selective retries, pengurangan flaky tests lewat stable locators, serta penggunaan test.fixme dan test.skip secara strategis.

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

Pendahuluan

Test suite yang lambat membuat tim menghindarinya; test suite yang flaky membuat tim tidak mempercayainya. Episode 15 ini membahas dua masalah sekaligus: bagaimana membuat suite lebih cepat dan bagaimana membuatnya lebih andal — dua kualitas yang harus berjalan bersama.

Kecepatan dicapai dengan paralelisme yang tepat, reuse resource, dan menghindari pekerjaan berulang. Keandalan dicapai dengan locator yang stabil dan strategi skip yang jujur. Kalian akan belajar mengukur dan mengoptimalkan keduanya secara sistematis.

Mengoptimalkan Test Runtime dan Parallelism

Mengukur Waktu per Test

Langkah pertama optimasi adalah mengetahui ke mana waktu pergi. Report list menampilkan durasi tiap test:

Lihat durasi per test
npx playwright test --reporter=list

--reporter=list menampilkan durasi tiap test. Identifikasi test yang paling lambat — mereka adalah kandidat utama optimasi. Sering kali beberapa test menyumbang sebagian besar total runtime.

Menemukan Hotspot dengan Trace

Untuk test yang lambat, buka trace dan amati bagian Network dan Timing. Sering penyebabnya adalah waitForTimeout yang panjang, navigasi yang tidak perlu, atau request yang lambat. Ganti sleep dengan menunggu kondisi, seperti yang sudah kita bahas di episode 5.

Mengatur Paralelisme dengan Bijak

Paralelisme membantu, tapi dengan batasan:

JSBatasi worker sesuai resource
export default defineConfig({
  workers: process.env.CI ? 4 : undefined,
});

workers: process.env.CI ? 4 : undefined memakai default di lokal dan membatasi 4 worker di CI. Terlalu banyak worker membuat CPU jenuh dan justru memperlambat; temukan jumlah optimal dengan mengukur.

Reuse Contexts, Fixtures, dan Selective Retries

Storage State untuk Memotong Waktu Login

Salah satu penghemat waktu terbesar adalah menghindari login berulang. Storage state yang kita bahas di episode 13 bisa dipakai ulang di banyak test:

JSSiapkan fixture login sekali
import { test as base } from '@playwright/test';
 
export const test = base.extend({
  page: async ({ page }, use) => {
    await page.goto('/beranda');
    await page.getByRole('button', { name: 'Masuk' }).click();
    await use(page);
  },
});

Fixture kustom page menjalankan setup (di sini, login) untuk setiap test yang memintanya. Setup sekali, dipakai banyak test — mengurangi runtime total secara signifikan.

Selective Retries, Bukan Retry Seragam

Retries di semua test membuang waktu pada test yang memang stabil. Sebaliknya, berikan retry hanya pada test yang dikenal flaky karena faktor eksternal:

JSRetry selektif
test('pembayaran dengan provider eksternal', async ({ page }) => {
  test.info().annotations.push({
    type: 'issue',
    description: 'Sering timeout karena provider pihak ketiga',
  });
  test.setTimeout(60000);
});

test.setTimeout(60000) memberi test tertentu waktu eksekusi lebih panjang tanpa mempengaruhi test lain. Gabungkan dengan retries di level project untuk menyeimbangkan kecepatan dan keandalan.

Reducing Flaky Tests dengan Stable Locators

Prinsip Stable Locator

Sebagian besar flaky test berakar pada locator yang rapuh — selector yang bergantung pada struktur DOM yang berubah-ubah. Prioritas locator yang benar:

  1. getByRole dengan accessible name — paling stabil karena berbasis makna.
  2. getByLabel untuk input form.
  3. getByText dan getByPlaceholder untuk konten.
  4. CSS atau XPath sebagai pilihan terakhir.
JSHindari CSS yang rapuh
await page.locator('#sidebar > div:nth-child(3) > button').click();
JSLebih stabil dengan role
await page.getByRole('button', { name: 'Simpan' }).click();

Locator berbasis getByRole('button', { name: 'Simpan' }) tidak patah saat markup berubah selama aksesibilitas namanya dipertahankan.

Test-ID sebagai Kontrak

Untuk elemen interaktif yang penting, tambahkan data-testid di aplikasi dan jadikan itu kontrak antara developer dan test:

JSLocator dengan data-testid
await page.getByTestId('submit-order').click();

getByTestId('submit-order') mencari atribut data-testid secara default. Test-ID sengaja dibuat stabil — perubahan tampilan tidak mempengaruhinya, hanya perubahan nama testid yang memengaruhinya.

Menggunakan test.fixme dan test.skip Secara Strategis

test.skip untuk Fitur yang Belum Ada

Jangan biarkan test untuk fitur yang belum diimplementasikan membuat suite merah:

JSSkip test untuk fitur belum ada
test.skip('export data belum tersedia', async ({ page }) => {
  await page.goto('/laporan');
  await page.getByRole('button', { name: 'Export' }).click();
});

test.skip(...) menandai test untuk dilewati, dengan catatan jelas di report. Ini menjaga suite hijau sambil mendokumentasikan bahwa ada kontrak yang belum dipenuhi.

test.fixme untuk Masalah yang Diketahui

test.fixme menunjukkan bahwa test itu benar tapi aplikasi sedang bermasalah — bersifat sementara dan harus segera diperbaiki:

JSTandai test bermasalah
test.fixme('logout setelah token expired', async ({ page }) => {
  await page.goto('/profil');
  await expect(page).toHaveURL(/login/);
});

test.fixme(...) menandai test sebagai known issue — akan dilewati tapi terdaftar jelas. Bedanya dengan skip: fixme adalah alarm yang harus diselesaikan, bukan kondisi permanen.

Menghindari Skip yang Menumpuk

Skip dan fixme adalah alat disiplin, bukan jalan pintas. Tinjau secara berkala: setiap sprint, audit berapa banyak test yang di-skip dan kenapa. Test yang terus di-skip tanpa alasan jelas adalah sinyal bahwa coverage sedang bocor diam-diam.

Lihat daftar test dan status
npx playwright test --list

npx playwright test --list menampilkan semua test termasuk yang di-skip dan di-fixme — alat cepat untuk audit kondisi suite.

Penutup

Episode 15 mengajarkan optimasi yang seimbang: mengukur durasi untuk menemukan hotspot, memakai storage state dan fixtures untuk memotong setup berulang, retries selektif untuk test yang memang butuh, locator stabil untuk menumpas flakiness, dan skip serta fixme yang jujur untuk menjaga suite tetap bermakna.

Inti yang harus dibawa pulang:

  • Ukur durasi per test dengan reporter list untuk menemukan hotspot.
  • Storage state dan fixtures memotong setup berulang secara signifikan.
  • Prioritaskan getByRole dan getByLabel untuk locator yang stabil.
  • getByTestId menciptakan kontrak yang tidak patah oleh perubahan tampilan.
  • test.skip dan test.fixme harus ditinjau secara berkala.

Di episode 16 selanjutnya kita akan membahas visual regression testing — menangkap baseline screenshot, membandingkan visual diff dengan toHaveScreenshot, menoleransi layout drift dengan thresholding, serta integrasi dengan tool visual regression.

Belajar Playwright - Speed & Reliability Optimization | Belajar Playwright