Belajar Playwright - API Testing & Network Interception
Episode 12 of 23

Belajar Playwright - API Testing & Network Interception

Episode ini membahas mocking API response dengan route interception, menguji offline mode dan network failures, memvalidasi perilaku backend melalui alur UI, serta integrasi dengan API test tools dan service mocks.

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

Pendahuluan

Aplikasi modern hampir selalu bergantung pada API — dan API yang tidak stabil adalah musuh utama test end-to-end. Episode 12 ini membahas dua kemampuan yang saling melengkapi: API testing langsung lewat fixture request, dan network interception untuk mengendalikan respons API di level browser.

Dengan route interception, kalian bisa membuat aplikasi berperilaku seolah server merespons dengan data tertentu, gagal total, atau lambat — semua tanpa menyentuh server sungguhan. Ini membuka skenario yang sebelumnya mustahil diuji dengan andal: offline mode, error handling, loading state, dan kontrak data.

Mocking API Responses dengan Route Interception

Memahami page.route

page.route mencegat request yang cocok dengan pola URL sebelum dikirim ke jaringan. Di dalam handler, kalian memutuskan apa yang terjadi: memenuhi request dengan data buatan, melanjutkan ke server, atau membatalkannya.

JSMock response dengan route.fulfill
import { test, expect } from '@playwright/test';
 
test('daftar produk dari mock', async ({ page }) => {
  await page.route('**/api/produk', (route) => {
    route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify([
        { id: 1, nama: 'Laptop', harga: 15000000 },
        { id: 2, nama: 'Mouse', harga: 250000 },
      ]),
    });
  });
 
  await page.goto('/produk');
  await expect(page.getByText('Laptop')).toBeVisible();
  await expect(page.getByText('Mouse')).toBeVisible();
});

route.fulfill(...) mengembalikan respons buatan tanpa benar-benar menghubungi server. Test di atas menguji bagaimana UI merender daftar produk dengan data yang terkontrol sepenuhnya.

Pola URL dan Scoping

Pola URL **/api/produk memakai glob: ** cocok dengan segmen path mana pun. Kalian bisa menargetkan API tertentu secara presisi. Untuk memodifikasi respons server sungguhan — misalnya menyisipkan field — gunakan route.continue():

JSModifikasi respons server asli
await page.route('**/api/produk', async (route) => {
  const response = await route.fetch();
  const data = await response.json();
  data.push({ id: 99, nama: 'Produk Tambahan', harga: 1000 });
  await route.fulfill({
    response,
    body: JSON.stringify(data),
  });
});

route.fetch() mengambil respons asli dari server, lalu kalian mengubah payloadnya sebelum route.fulfill. Pola ini berguna untuk menambahkan data uji tanpa mengubah kontrak server.

Menguji Offline Mode dan Network Failures

Mensimulasikan Gagal Jaringan

Untuk menguji bagaimana aplikasi menangani kegagalan, route.abort membuat request gagal seolah koneksi terputus:

JSSimulasi network failure
await page.route('**/api/*', (route) => route.abort('failed'));
 
await page.goto('/beranda');
await expect(page.getByText('Gagal memuat data')).toBeVisible();
await expect(page.getByRole('button', { name: 'Coba Lagi' })).toBeVisible();

route.abort('failed') membatalkan semua request API dengan alasan failed. Aplikasi yang baik menampilkan pesan error dan tombol retry — dan inilah yang kalian verifikasi.

Uji bagaimana UI menampilkan state loading sebelum data tiba dengan menunda fulfill:

JSTunda respons untuk uji loading
await page.route('**/api/lambat', async (route) => {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  await route.fulfill({ status: 200, body: '{}' });
});

Menunda respons dengan setTimeout dalam handler memberi kesempatan memverifikasi bahwa spinner atau skeleton muncul sambil menunggu. Pastikan test juga tetap menunggu data akhir, bukan hanya memeriksa loading.

Menerapkan Offline Secara Keseluruhan

Untuk menguji mode offline total, gunakan context dengan opsi yang menonaktifkan network:

JSContext offline
const context = await browser.newContext({
  offline: true,
});

offline: true membuat seluruh context berjalan tanpa koneksi. Aplikasi yang memakai service worker dan cache akan tetap berfungsi — dan itu yang layak diuji untuk pengalaman offline.

Memvalidasi Backend Behavior Melalui UI Flows

Menangkap Payload Request

Selain mengendalikan respons, kalian bisa mengamati apa yang dikirim aplikasi ke server:

JSTangkap dan periksa request body
let requestBody;
await page.route('**/api/checkout', (route) => {
  requestBody = route.request().postDataJSON();
  route.continue();
});
 
await page.getByRole('button', { name: 'Bayar' }).click();
expect(requestBody).toMatchObject({
  email: 'user@example.com',
  total: 15000000,
});

route.request().postDataJSON() mengembalikan body request sebagai objek. Dengan ini, validasi perilaku backend dilakukan lewat UI — memastikan bahwa klik kalian benar-benar mengirim data yang tepat ke server.

Menggabungkan API Check dan UI Check

Pendekatan yang seimbang: uji kontrak API langsung dengan fixture request, lalu uji bahwa UI memakai API tersebut dengan benar lewat route. Jika API berubah, test API langsung memberi sinyal cepat tanpa browser; jika UI salah mengirim data, interception test menangkapnya.

Integrasi dengan API Test Tools dan Service Mocks

Memakai Fixture request untuk API Test Murni

Playwright memiliki fixture request untuk HTTP test tanpa browser — cepat dan cocok untuk smoke test API:

JSSmoke test API
import { test, expect } from '@playwright/test';
 
test('health check API', async ({ request }) => {
  const response = await request.get('/api/health');
  expect(response.ok()).toBeTruthy();
  const body = await response.json();
  expect(body.status).toBe('up');
});

request.get('/api/health') mengirim HTTP GET langsung. Kombinasikan dengan baseURL di konfigurasi agar path relatif berfungsi. Test semacam ini murah dan bisa dijalankan sangat cepat.

Service Mocks untuk Data yang Kompleks

Ketika data uji terlalu kompleks untuk ditulis inline, pisahkan ke file JSON dan penuhi via route dengan data tersebut:

JSFulfill dari data file
import dataProduk from '../fixtures/produk.json';
 
await page.route('**/api/produk', (route) => {
  route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(dataProduk) });
});

dataProduk dimuat dari file fixtures — dataset yang sama bisa dipakai di banyak test dan mudah diperbarui. Ini menjaga konsistensi antara data mock dan harapan assertion.

Jalankan test API dan interception
npx playwright test tests/api.spec.ts

Penutup

Episode 12 memberikan kalian kendali penuh atas lapisan jaringan: mocking dan modifikasi respons API lewat page.route, simulasi offline dan network failures untuk menguji error handling, validasi payload yang dikirim aplikasi, serta integrasi dengan fixture request untuk API test yang cepat dan service mocks yang terpusat.

Inti yang harus dibawa pulang:

  • route.fulfill mengendalikan respons API tanpa menyentuh server.
  • route.abort('failed') mensimulasikan kegagalan jaringan.
  • route.request().postDataJSON memvalidasi payload yang dikirim aplikasi.
  • Fixture request memberi API test cepat tanpa browser.
  • Pisahkan data mock ke file fixtures agar mudah dipakai dan diperbarui.

Di episode 13 selanjutnya kita akan membahas security dan isolation — menjalankan test dalam browser contexts yang terisolasi, menangani secrets dan environment variables dengan aman, melindungi test data dan credentials, serta mencegah state leakage antar test.