import { chromium } from 'playwright'; /* Scrolls to positions around each deck card's snap point and reports where the page comes to rest. */ const [,, url, width = '1440', height = '900'] = process.argv; const browser = await chromium.launch(); const page = await browser.newPage({ viewport: { width: Number(width), height: Number(height) } }); await page.goto(url, { waitUntil: 'networkidle' }); const info = await page.evaluate(() => { const cards = Array.from(document.querySelectorAll('[data-deck-snap]')); const cs = getComputedStyle(document.documentElement); return cards.map((c, i) => { const st = getComputedStyle(c); return { i, naturalTop: c.offsetTop + (c.offsetParent?.getBoundingClientRect().top ?? 0) + window.scrollY, marginTop: st.scrollMarginTop, snapAlign: st.scrollSnapAlign, snapStop: st.scrollSnapStop, htmlSnap: cs.scrollSnapType }; }); }); console.log(JSON.stringify(info, null, 1)); // expected snap points: naturalTop - scrollMarginTop const results = []; for (const c of info) { const expected = Math.round(c.naturalTop - parseFloat(c.marginTop)); for (const off of [-220, 180, 320, 352]) { await page.evaluate((y) => window.scrollTo({ top: y, behavior: 'auto' }), expected + off); await page.waitForTimeout(1200); const y = await page.evaluate(() => Math.round(window.scrollY)); results.push({ card: c.i, expected, offset: off, landed: y, snapped: Math.abs(y - expected) < 2 }); } } console.table(results); await browser.close();