5069354df3
CI / Lint (push) Has been cancelled
CI / Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Build (push) Has been cancelled
Bump Nix package on release / bump (release) Has been cancelled
Update Homebrew Cask / update-cask (release) Has been cancelled
123 lines
3.0 KiB
TypeScript
123 lines
3.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { GUIDE_SCHEMA_VERSION, type GuideSession } from "./contracts";
|
|
import { buildGuideVideoAnnotations, buildGuideVideoSpeedRegions } from "./videoAnnotations";
|
|
|
|
function createSession(): GuideSession {
|
|
return {
|
|
schemaVersion: GUIDE_SCHEMA_VERSION,
|
|
recordingId: "recording-1",
|
|
videoPath: "recording.mp4",
|
|
guidePath: "recording.guide.json",
|
|
outputDir: "recording-guide",
|
|
status: "draft-ready",
|
|
events: [],
|
|
snapshots: [],
|
|
ocrBlocks: [],
|
|
candidates: [
|
|
{
|
|
id: "candidate-1",
|
|
eventId: "event-1",
|
|
timeMs: 1200,
|
|
action: "click",
|
|
targetText: "Settings",
|
|
targetRole: "button",
|
|
position: {
|
|
normalizedX: 0.2,
|
|
normalizedY: 0.25,
|
|
xPercent: 20,
|
|
yPercent: 25,
|
|
description: "top left",
|
|
},
|
|
nearbyText: ["Settings"],
|
|
confidence: 0.91,
|
|
},
|
|
],
|
|
generatedGuide: {
|
|
title: "Guide",
|
|
steps: [
|
|
{
|
|
id: "step-1",
|
|
order: 1,
|
|
title: "Open settings",
|
|
instruction: "Click Settings.",
|
|
sourceCandidateId: "candidate-1",
|
|
},
|
|
],
|
|
},
|
|
createdAt: "2026-06-04T00:00:00.000Z",
|
|
updatedAt: "2026-06-04T00:00:00.000Z",
|
|
};
|
|
}
|
|
|
|
describe("buildGuideVideoAnnotations", () => {
|
|
it("creates caption and pointer annotations from generated guide candidates", () => {
|
|
let id = 1;
|
|
let zIndex = 1;
|
|
const annotations = buildGuideVideoAnnotations(createSession(), {
|
|
nextId: () => `guide-video-${id++}`,
|
|
nextZIndex: () => zIndex++,
|
|
});
|
|
|
|
expect(annotations).toHaveLength(3);
|
|
expect(annotations[0]).toMatchObject({
|
|
id: "guide-video-1",
|
|
type: "text",
|
|
startMs: 1200,
|
|
content: "1. Click Settings.",
|
|
});
|
|
expect(annotations[0]?.endMs).toBe(3200);
|
|
expect(annotations[0]?.position.x).toBeGreaterThan(20);
|
|
expect(annotations[1]?.endMs).toBe(3200);
|
|
expect(annotations[1]?.position.x).toBeGreaterThan((annotations[0]?.position.x ?? 0) + 34);
|
|
expect(annotations[1]?.position.y).toBeCloseTo(30.5);
|
|
expect(annotations[1]).toMatchObject({
|
|
id: "guide-video-2",
|
|
type: "magnifier",
|
|
magnifierData: {
|
|
target: { x: 20, y: 25 },
|
|
zoom: 2.2,
|
|
shape: "circle",
|
|
caption: "Settings",
|
|
},
|
|
});
|
|
expect(annotations[2]).toMatchObject({
|
|
id: "guide-video-3",
|
|
type: "figure",
|
|
endMs: 3200,
|
|
figureData: {
|
|
arrowDirection: "left",
|
|
color: "#34B27B",
|
|
},
|
|
});
|
|
expect(annotations[2]?.position.x).toBeGreaterThan(20);
|
|
});
|
|
|
|
it("returns an empty list when no draft exists", () => {
|
|
const session = createSession();
|
|
session.generatedGuide = undefined;
|
|
|
|
const annotations = buildGuideVideoAnnotations(session, {
|
|
nextId: () => "unused",
|
|
nextZIndex: () => 1,
|
|
});
|
|
|
|
expect(annotations).toEqual([]);
|
|
});
|
|
|
|
it("creates 0.3x speed regions for two seconds at each guide point", () => {
|
|
let id = 1;
|
|
const speedRegions = buildGuideVideoSpeedRegions(createSession(), {
|
|
nextId: () => `guide-speed-${id++}`,
|
|
});
|
|
|
|
expect(speedRegions).toEqual([
|
|
{
|
|
id: "guide-speed-1",
|
|
startMs: 1200,
|
|
endMs: 3200,
|
|
speed: 0.3,
|
|
},
|
|
]);
|
|
});
|
|
});
|