* Motion verification (#1437): sample the asserted selectors on a dense grid * against the same seeked timeline the renderer uses, then evaluate the spec's * assertions in Node. Reuses the live page from the layout audit — no extra * Chrome launch. Findings reuse the LayoutIssue shape.
(
page: import("puppeteer-core").Page,
spec: MotionSpec,
duration: number,
)
| 398 | * Chrome launch. Findings reuse the LayoutIssue shape. |
| 399 | */ |
| 400 | async function runMotionPass( |
| 401 | page: import("puppeteer-core").Page, |
| 402 | spec: MotionSpec, |
| 403 | duration: number, |
| 404 | ): Promise<{ issues: LayoutIssue[]; sampleCount: number }> { |
| 405 | const times = buildMotionSampleTimes(spec.duration ?? duration); |
| 406 | if (times.length === 0) return { issues: [], sampleCount: 0 }; |
| 407 | |
| 408 | const { selectors, livenessScopes } = collectSamplingTargets(spec.assertions); |
| 409 | const ambiguous = await findAmbiguousSelectors(page, selectors); |
| 410 | if (ambiguous.length > 0) return { issues: ambiguous, sampleCount: 0 }; |
| 411 | |
| 412 | const canvas = await page.evaluate(() => ({ |
| 413 | width: window.innerWidth, |
| 414 | height: window.innerHeight, |
| 415 | })); |
| 416 | await page.addScriptTag({ content: loadBrowserScript("motion-sample.browser.js") }); |
| 417 | const frames = await collectMotionFrames(page, times, selectors, livenessScopes); |
| 418 | return { issues: evaluateMotion(frames, spec.assertions, canvas), sampleCount: frames.length }; |
| 419 | } |
| 420 | |
| 421 | /** Read + validate the motion sidecar; print the error and exit on a bad spec. */ |
| 422 | function resolveMotionSpec(specPath: string, json: boolean): MotionSpec { |
no test coverage detected