Sumber skrip Playwright CLI 0.1.22, 25 Oktober 2026. Buka beranda build Pages di browser CLI, lalu jalankan skrip ini lewat run-code --filename. Skrip menyimpan artefak ke output/playwright/ dan tidak mengirim form email. async (page) => { const base = new URL(page.url()).origin; const result = { date: '2026-10-25', tool: 'Chromium via Playwright CLI', browserVersion: page.context().browser()?.version(), target: base.includes('127.0.0.1') ? 'local Pages build' : 'public deployment', measurements: [], actionRequests: [], actionResponses: [] }; page.on('request', request => { if (new URL(request.url()).pathname === '/api/metrics/event/') result.actionRequests.push({ event: request.postDataJSON()?.event, pathname: request.postDataJSON()?.pathname }); }); page.on('response', response => { if (new URL(response.url()).pathname === '/api/metrics/event/') result.actionResponses.push({ method: response.request().method(), status: response.status(), event: response.request().postDataJSON()?.event }); }); const paths = ['/', '/newsletter/', '/newsletter/paket-ai/', '/mulai/', '/redaksi/', '/deep-dives/uji-prompt-ai-lima-catatan-rapat/', '/panduan/catatan-rapat-jadi-tindakan/']; for (const width of [390, 1440]) { await page.setViewportSize({ width, height: 844 }); for (const path of paths) { const response = await page.goto(base + path); await page.evaluate(() => document.fonts.ready); await page.locator('img').evaluateAll(images => Promise.all(images.map(image => { image.loading = 'eager'; return image.decode().catch(() => {}); }))); result.measurements.push(await page.evaluate(({ path, status, width }) => { const firstKit = document.querySelector('a[href="/newsletter/paket-ai/"]'); const heroKit = document.querySelector('.welcome-actions a[href="/newsletter/paket-ai/"]'); const position = a => a ? Math.round(a.getBoundingClientRect().top + scrollY) : null; return { path, status, width, scrollWidth: document.documentElement.scrollWidth, pageHeight: document.documentElement.scrollHeight, firstKitY: position(firstKit), heroKitY: position(heroKit), newsletterForms: document.querySelectorAll('form[data-newsletter-form]').length, headingCount: document.querySelectorAll('h1').length, diagramFits: [...document.querySelectorAll('img.editorial-art')].every(img => getComputedStyle(img).objectFit === 'contain') }; }, { path, status: response.status(), width })); if (path === '/' && width === 390) await page.screenshot({ path: 'output/playwright/audit-fixes-home-390-browser.png', fullPage: true }); if (path === '/' && width === 1440) await page.screenshot({ path: 'output/playwright/audit-fixes-home-1440-browser.png', fullPage: true }); if (path === '/newsletter/' && width === 390) await page.screenshot({ path: 'output/playwright/audit-fixes-newsletter-390-browser.png', fullPage: true }); } } await page.setViewportSize({ width: 390, height: 844 }); await page.goto(base + '/'); const openEvent = page.waitForRequest(request => new URL(request.url()).pathname === '/api/metrics/event/' && request.postDataJSON()?.event === 'starter_kit_open'); await page.getByRole('link', { name: 'Coba paket AI gratis' }).click(); await openEvent; await page.waitForURL('**/newsletter/paket-ai/'); const downloadPromise = page.waitForEvent('download'); const downloadEvent = page.waitForResponse(response => new URL(response.url()).pathname === '/api/metrics/event/' && response.request().postDataJSON()?.event === 'starter_kit_download_click'); await page.getByRole('link', { name: 'Unduh paket gratis' }).click(); await downloadEvent; const download = await downloadPromise; await download.saveAs('output/playwright/audit-fixes-downloaded-kit.txt'); result.download = { filename: download.suggestedFilename(), failure: await download.failure() }; const file = await page.request.get(base + '/downloads/paket-3-alur-kerja-ai.txt', { headers: { DNT: '1' } }); const body = await file.body(); result.download.status = file.status(); result.download.bytes = body.length; const text = body.toString('utf8'); result.download.sections = ['CATAT HASIL PERCOBAAN KAMU', 'Orang yang memeriksa:'].every(value => text.includes(value)); if (result.measurements.some(row => row.status !== 200 || row.scrollWidth > row.width || row.headingCount !== 1 || row.newsletterForms !== 0 || !row.diagramFits)) throw new Error('Public page regression; inspect measurements.'); if (result.download.status !== 200 || result.download.failure || !result.download.sections || body.length < 10000) throw new Error('Starter kit download failed.'); const hero = result.measurements.find(row => row.path === '/' && row.width === 390); if (hero.heroKitY === null || hero.heroKitY >= 844) throw new Error('Starter kit is below the initial viewport.'); return result; }