Prototipe HTML mandiri yang dihasilkan oleh agen AI (seperti baoyu-design, Claude Artifacts, atau v0) sering mengalami regresi visual tak terduga saat diubah atau diintegrasikan ke codebase produksi. Masalah umum mencakup container collapse, font flash (FOUT/FOIT), hingga layout overflow pada viewport tertentu. Artikel ini membahas cara membangun harness verifikasi visual otomatis berbasis Playwright untuk memastikan integritas visual dan struktural prototipe.
Tantangan Determinisme pada Artefak AI
Kode yang dihasilkan model AI generatif cenderung memiliki karakteristik unik:
- Menggunakan asset eksternal tidak terkunci (CDN fonts, remote SVGs, Unsplash URLs).
- Inline styling atau utility classes (Tailwind) yang ambigu terhadap inherited layout.
- Animasi CSS default yang menyebabkan race condition saat testing screenshot.
Visual regression testing standar akan menghasilkan false-positive tinggi jika lingkungan eksekusi tidak dikendalikan secara deterministik.
Arsitektur Verification Harness
Harness terdiri dari tiga layer pengujian: isolasi lokal file statis, asersi geometris DOM mentah (structural assertions), dan visual pixel comparison menggunakan Playwright snapshot API.
1. Isolasi Environment dan Penanganan Flakiness
Sebelum mengambil snapshot visual, browser harus dipaksa berada dalam kondisi deterministik:
- Matikan Animasi CSS: Injeksi style untuk me-reset transition dan animation duration ke 0s.
- Tunggu Font Readiness: Evaluasi
document.fonts.readysebelum melakukan capture. - Mock Network Image: Cegah request eksternal gagal dengan me-route asset dummy jika AI menggunakan placeholder URLs.
2. Konfigurasi Playwright Minimal
Gunakan konfigurasi ringan berikut untuk menguji file HTML statis tanpa menjalankan full production server.
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
use: {
baseURL: 'http://127.0.0.1:8080',
trace: 'on-first-retry',
},
projects: [
{
name: 'desktop',
use: { ...devices['Desktop Chrome'], viewport: { width: 1280, height: 720 } },
},
{
name: 'mobile',
use: { ...devices['iPhone 13'], viewport: { width: 390, height: 844 } },
},
],
webServer: {
command: 'npx http-server ./artifacts -p 8080 -s',
url: 'http://127.0.0.1:8080',
reuseExistingServer: !process.env.CI,
},
});Implementasi Skrip Validasi Layout dan Snapshot
Skrip berikut mengeksekusi validasi DOM struktural (memeriksa overflow dan layout break) sebelum membandingkan snapshot pixel.
// tests/prototype-verification.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Verifikasi Visual Prototipe HTML', () => {
test.beforeEach(async ({ page }) => {
// Buka prototipe hasil AI
await page.goto('/prototype-index.html');
// 1. Matikan CSS transitions & animations
await page.addStyleTag({
content: `
*, *::before, *::after {
animation-duration: 0s !important;
animation-delay: 0s !important;
transition-duration: 0s !important;
transition-delay: 0s !important;
}
`,
});
// 2. Tunggu web fonts selesai dimuat
await page.evaluate(() => document.fonts.ready);
});
test('Validasi struktural DOM (tanpa horizontal overflow)', async ({ page }) => {
// Deteksi jika artefak AI membuat page width melebihi viewport
const hasHorizontalOverflow = await page.evaluate(() => {
return document.documentElement.scrollWidth > window.innerWidth;
});
expect(hasHorizontalOverflow).toBeFalsy();
// Pastikan elemen kritis memiliki bounding box valid
const ctaButton = page.locator('button.cta-primary');
await expect(ctaButton).toBeVisible();
const box = await ctaButton.boundingBox();
expect(box).not.toBeNull();
expect(box!.width).toBeGreaterThan(40);
expect(box!.height).toBeGreaterThan(20);
});
test('Verifikasi snapshot visual terhadap baseline', async ({ page }) => {
// Capture full-page snapshot dengan threshold perbedaan pixel rendah
await expect(page).toHaveScreenshot('prototype-baseline.png', {
fullPage: true,
maxDiffPixelRatio: 0.02, // Toleransi perbedaan maksimal 2%
animations: 'disabled',
});
});
});Menghindari Overhead Headless Browser
Visual testing di CI/CD sering lambat karena rendering browser headless penuh. Untuk optimasi pipeline:
- Fail-Fast via Structural Assertions: Jalankan asersi DOM ukuran/overflow terlebih dahulu. Jika struktur dasar gagal, hentikan pipeline sebelum memicu snapshot screenshot yang memakan I/O disk tinggi.
- Toleransi Threshold Deterministic: Hindari
maxDiffPixelRatio: 0. Perbedaan font subpixel rendering antar OS (Linux di CI vs macOS lokal) sering memicu kegagalan semu. Gunakan threshold toleransi antara0.01sampai0.03. - Cache Baseline Images: Simpan gold baseline screenshots di Git LFS atau CI cache untuk menghindari rekalkulasi dari awal setiap commit.
Rekomendasi: Bila artefak AI hanya berisi file presentasi statis sederhana, gunakan visual regression harness ini sebagai gate blocker di CI sebelum kode HTML/Tailwind di-porting menjadi komponen Vue, React, atau blade templates.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!