mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(cli): check no longer calls a redrawn WebGL canvas a dead stretch (#6749)
* fix(cli): check no longer calls a redrawn WebGL canvas a dead stretch * fix(cli): keep the seek comment under the line limit
This commit is contained in:
@@ -2841,6 +2841,20 @@ describe("check pipeline", () => {
|
||||
expect(checkExitCode(strict.report)).toBe(0);
|
||||
});
|
||||
|
||||
it("seeks each craft frame with WebGL draws on, so a redrawn canvas reads as moving", async () => {
|
||||
const driver = craftDriver();
|
||||
await runScenario(driver);
|
||||
const painted = new Set(
|
||||
vi
|
||||
.mocked(driver.seekGeometry)
|
||||
.mock.calls.flatMap(([time, seek]) => (seek?.draws ? [time] : [])),
|
||||
);
|
||||
const sampled = vi.mocked(driver.collectCraftFrame!).mock.calls.map(([time]) => time);
|
||||
|
||||
expect(sampled.length).toBeGreaterThan(0);
|
||||
expect(sampled.every((time) => painted.has(time))).toBe(true);
|
||||
});
|
||||
|
||||
it("re-measures a short line between dense samples before judging it", async () => {
|
||||
const driver = craftDriver();
|
||||
const { report } = await runScenario(driver);
|
||||
|
||||
@@ -3,7 +3,7 @@ import puppeteer, { type Browser, type Page } from "puppeteer-core";
|
||||
import { createRequire } from "node:module";
|
||||
import { resolve } from "node:path";
|
||||
import { measuredInMotion, readContrastMotion } from "./contrastMotion.js";
|
||||
import { collectSeekClock } from "./checkBrowser.js";
|
||||
import { collectSeekClock, createPageDriver } from "./checkBrowser.js";
|
||||
|
||||
const executablePath = process.env.PUPPETEER_EXECUTABLE_PATH;
|
||||
|
||||
@@ -119,6 +119,24 @@ describe.runIf(executablePath)("collectSeekClock in Chromium", () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
it("skips a seek's WebGL draws unless the caller asks to paint them", async () => {
|
||||
page = await browser.newPage();
|
||||
await page.setContent(`<script>
|
||||
window.draws = 0;
|
||||
window.WebGLRenderingContext = function () {};
|
||||
window.WebGLRenderingContext.prototype.drawArrays = () => { window.draws += 1; };
|
||||
window.__hf = { seek: () => new window.WebGLRenderingContext().drawArrays() };
|
||||
</script>`);
|
||||
const driver = createPageDriver(page);
|
||||
const drawn = () => page.evaluate(() => Reflect.get(window, "draws"));
|
||||
|
||||
await driver.seekGeometry(1);
|
||||
expect(await drawn()).toBe(0);
|
||||
await driver.seekGeometry(2, { draws: true });
|
||||
expect(await drawn()).toBe(1);
|
||||
await page.close();
|
||||
});
|
||||
|
||||
it("reports nothing on a page with no animations", async () => {
|
||||
page = await browser.newPage();
|
||||
await page.setContent("<body><h1>Hello</h1></body>");
|
||||
|
||||
@@ -969,9 +969,12 @@ export function createPageDriver(
|
||||
screenshotFollows ? SCREENSHOT_SEEK_OPTIONS : AUDIT_SEEK_OPTIONS,
|
||||
);
|
||||
},
|
||||
seekGeometry: async (time) => {
|
||||
seekGeometry: async (time, { draws = false } = {}) => {
|
||||
clock.at(time);
|
||||
await seekCompositionTimeline(page, time, DENSE_GEOMETRY_SEEK_OPTIONS);
|
||||
const options = draws
|
||||
? { ...DENSE_GEOMETRY_SEEK_OPTIONS, skipWebglDraws: false }
|
||||
: DENSE_GEOMETRY_SEEK_OPTIONS;
|
||||
await seekCompositionTimeline(page, time, options);
|
||||
},
|
||||
collectLayout: (time, tolerance, layout) => collectLayout(page, time, tolerance, layout),
|
||||
collectOverlap: (time) => collectOverlap(page, time),
|
||||
|
||||
@@ -759,7 +759,7 @@ async function collectMotionOverlapSamples(
|
||||
const craftTimes = buildCraftSampleTimes(grid.duration).filter((time) => time < grid.duration);
|
||||
for (const [index, time] of craftTimes.entries()) {
|
||||
progress(`craft frame at ${time}s`);
|
||||
await driver.seekGeometry(time);
|
||||
await driver.seekGeometry(time, { draws: true });
|
||||
collected.craftFrames.push(...(await collectCraftFrame(driver, time)));
|
||||
progress();
|
||||
report("craft", index + 1, craftTimes.length);
|
||||
@@ -1583,7 +1583,7 @@ export async function runAuditGrid(
|
||||
noTimeline || sweepFindings.length > 0 || wholeCompositionKeepsMoving(plan.assertions),
|
||||
},
|
||||
async (time) => {
|
||||
await driver.seekGeometry(time);
|
||||
await driver.seekGeometry(time, { draws: true });
|
||||
if (!driver.collectCraftFrame) throw new Error("craft sampling unavailable");
|
||||
return driver.collectCraftFrame(time);
|
||||
},
|
||||
|
||||
@@ -262,8 +262,8 @@ export interface CheckAuditDriver {
|
||||
getCanvas(): Promise<Canvas>;
|
||||
findAmbiguousSelectors(selectors: string[]): Promise<AnchoredLayoutIssue[]>;
|
||||
seek(time: number, screenshotFollows?: boolean): Promise<void>;
|
||||
/** Settle-free seek for the geometry-only dense content_overlap pass; only collectOverlap consumes it, and getBoundingClientRect is valid synchronously after setTime. */
|
||||
seekGeometry(time: number): Promise<void>;
|
||||
/** Settle-free seek for the dense passes; WebGL draws are skipped unless `draws` (a pass reading canvas pixels). */
|
||||
seekGeometry(time: number, options?: { draws?: boolean }): Promise<void>;
|
||||
collectLayout(
|
||||
time: number,
|
||||
tolerance: number,
|
||||
|
||||
Reference in New Issue
Block a user