Skip to main content

E2E Full-Flow Testing dengan Playwright API & k6

Target: E2E full-flow (login → cart → checkout → payment → webhook → logout) dengan real hit API, tanpa mock, dan 100% testable, repeatable, serta bisa dijalankan otomatis. Postman tidak lagi cukup untuk kebutuhan ini; kita butuh pendekatan scriptable yang lebih stabil.

🎯 Overview

Untuk E2E flow panjang yang butuh chaining dan state sharing, ada dua pendekatan yang paling masuk akal:
  1. Playwright API Test (mode API-only, tanpa UI)
  2. k6 (JS-based E2E + load test runner)
Keduanya:
  • Scriptable
  • Clean & readable
  • Real hit API (bukan mock)
  • Stateful (bisa share token/login antar step)

Kenapa Playwright API Test?

  • Bisa chain request berurutan: login → cart → checkout → payment → dsb.
  • Bisa simpan token antar step via fixtures/helper.
  • Bisa nunggu webhook atau polling order status.
  • Bisa dijalankan di CI.
  • Bisa hit API lokal, dev, maupun environment lain.
  • Test case mudah dibaca dan deterministic.

Struktur Folder (contoh)

mstore_test/
  e2e/
    flows/
      full_checkout.spec.ts
    utils/
      payment.ts
      webhook.ts
      env.ts
Catatan: Di repo ini, kerangka Playwright API sudah diinisialisasi di mstore_test.

Contoh E2E Single Test (Konseptual)

import { test, expect } from '@playwright/test';

import { simulatePayment, waitUntilPaid } from './utils/payment';

test('full checkout flow', async ({ request }) => {
  // 1. Login
  const login = await request.post('/auth/login', {
    data: { email: '[email protected]', password: '123' }
  });
  const token = (await login.json()).token;

  // 2. Add to cart
  const cart = await request.post('/cart/add', {
    headers: { Authorization: `Bearer ${token}` },
    data: { product_id: 'P001', qty: 1 }
  });
  const cartId = (await cart.json()).id;

  // 3. Checkout
  const checkout = await request.post('/checkout', {
    headers: { Authorization: `Bearer ${token}` },
    data: { cart_id: cartId, payment_method: 'VA' }
  });
  const order = await checkout.json();

  // 4. Simulate Payment (sandbox)
  await simulatePayment(order.payment_ref);

  // 5. Wait / poll order final state
  const final = await waitUntilPaid(order.order_id);
  expect(final.status).toBe('PAID');

  // 6. Logout
  const out = await request.post('/auth/logout', {
    headers: { Authorization: `Bearer ${token}` }
  });
  expect(out.status()).toBe(200);
});
Implementasi aktual di repo bisa sedikit berbeda (prefix /api/v1, field data.token, dsb.), tapi pola chaining dan state sharing sama.

2️⃣ k6 – E2E + Load Test Ringan

k6 cocok untuk:
  • Smoke test E2E
  • Load test ringan
  • Validasi basic correctness di bawah beban

Contoh Skema k6 (Konseptual)

import http from 'k6/http';
import { check, sleep } from 'k6';

export default function () {
  const login = http.post('/auth/login', JSON.stringify({/* ... */}));

  const cart = http.post('/cart/add', JSON.stringify({/* ... */}));

  const checkout = http.post('/checkout', JSON.stringify({/* ... */}));

  simulatePayment(checkout.json().payment_ref);

  // polling
  let final;
  for (let i = 0; i < 10; i++) {
    final = http.get(`/order/${id}`);
    if (final.json().status === 'PAID') break;
    sleep(1);
  }

  check(final, { 'is paid': r => r.json().status === 'PAID' });
}
k6 lebih simpel & cepat untuk CLI dan load, tetapi Playwright biasanya lebih enak untuk E2E logic yang kompleks (branching, assertions kaya, fixtures, dsb.).

3️⃣ Kenapa Pendekatan Ini Masuk Akal untuk MStore?

  • E2E checkout adalah rantai panjang → butuh script, bukan sekadar collections.
  • Perlu state persistence: token login di‑share semua step.
  • Perlu simulate payment + webhook → bisa di‑enkapsulasi dalam helper function.
  • Perlu assert setelah webhook → polling atau webhook listener.
  • Harus jalan lokal (Windsurf/MCP friendly) dan di CI.
  • Harus real API hit → no mocks, no abstraction di level E2E.
Tool seperti Postman/Insomnia/Swagger/Bruno GUI bagus untuk eksplorasi manual, tapi:
  • Lemah dalam chaining panjang & state sharing.
  • Tidak ideal untuk CI/CD E2E yang kompleks.

4️⃣ Rekomendasi Urutan Implementasi

  1. Pakai Playwright API Test untuk full E2E
    • Fokuskan dulu pada alur: login → cart → checkout → payment → status final.
  2. Tambah simulatePayment function (Xendit/Midtrans)
    • Panggil sandbox API atau internal simulator.
  3. Tambah webhook tester
    • Bisa via Knock/local forwarder, atau polling status order sampai berubah.
  4. Tambah poll order status setelah webhook/pembayaran
    • Implementasikan helper waitUntilPaid.
  5. Integrasikan ke CI/CD
    • Jalankan Playwright E2E di setiap PR / sebelum rilis.

5️⃣ Fact / Opinion / Possibility

  • Fact: E2E API dengan flow full checkout membutuhkan chaining + state share; tool non-script sulit melakukan ini dengan rapi.
  • Opinion: Playwright API test adalah “sweet spot” — simple tapi powerful, cocok untuk backend modern seperti MStore.
  • Possibility: Untuk determinisme penuh, kita bisa membangun MCP payment simulator sendiri → test pembayaran tanpa tergantung sandbox gateway eksternal.

6️⃣ Integrasi dengan Struktur mstore_test

  • Playwright API skeleton sudah diinisialisasi di mstore_test/:
    • playwright.config.ts
    • e2e/flows/full_checkout.spec.ts
    • e2e/utils/payment.ts
  • k6 skeleton sudah ada di:
    • performance/k6/login_smoke_test.js
Next step yang disarankan:
  • Mapping endpoint aktual backend ke skeleton Playwright.
  • Menambah skenario k6 yang mirror alur E2E utama.