feat(film): capture manifest + validation
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"viewport": { "width": 1920, "height": 1080, "deviceScaleFactor": 2 },
|
||||||
|
"theme": "dark",
|
||||||
|
"baseUrl": "http://localhost:5173",
|
||||||
|
"captures": [
|
||||||
|
{ "id": "storm-intel", "role": "owner", "route": "/owner/storm-intel", "waitMs": 2000 },
|
||||||
|
{ "id": "territory-map", "role": "owner", "route": "/owner/maps", "waitMs": 2500 },
|
||||||
|
{ "id": "pro-canvas", "role": "owner", "route": "/owner/pro-canvas", "waitMs": 1800 },
|
||||||
|
{ "id": "lead-verification", "role": "owner", "route": "/lead-verification", "waitMs": 1800 },
|
||||||
|
{ "id": "dispatch", "role": "owner", "route": "/owner/dispatch", "waitMs": 2500 },
|
||||||
|
{ "id": "people-skills", "role": "owner", "route": "/owner/people", "waitMs": 1800 },
|
||||||
|
{ "id": "kanban", "role": "owner", "route": "/owner/kanban", "waitMs": 1800 },
|
||||||
|
{ "id": "settings-access", "role": "owner", "route": "/owner/settings", "waitMs": 1800 },
|
||||||
|
{ "id": "projects", "role": "owner", "route": "/owner/projects", "waitMs": 1800 },
|
||||||
|
{ "id": "estimates", "role": "owner", "route": "/owner/estimates", "waitMs": 1800 },
|
||||||
|
{ "id": "sub-tasks-owner", "role": "owner", "route": "/owner/subcontractor-tasks", "waitMs": 1800 },
|
||||||
|
{ "id": "owner-snapshot", "role": "owner", "route": "/owner/snapshot", "waitMs": 2000 },
|
||||||
|
{ "id": "leaderboard", "role": "owner", "route": "/admin/leaderboard", "waitMs": 1800 },
|
||||||
|
{ "id": "rep-leads", "role": "agentCody", "route": "/emp/fa/leads", "waitMs": 1800 },
|
||||||
|
{ "id": "rep-dashboard", "role": "agentCody", "route": "/emp/fa/dashboard", "waitMs": 1800 },
|
||||||
|
{ "id": "sub-dashboard", "role": "subCarlos", "route": "/subcontractor/dashboard", "waitMs": 1800 },
|
||||||
|
{ "id": "sub-projects", "role": "subCarlos", "route": "/subcontractor/projects", "waitMs": 1800 }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import manifest from "./captures.manifest.json";
|
||||||
|
import { validateManifest, type Manifest } from "./captures";
|
||||||
|
|
||||||
|
describe("captures manifest", () => {
|
||||||
|
it("passes validation", () => {
|
||||||
|
expect(validateManifest(manifest as Manifest)).toEqual([]);
|
||||||
|
});
|
||||||
|
it("has unique ids", () => {
|
||||||
|
const ids = (manifest as Manifest).captures.map((c) => c.id);
|
||||||
|
expect(new Set(ids).size).toBe(ids.length);
|
||||||
|
});
|
||||||
|
it("captures in dark theme", () => {
|
||||||
|
expect((manifest as Manifest).theme).toBe("dark");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
export type CaptureRole = "owner" | "agentCody" | "subCarlos";
|
||||||
|
|
||||||
|
export interface Capture {
|
||||||
|
id: string;
|
||||||
|
role: CaptureRole;
|
||||||
|
route: string;
|
||||||
|
waitMs?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Manifest {
|
||||||
|
viewport: { width: number; height: number; deviceScaleFactor: number };
|
||||||
|
theme: "dark" | "light";
|
||||||
|
baseUrl: string;
|
||||||
|
captures: Capture[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const VALID_ROLES: CaptureRole[] = ["owner", "agentCody", "subCarlos"];
|
||||||
|
|
||||||
|
export function validateManifest(m: Manifest): string[] {
|
||||||
|
const errors: string[] = [];
|
||||||
|
const seen = new Set<string>();
|
||||||
|
if (!m.baseUrl?.startsWith("http")) errors.push("baseUrl must be an http(s) URL");
|
||||||
|
if (m.theme !== "dark" && m.theme !== "light") errors.push("theme must be dark|light");
|
||||||
|
for (const c of m.captures) {
|
||||||
|
if (!c.id) errors.push("capture missing id");
|
||||||
|
if (seen.has(c.id)) errors.push(`duplicate id: ${c.id}`);
|
||||||
|
seen.add(c.id);
|
||||||
|
if (!c.route?.startsWith("/")) errors.push(`${c.id}: route must start with "/"`);
|
||||||
|
if (!VALID_ROLES.includes(c.role)) errors.push(`${c.id}: unknown role "${c.role}"`);
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user