Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 73 additions & 1 deletion packages/cli/src/commands/snapshot-contactSheet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ vi.mock("@hyperframes/engine", () => ({
extractMediaMetadata: vi.fn(),
}));

import snapshotCommand from "./snapshot.js";
import snapshotCommand, { SNAPSHOT_IMAGE_NAME } from "./snapshot.js";
import { planReview, reviewFrames } from "./snapshotReview.js";
import { historyDeps } from "../utils/historyOwner.js";
import { openProjectHistory } from "@hyperframes/studio-server/history";

Expand Down Expand Up @@ -307,3 +308,74 @@ describe("snapshot --keep", () => {
}
});
});

describe("snapshot --output", () => {
let project: string;

const USER_IMAGES = ["hero.png", "logo.jpg", "Notes.PNG", "frame-hero.png"];
const PREVIOUS_RUN = [
"frame-00-at-0.25s.png",
"frame-07-at-12.5s.png",
"at-3s.png",
"ref-00-at-0.25s.png",
"pair-00-at-0.25s.jpg",
"contact-sheet-2.jpg",
"beat-01-at-0.3s.png",
"seam-01-3-at-6s.png",
"review-beats.jpg",
"review-seam-01.jpg",
"review-phone-2.jpg",
];

beforeEach(() => {
project = mkdtempSync(join(tmpdir(), "hf-snapshot-output-"));
writeFileSync(join(project, "index.html"), PROJECT_HTML);
capture.screenshot.mockImplementation(async () => Buffer.from("captured PNG"));
primePage(2);
vi.spyOn(console, "log").mockImplementation(() => undefined);
vi.spyOn(console, "warn").mockImplementation(() => undefined);
});

afterEach(() => {
vi.restoreAllMocks();
rmSync(project, { recursive: true, force: true });
});

it.each([
["a snapshots folder", "snapshots"],
["the project folder", "."],
["the assets folder", "assets"],
])("replaces the previous run's images in %s and keeps every other image", async (_, sub) => {
const output = join(project, sub);
mkdirSync(output, { recursive: true });
for (const name of [...USER_IMAGES, ...PREVIOUS_RUN]) writeFileSync(join(output, name), name);

await runCommand(snapshotCommand, {
rawArgs: [project, ...["--at", "0.5,1", "--no-end", "--describe", "false", "-o", output]],
});

for (const name of USER_IMAGES) expect(readFileSync(join(output, name), "utf8")).toBe(name);
for (const name of PREVIOUS_RUN) expect(existsSync(join(output, name))).toBe(false);
for (const name of ["frame-00-at-0.5s.png", "frame-01-at-1s.png"]) {
expect(readFileSync(join(output, name), "utf8")).toBe("captured PNG");
}
});

it("names every review still with a name the next run clears", () => {
const plan = planReview(
{
window: [0, 10],
scenes: [
{ id: "a", start: 0, end: 4 },
{ id: "b", start: 4, end: 10 },
],
beats: [],
notes: [],
},
10,
);
const files = reviewFrames(plan).map((frame) => frame.file);
expect(files.some((file) => file.startsWith("seam-"))).toBe(true);
for (const file of files) expect(file).toMatch(SNAPSHOT_IMAGE_NAME);
});
});
5 changes: 4 additions & 1 deletion packages/cli/src/commands/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ export function formatSnapshotTimestamp(time: number): string {
return `${Number(time.toFixed(3))}s`;
}

export const SNAPSHOT_IMAGE_NAME =
/^(?:(?:frame-\d+-|ref-(?:\d+-)?)?at-[\d.]+s\.png|pair-(?:\d+-)?at-[\d.]+s\.jpg|(?:beat-\d+|seam-\d+-\d+)-at-[\d.]+s\.png|(?:contact-sheet|review-beats|review-phone)(?:-\d+)?\.jpg|review-seam-\d+\.jpg)$/;

/** --keep names a still by its millisecond label, so two distinct times may not share one. */
function assertDistinctKeepNames(times: number[]): void {
const timeByLabel = new Map<string, number>();
Expand Down Expand Up @@ -683,7 +686,7 @@ async function captureSnapshots(
try {
const { readdirSync } = await import("node:fs");
for (const file of opts.keep ? [] : readdirSync(snapshotDir)) {
if (/\.(png|jpg|jpeg)$/i.test(file)) {
if (SNAPSHOT_IMAGE_NAME.test(file)) {
const path = resolve(snapshotDir, file);
replaced.push(path);
rmSync(path, { force: true });
Expand Down
Loading