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:
1 parent
1ffff67991
commit
af7f98d66b
5 files changed
+49
-14
No files matched your search
@@ -60,18 +60,28 @@ const geo = s => JSON.stringify([s.box[2], s.box[3], s.icon && [rd(s.icon[0] - s
|
||||
async function cycleAll(sel, q, tag) {
|
||||
const n = await ev(`[...document.querySelectorAll(${JSON.stringify(sel)})].filter(e => e.getClientRects().length).length`)
|
||||
const results = []
|
||||
// 2026-10-20: state-based waits replace the fixed 60–100ms sleeps (Firefox sometimes read a tile before :hover or its
|
||||
// transition applied, so a tile looked unhovered or a read hit the wrong index). Each read waits until the item's
|
||||
// :hover / :active state is the expected one and its transitions ended; a wait that times out is recorded and fails.
|
||||
// The preview sets html { scroll-behavior: smooth } (src/hm-theme.css): scroll instantly, or the item is measured mid-scroll
|
||||
// and the pointer lands on another tile (the former "저장" hover / index misses).
|
||||
// After a release outside the item Firefox keeps :active on it until the next press, so that last wait checks :hover only.
|
||||
const settle = (i, hover, active = false) => ev(`(async () => { const el = [...document.querySelectorAll(${JSON.stringify(sel)})].filter(e => e.getClientRects().length)[${i}]
|
||||
const frame = () => new Promise(r => requestAnimationFrame(() => r()))
|
||||
for (let t = 0; t < 120; t++) { await frame(); if (el.matches(':hover') === ${hover} && (${active === null} || el.matches(':active') === ${active}) && el.getAnimations({ subtree: true }).every(a => a.playState !== 'running')) { await frame(); return true } }
|
||||
return false })()`)
|
||||
for (let i = 0; i < n; i++) {
|
||||
await ev(`[...document.querySelectorAll(${JSON.stringify(sel)})].filter(e => e.getClientRects().length)[${i}].scrollIntoView({ block: 'center', inline: 'center' }), true`); await sleep(60)
|
||||
await move(1, 1); await sleep(80)
|
||||
await ev(`[...document.querySelectorAll(${JSON.stringify(sel)})].filter(e => e.getClientRects().length)[${i}].scrollIntoView({ block: 'center', inline: 'center', behavior: 'instant' }), true`)
|
||||
await move(1, 1); const waits = [await settle(i, false)]
|
||||
const d0 = await snap(sel, i, q)
|
||||
const [x, y] = [d0.box[0] + d0.box[2] / 2, d0.box[1] + d0.box[3] / 2]
|
||||
await move(x, y); await sleep(100); const h1 = await snap(sel, i, q)
|
||||
await move(1, 1); await sleep(100); const d1 = await snap(sel, i, q)
|
||||
await move(x, y); await sleep(100); const h2 = await snap(sel, i, q)
|
||||
await pointer([{ type: 'pointerDown', button: 0 }]); await sleep(80); const a = await snap(sel, i, q)
|
||||
await pointer([{ type: 'pointerMove', x: 1, y: 1, duration: 0 }, { type: 'pointerUp', button: 0 }]); await sleep(100)
|
||||
const same = [h1, d1, h2, a].every(s => geo(s) === geo(d0))
|
||||
results.push({ name: d0.name, same, hovered: d0.active || h1.color !== d0.color, d0, h1, a })
|
||||
await move(x, y); waits.push(await settle(i, true)); const h1 = await snap(sel, i, q)
|
||||
await move(1, 1); waits.push(await settle(i, false)); const d1 = await snap(sel, i, q)
|
||||
await move(x, y); waits.push(await settle(i, true)); const h2 = await snap(sel, i, q)
|
||||
await pointer([{ type: 'pointerDown', button: 0 }]); waits.push(await settle(i, true, true)); const a = await snap(sel, i, q)
|
||||
await pointer([{ type: 'pointerMove', x: 1, y: 1, duration: 0 }, { type: 'pointerUp', button: 0 }]); waits.push(await settle(i, false, null))
|
||||
const same = [h1, d1, h2, a].every(s => geo(s) === geo(d0)) && waits.every(Boolean)
|
||||
results.push({ name: d0.name, same, hovered: d0.active || h1.color !== d0.color, d0, h1, a, waits })
|
||||
check(`Firefox ${tag} "${d0.name}": icon · text · box unchanged (Default/Hover/Default/Hover/Active)`, same, { d0: geo(d0), h1: geo(h1), a: geo(a) })
|
||||
}
|
||||
return results
|
||||
|
||||
Reference in new issue
Block a user