Skip to content

Manual PDF Otomatis dari Capture Playwright

Adityo Guni Waluyo

Test tour Playwright bisa langsung menjadi user manual: satu manifest menghasilkan halaman HTML, indeks, dan PDF A4 yang diverifikasi otomatis tiap run.

Ringkasan

Bikin user manual KotaPortal ternyata nggak semudah rekam video lalu ekstrak frame, soalnya video Playwright baru ada setelah context ditutup. Jadinya ffmpeg dipindah ke afterAll, plus satu manifest.json yang nyambungin tur ke tiga file HTML dan PDF A4. Sekalian ketahuan urutan cleanup salah: trash dulu baru delete permanen, plus guard PDF minimal 100 ribu byte.

Proses handover KotaPortal mensyaratkan satu berkas user manual untuk tim operasional. Di repo, suite e2e Playwright sudah menjelajahi hampir setiap layar: empat capture spec, 24 tour group (6 + 7 + 8 + 3), semuanya read-only. Pekerjaan yang tersisa tampak kecil tinggal mengubah tur itu menjadi dokumentasi.

Dugaan pertama yang menggoda: ambil rekaman video dari test run, lalu ekstrak frame-nya dengan ffmpeg. Atau, tanpa video, tempel screenshot satu per satu ke dokumen. Dua-duanya terasa melelahkan, tapi video terlihat paling cepat.

Dugaan itu salah pada titik yang tidak terduga. Konfigurasi test.use({ video: 'on' }) aktif dengan viewport 1280x720, dan ffmpeg dipanggil langsung di dalam test body untuk mengubah video.webm menjadi gambar. Hasilnya error ENOENT di tengah test: berkas videonya belum ada. Menurut dokumentasi video Playwright, rekaman baru disimpan setelah browser context ditutup, jadi video hanya tersedia setelah page atau browser context close [1]. Asumsi bahwa konversi bisa berlangsung di dalam test body gugur begitu saja.

Satu manifest, tiga keluaran HTML

Keputusan yang diambil: pisahkan tahap staging dan tahap finalisasi. Test body hanya mengumpulkan artefak tur; finalizeCaptures menjalankan ffmpeg dan menulis manifest.json di afterAll, setelah semua context tertutup dan video sudah final.

Generator generate_manual.mjs membaca satu manifest.json itu saja. Untuk setiap tour group, generator menelurkan satu halaman HTML, lalu sebuah indeks, dan varian cetak print.html. Manifest tunggal berarti urutan bab di manual selalu identik dengan urutan tur di test run tanpa ada daftar kedua yang perlu disinkronkan.

Bagian akhir generate_manual.mjs memanggil page.pdf({ format: 'A4' }) terhadap berkas cetak print.html. Dokumentasi Playwright menyebutkan bahwa page.pdf() menghasilkan PDF dengan print css media, dan warna perlu properti -webkit-print-color-adjust agar hasil cetak memakai warna persis [2]. Format A4 (8.27in x 11.7in) tersedia sebagai opsi bawaan [2]. Chromium dipilih sebagai browser generator, sebuah keputusan implementasi di proyek ini.

Contoh berikut adalah rekonstruksi generik dari pola tersebut:

// capture_tour.spec.js (rekonstruksi generik)
import { test } from '@playwright/test';

test.use({ video: 'on', viewport: { width: 1280, height: 720 } });

test('tur dashboard admin', async ({ page }, testInfo) => {
  await page.goto('https://example.com/admin/dashboard');
  // langkah tur read-only: buka menu, isi filter, baca tabel
  await stageCapture(testInfo, 'dashboard');
});

test.afterAll(async () => {
  await finalizeCaptures(); // ffmpeg + tulis manifest.json
});
// generate_manual.mjs (rekonstruksi generik)
const manifest = JSON.parse(await readFile('manifest.json', 'utf8'));
// per tour group: page.html, index.html, print.html
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(`file://${printPath}`);
const pdf = await page.pdf({ path: 'manual.pdf', format: 'A4' });
assert.ok(pdf.length >= 100_000, `PDF terlalu kecil: ${pdf.length} byte`);

Finalisasi menemukan masalah kedua

Memindahkan ffmpeg ke afterAll membuka satu temuan lagi. Tur memang read-only, tetapi data uji yang dipakai harus dibersihkan setelah run. Penghapusan permanen baris uji ternyata diam-diam tidak melakukan apa pun selama baris tersebut belum dipindahkan dari trash. Urutan cleanup yang benar adalah trash lebih dulu, baru delete permanen. Perilaku ini datang dari API internal proyek dan tidak terkait dengan perilaku Playwright.

Rinciannya kecil, tetapi menentukan apakah run berikutnya memakai data bersih atau data bekas. Pola yang sama berlaku untuk staging artefak: apa pun yang bergantung pada state akhir sebuah context harus menunggu context itu ditutup.

Wrapper dan ukuran sebagai guard

Seluruh alur dijalankan satu perintah: run_manual_capture.sh memanggil capture, lalu generate_manual.mjs, lalu verifikasi Node yang memeriksa artefak keluaran. Pemeriksaan itu pada dasarnya asersi atas artefak, dan Node.js menyediakan modul bawaan untuk pekerjaan semacam itu: node:assert menyediakan assertion functions untuk memverifikasi invariant [3].

Guard-nya sederhana: run gagal bila manual.pdf berada di bawah 100.000 byte. PDF yang terlalu kecil hampir selalu berarti print.html kosong atau screenshot tidak masuk manifest, dan kegagalan itu lebih jelas daripada menyerahkan berkas rusak ke tim operasional. Batas 100.000 byte hanyalah ambang kegagalan kasar.

Satu run tercatat pada entri ini menghasilkan 24 halaman tur, seluruhnya PASS, dengan manual.pdf sekitar 12,5 MB. Angka itu keluaran satu run dengan isi capture spesifik dan tidak berlaku sebagai patokan.

Perubahan yang tersisa setelah run pertama hanya isi tur, bukan pipanya. Menambah satu tour group berarti menambah satu entry di manifest.json, dan tiga berkas HTML beserta PDFnya menyusul tanpa disentuh.

Sources:

[1] Playwright: Videos

[2] Playwright: Page (page.pdf())

[3] Node.js: Assertions (node:assert)

Artikel terkait