fix(cli): snapshot prints a progress line as each frame starts (#6618)

* fix(cli): snapshot prints a progress line as each frame starts

* test(cli): contact sheet tests ignore snapshot's progress lines
This commit is contained in:
Miguel Ángel
2026-10-28 06:48:26 +00:00
committed by GitHub
parent a54921e0f6
commit b288ce0187
3 changed files with 58 additions and 4 deletions
@@ -16,6 +16,11 @@ import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const errorsBesideProgress = () =>
vi
.mocked(console.error)
.mock.calls.filter(([line]) => !String(line).startsWith("[hyperframes] snapshot:"));
const capture = vi.hoisted(() => ({
evaluate: vi.fn(),
screenshot: vi.fn(async () => Buffer.from("captured PNG")),
@@ -123,7 +128,7 @@ describe("snapshot contact sheet failures", () => {
}),
).resolves.toBeDefined();
expect(console.error).not.toHaveBeenCalled();
expect(errorsBesideProgress()).toEqual([]);
for (const [index, time] of ["0.5", "1"].entries()) {
const frame = join(project, "snapshots", `frame-0${index}-at-${time}s.png`);
expect(readFileSync(frame)).toEqual(Buffer.from("captured PNG"));
@@ -161,7 +166,7 @@ describe("snapshot contact sheet failures", () => {
);
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("contact-sheet.jpg"));
expect(console.warn).not.toHaveBeenCalled();
expect(console.error).not.toHaveBeenCalled();
expect(errorsBesideProgress()).toEqual([]);
});
it("builds the sheet from this run's frames, not another frame-*.png in the folder", async () => {
@@ -262,7 +267,7 @@ describe("snapshot contact sheet failures", () => {
}
expect(readdirSync(out).filter((name) => name.startsWith("pair-"))).toEqual([]);
expect(pairSheet).toHaveBeenCalledOnce();
expect(console.error).toHaveBeenCalledOnce();
expect(errorsBesideProgress()).toHaveLength(1);
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining("Reference pair sheets skipped: Windows App Control"),
);
@@ -325,7 +330,7 @@ describe("snapshot contact sheet failures", () => {
join(project, "snapshots", `frame-0${index}-at-${time}s.png`),
),
);
expect(console.error).not.toHaveBeenCalled();
expect(errorsBesideProgress()).toEqual([]);
expect(console.warn).not.toHaveBeenCalledWith(expect.stringContaining("not recorded"));
} finally {
historyDeps.ownerWaitMs = previousWait;
@@ -0,0 +1,48 @@
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterAll, expect, it, vi } from "vitest";
import snapshotCommand from "./snapshot.js";
const root = mkdtempSync(join(tmpdir(), "hf-snapshot-progress-"));
afterAll(() => rmSync(root, { recursive: true, force: true }));
it("prints a progress line on stderr as each frame starts, and keeps stdout one --json envelope", async () => {
writeFileSync(
join(root, "index.html"),
`<!doctype html><html><body style="margin:0;background:#000">
<div id="root" data-composition-id="main" data-start="0" data-duration="5" data-width="320" data-height="180" style="width:320px;height:180px"></div>
<script>
window.__timelines = { main: { pause() {}, time() { return 0; }, duration() { return 5; }, seek() {} } };
</script></body></html>`,
);
const log = vi.spyOn(console, "log").mockImplementation(() => undefined);
const error = vi.spyOn(console, "error").mockImplementation(() => undefined);
vi.spyOn(console, "warn").mockImplementation(() => undefined);
try {
await snapshotCommand.run?.({
args: {
dir: root,
at: "1,2.5",
end: false,
json: true,
output: join(root, "out"),
describe: "false",
"browser-gpu": false,
},
} as never);
const progress = error.mock.calls
.map(([line]) => String(line))
.filter((line) => line.startsWith("[hyperframes] snapshot:"));
expect(progress).toEqual([
"[hyperframes] snapshot: frame 1/2 at 1s",
"[hyperframes] snapshot: frame 2/2 at 2.5s",
]);
expect(log).toHaveBeenCalledTimes(1);
expect(JSON.parse(String(log.mock.calls[0]?.[0])).frames).toHaveLength(2);
} finally {
vi.restoreAllMocks();
}
}, 120_000);
+1
View File
@@ -930,6 +930,7 @@ async function captureSnapshots(
for (let i = 0; i < positions.length; i++) {
const time = positions[i]!;
console.error(`[hyperframes] snapshot: frame ${i + 1}/${positions.length} at ${time}s`);
const seekOptions = { exactTime: true, waitForImagesMs: SCREENSHOT_IMAGE_WAIT_MS };
await atStep(`seeking to ${time}s, frame ${i + 1} of ${positions.length}`, () =>