import { chromium } from 'playwright'; const shots = [ { name: 'desktop-1440', w: 1440, h: 1000 }, { name: 'laptop-1280', w: 1280, h: 900 }, { name: 'tablet-1024', w: 1024, h: 950 }, { name: 'mobile-390', w: 390, h: 844 }, ]; for (const s of shots) { // fresh browser each time: reusing one exhausts software WebGL contexts const browser = await chromium.launch({ args: ['--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader'], }); const page = await browser.newPage({ viewport: { width: s.w, height: s.h }, deviceScaleFactor: 1 }); const errs = []; page.on('pageerror', e => errs.push('pageerror: ' + e.message)); await page.goto('http://localhost:3000/miletruth', { waitUntil: 'load', timeout: 90000 }); const toSec = () => page.evaluate(() => { const el = document.querySelector('#solution-miletruth-ai'); if (el) window.scrollTo(0, window.scrollY + el.getBoundingClientRect().top - 8); }); await toSec(); await page.waitForTimeout(18000); await toSec(); await page.waitForTimeout(2500); const info = await page.evaluate(() => { const sec = document.querySelector('#solution-miletruth-ai'); const scene = sec.querySelector('.mtn-scene'); const sb = scene.getBoundingClientRect(); return { canvas: sec.querySelectorAll('canvas').length, labels: [...scene.querySelectorAll('.mtn-lbl')].map(e => { const r = e.getBoundingClientRect(); const clip = r.left < sb.left || r.right > sb.right || r.top < sb.top || r.bottom > sb.bottom; return e.querySelector('.mtn-lbl-n').textContent + (clip ? ' CLIPPED' : ''); }), stepRows: new Set([...sec.querySelectorAll('.sw-mt-step')].map(e => Math.round(e.getBoundingClientRect().top))).size, overflowX: document.documentElement.scrollWidth > document.documentElement.clientWidth, }; }); console.log(`${s.name}: ` + JSON.stringify(info)); if (errs.length) console.log(' ERRORS:', errs.slice(0, 3)); await page.screenshot({ path: `/tmp/mt-${s.name}.png`, timeout: 90000 }); await browser.close(); }