mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 09:27:29 +00:00
Offscreen or clipped working rings dropped their CSS animation through one shared IntersectionObserver; revealing a ring restarts it and the existing animationstart anchor keeps every ring on the shared phase. The spinner bench gains an always-on comparison variant and reports compositor frame counts.
123 lines
4.1 KiB
JavaScript
123 lines
4.1 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { verifyPixels } from './verify-pixels.mjs'
|
|
|
|
async function waitForPhase(page) {
|
|
await page
|
|
.waitForFunction(() =>
|
|
[...document.querySelectorAll('[data-agent-spinner]')].every((element) => {
|
|
const animations = element.getAnimations({ subtree: true })
|
|
// Offscreen rings must hold no animation; onscreen ones run on the shared phase.
|
|
if (element.hasAttribute('data-animation-offscreen')) {
|
|
return animations.length === 0
|
|
}
|
|
return (
|
|
animations.length === 1 &&
|
|
animations[0].startTime === 0 &&
|
|
animations[0].playState === 'running'
|
|
)
|
|
})
|
|
)
|
|
.catch(async (error) => {
|
|
console.log(
|
|
await page.evaluate(() =>
|
|
[...document.querySelectorAll('[data-agent-spinner]')].slice(0, 3).map((element) => ({
|
|
html: element.outerHTML,
|
|
width: getComputedStyle(element).width,
|
|
state: document.visibilityState,
|
|
animations: element.getAnimations({ subtree: true }).map((animation) => ({
|
|
name: animation.animationName,
|
|
start: animation.startTime,
|
|
time: animation.currentTime
|
|
}))
|
|
}))
|
|
)
|
|
)
|
|
throw error
|
|
})
|
|
}
|
|
|
|
export async function verifyRendering(app, page, outputDir) {
|
|
await page.emulateMedia({ reducedMotion: 'no-preference' })
|
|
await page.evaluate(() => window.spinnerBenchmark.render({ count: 4, paired: true }))
|
|
await waitForPhase(page)
|
|
const pixelComparisons = await verifyPixels(app, page, outputDir, waitForPhase)
|
|
await app.evaluate(({ BrowserWindow }) =>
|
|
BrowserWindow.getAllWindows()[0].webContents.setZoomFactor(1)
|
|
)
|
|
await page.emulateMedia({ reducedMotion: 'reduce' })
|
|
await page.waitForFunction(() =>
|
|
[...document.querySelectorAll('[data-agent-spinner]')].every((element) => {
|
|
const ring = getComputedStyle(element)
|
|
return (
|
|
element.getAnimations({ subtree: true }).length === 0 &&
|
|
ring.borderTopColor === ring.borderLeftColor
|
|
)
|
|
})
|
|
)
|
|
await page.emulateMedia({ reducedMotion: 'no-preference' })
|
|
await waitForPhase(page)
|
|
await page.evaluate(() => window.spinnerBenchmark.render({ count: 200, offset: 5000 }))
|
|
await page.waitForFunction(
|
|
() => document.querySelectorAll('[data-agent-spinner][data-animation-offscreen]').length === 200
|
|
)
|
|
await waitForPhase(page)
|
|
await page.evaluate(() => {
|
|
document.querySelector('#scroller').scrollTop = 5000
|
|
})
|
|
await waitForPhase(page)
|
|
await page.evaluate(() => {
|
|
document.querySelector('#scroller').scrollTop = 0
|
|
})
|
|
await waitForPhase(page)
|
|
await page.evaluate(() => {
|
|
document.querySelector('#scroller').scrollTop = 5000
|
|
})
|
|
await waitForPhase(page)
|
|
await page.evaluate(() => {
|
|
document.querySelector('#grid').style.display = 'none'
|
|
})
|
|
await page.waitForFunction(
|
|
() => document.querySelector('#grid').getBoundingClientRect().height === 0
|
|
)
|
|
await page.evaluate(() => {
|
|
document.querySelector('#grid').style.display = 'grid'
|
|
})
|
|
await waitForPhase(page)
|
|
const iterationEvents = await page.evaluate(async () => {
|
|
window.spinnerBenchmark.render({ count: 4, paired: true })
|
|
const events = { baseline: 0, candidate: 0 }
|
|
const count = (event) => {
|
|
if (event.animationName === 'spinner-benchmark-spin') {
|
|
events.baseline++
|
|
}
|
|
if (event.animationName === 'agent-spinner-rotate') {
|
|
events.candidate++
|
|
}
|
|
}
|
|
document.addEventListener('animationiteration', count, true)
|
|
try {
|
|
await new Promise((resolve) => setTimeout(resolve, 1250))
|
|
} finally {
|
|
document.removeEventListener('animationiteration', count, true)
|
|
}
|
|
return events
|
|
})
|
|
assert.ok(iterationEvents.baseline >= 2)
|
|
assert.equal(iterationEvents.candidate, 0)
|
|
assert.ok(
|
|
await app.evaluate(({ BrowserWindow }) =>
|
|
BrowserWindow.getAllWindows().every((window) => !window.isVisible() && !window.isFocused())
|
|
)
|
|
)
|
|
return {
|
|
pixelComparisons,
|
|
offscreenPause: true,
|
|
iterationEvents,
|
|
phases: true,
|
|
reducedMotion: true,
|
|
scrollReveal: true,
|
|
displayReveal: true,
|
|
hiddenWindow: true
|
|
}
|
|
}
|