test(sw): stabilize Firefox hover, pixel and timing checks

- hover-stability-firefox: instant scroll and state waits instead of a fixed 60ms delay (smooth scroll in preview).
- integrated-visual, viewer-regression, theme-inheritance: deterministic Chromium raster flags, animations held at
  time 0, layout settle wait, integer instant scroll of inner panels; tolerance stays 0.
- text-weight: wait for the Viewer More panel instead of a fixed 200ms and fix the failure report.
This commit is contained in:
shkim4 committed 2026-10-21 06:08:31 +09:00
1 parent 1ffff67991
commit af7f98d66b
5 files changed
+49 -14

No files matched your search

@@ -20,7 +20,9 @@ await mkdir(out, { recursive: true })
const ids = ['overview', 'interactive-states', 'logo-slot', 'document-dropdown', 'responsive-more', 'k-guide', 'property-panel-compare', 'composed-controls', 'document-open', 'hidden-sub-controls', 'detail-buttons'].map(id => `sw-header--${id}`)
.concat(['sw-popup--custom-content', 'sw-popup--multiple-popups'])
const widths = [1920, 1180, 768]
const browser = await chromium.launch({ headless: true, executablePath: process.env.SW_CHROME_PATH ?? 'C:/Program Files/Google/Chrome/Application/chrome.exe' })
// 2026-10-20: software raster without font hinting / subpixel positioning, as integrated-visual.browser.mjs: two
// captures of the same build otherwise differed in text anti-aliasing (Δ1 areas, 2 × 2 glyph spots). Threshold stays 0.
const browser = await chromium.launch({ headless: true, args: ['--disable-gpu', '--font-render-hinting=none', '--disable-font-subpixel-positioning', '--disable-lcd-text', '--force-color-profile=srgb'], executablePath: process.env.SW_CHROME_PATH ?? 'C:/Program Files/Google/Chrome/Application/chrome.exe' })
const shot = async (url, width, restore = false) => {
const page = await browser.newPage({ viewport: { width, height: 1000 }, reducedMotion: 'reduce' })
await page.goto(url)
@@ -32,6 +34,15 @@ const shot = async (url, width, restore = false) => {
const elements = []
for (const element of await page.locator('.hm-sw-header, .hm-sw-property').all()) {
if (!(await element.isVisible())) continue
// 2026-10-20: panels inside an inner scroller (Property Panel · 4개 비교) were scrolled into view at varying offsets, so
// two captures of the same build differed by 3–7px. Scroll instantly, keep every scroll offset whole, wait for stable frames.
await element.evaluate(e => new Promise(resolve => {
e.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'instant' })
for (let n = e.parentElement; n; n = n.parentElement) { n.scrollTop = Math.round(n.scrollTop); n.scrollLeft = Math.round(n.scrollLeft) }
let last = '', stable = 0
const tick = () => { const r = e.getBoundingClientRect(), now = [r.x, r.y, r.width, r.height].join(); stable = now === last ? stable + 1 : 0; last = now; stable >= 3 ? resolve() : requestAnimationFrame(tick) }
requestAnimationFrame(tick)
}))
elements.push(PNG.sync.read(await element.screenshot({ animations: 'disabled' })))
}
await page.close()