import type { MediaEditPlan, MediaRender } from "@rakazo/contracts"; import { describe, expect, it } from "vitest"; import { assetThumbUrl, blockers, canApprove, canShare, formatDuration, isRenderActive, libraryAccess, mediaNotificationRoute, projectReadiness, projectVariants, renderFileUrl, shareFileName, shouldPollProject, uploadsFromDevice, variantState, } from "./media-project"; function plan( id: string, profileId: string, version: number, createdAt = "2026-01-01T00:00:00.000Z", ) { return { id, profileId, version, createdAt } as MediaEditPlan; } function render(id: string, planId: string, overrides: Partial = {}): MediaRender { return { id, planId, projectId: "p1", profileId: "example-short-vertical", quality: "draft", status: "done", progress: 1, outputs: [{ kind: "video", artifactId: null, fileName: "video.mp4", sizeBytes: 10 }], gateReport: null, ffprobe: null, error: null, createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", ...overrides, }; } const profiles = [{ id: "short", name: "Short" }]; function variantFor(renders: MediaRender[]) { const [variant] = projectVariants({ profileIds: ["short"], plans: [plan("plan1", "short", 1)], renders, profiles, }); if (!variant) throw new Error("no variant"); return variant; } describe("projectVariants", () => { it("uses the newest plan version per profile and its renders only", () => { const variants = projectVariants({ profileIds: ["short", "wide", "missing"], plans: [plan("a1", "short", 1), plan("a2", "short", 2), plan("b1", "wide", 1)], renders: [ render("r-old", "a1", { createdAt: "2026-01-02T00:00:00.000Z" }), render("r-new", "a2"), ], profiles, }); expect( variants.map((variant) => [variant.profileId, variant.profileName, variant.plan.id]), ).toEqual([ ["short", "Short", "a2"], ["wide", "wide", "b1"], ]); expect(variants[0]?.latest?.id).toBe("r-new"); expect(variants[1]?.latest).toBeNull(); }); it("previews the final render once it is done, else the draft", () => { const draft = render("d", "plan1", { createdAt: "2026-01-01T00:00:00.000Z" }); const finalRunning = render("f", "plan1", { quality: "final", status: "rendering", outputs: [], createdAt: "2026-01-02T00:00:00.000Z", }); expect(variantFor([draft, finalRunning]).preview?.id).toBe("d"); const finalDone = { ...finalRunning, status: "done" as const, outputs: draft.outputs }; expect(variantFor([draft, finalDone]).preview?.id).toBe("f"); }); }); describe("variant state and actions", () => { it("is planned without renders and can be approved", () => { const variant = variantFor([]); expect(variantState(variant)).toBe("planned"); expect(canApprove(variant)).toBe(true); expect(canShare(variant)).toBe(false); }); it("is rendering while a draft runs and cannot be approved", () => { const variant = variantFor([render("d", "plan1", { status: "gating", progress: 0.9 })]); expect(variantState(variant)).toBe("rendering"); expect(canApprove(variant)).toBe(false); }); it("approves a finished draft", () => { const variant = variantFor([render("d", "plan1")]); expect(variantState(variant)).toBe("draft_ready"); expect(canApprove(variant)).toBe(true); expect(canShare(variant)).toBe(false); }); it("shares only a finished final render", () => { const running = variantFor([render("f", "plan1", { quality: "final", status: "queued" })]); expect(variantState(running)).toBe("approved_rendering"); expect(canShare(running)).toBe(false); const done = variantFor([render("f", "plan1", { quality: "final" })]); expect(variantState(done)).toBe("ready"); expect(canShare(done)).toBe(true); expect(canApprove(done)).toBe(false); }); it("never shares a blocked render and lists its blockers", () => { const blocked = render("f", "plan1", { quality: "final", status: "blocked", gateReport: { profileId: "short", passed: false, checkedAt: "2026-01-01T00:00:00.000Z", sampledFrames: 10, autoFixRound: 3, issues: [ { check: "consent", severity: "block", code: "consent_missing", message: "Consent missing", }, { check: "text", severity: "warn", code: "long", message: "Long caption" }, ], }, }); const variant = variantFor([blocked]); expect(variantState(variant)).toBe("blocked"); expect(canShare(variant)).toBe(false); expect(canApprove(variant)).toBe(false); expect(blockers(variant.latest).map((issue) => issue.code)).toEqual(["consent_missing"]); }); it("allows another try after a failure", () => { const variant = variantFor([render("d", "plan1", { status: "failed", outputs: [] })]); expect(variantState(variant)).toBe("failed"); expect(canApprove(variant)).toBe(true); }); }); describe("polling", () => { it("polls only while a render is queued, rendering, or gating", () => { expect(isRenderActive(null)).toBe(false); for (const status of ["queued", "rendering", "gating"] as const) { expect(shouldPollProject([render("r", "p", { status })])).toBe(true); } for (const status of ["done", "blocked", "failed", "canceled"] as const) { expect(shouldPollProject([render("r", "p", { status })])).toBe(false); } }); }); describe("projectReadiness", () => { const device = "src-phone"; it("waits for this device's uploads first", () => { expect( projectReadiness( [ { sourceId: device, storage: "remote", ingestState: "awaiting_upload" }, { sourceId: device, storage: "uploaded", ingestState: "analyzed" }, ], true, device, ), ).toBe("uploading"); }); it("treats items another device must upload as processing", () => { const assets = [ { sourceId: "src-mac", storage: "remote" as const, ingestState: "awaiting_upload" as const }, ]; expect(projectReadiness(assets, true, device)).toBe("processing"); expect(uploadsFromDevice(assets, device)).toEqual([]); expect(uploadsFromDevice(assets, null)).toEqual([]); }); it("waits for analysis when it is available", () => { const assets = [ { sourceId: device, storage: "uploaded" as const, ingestState: "proxied" as const }, ]; expect(projectReadiness(assets, true, device)).toBe("processing"); expect(projectReadiness(assets, false, device)).toBe("ready"); }); it("ignores failed items unless all failed", () => { expect( projectReadiness( [ { sourceId: device, storage: "uploaded", ingestState: "failed" }, { sourceId: device, storage: "uploaded", ingestState: "analyzed" }, ], true, device, ), ).toBe("ready"); expect( projectReadiness( [{ sourceId: device, storage: "uploaded", ingestState: "failed" }], true, device, ), ).toBe("failed"); expect(projectReadiness([], true, device)).toBe("processing"); }); }); describe("urls and names", () => { it("builds render and thumbnail routes", () => { expect(renderFileUrl("https://api.example.test/", "r1", "video.mp4")).toBe( "https://api.example.test/api/media/renders/r1/files/video.mp4", ); expect(renderFileUrl("https://api.example.test", "r1", "video.mp4", true)).toBe( "https://api.example.test/api/media/renders/r1/files/video.mp4?download=1", ); expect(assetThumbUrl("https://api.example.test", "a 1")).toBe( "https://api.example.test/api/media/assets/a%201/thumb", ); }); it("names shared files from the render id", () => { expect(shareFileName("r1", "video.MP4")).toBe("render-r1.mp4"); expect(shareFileName("../r1", "video")).toBe("render-r1.mp4"); }); it("formats durations", () => { expect(formatDuration(0)).toBe("0:00"); expect(formatDuration(65_400)).toBe("1:05"); expect(formatDuration(3_725_000)).toBe("1:02:05"); }); }); describe("mediaNotificationRoute", () => { it("opens the project of a render push", () => { expect( mediaNotificationRoute({ kind: "media.render", projectId: "p1", renderId: "r1", status: "done", }), ).toEqual({ pathname: "/media-project", params: { projectId: "p1" } }); }); it("ignores other pushes and malformed ids", () => { expect(mediaNotificationRoute(null)).toBeNull(); expect(mediaNotificationRoute({ kind: "completion", threadId: "t1" })).toBeNull(); expect(mediaNotificationRoute({ kind: "media.render", projectId: "../x" })).toBeNull(); expect(mediaNotificationRoute({ kind: "media.render" })).toBeNull(); }); }); describe("libraryAccess", () => { it("distinguishes full, limited, undecided, denied, and blocked access", () => { expect( libraryAccess({ granted: true, canAskAgain: true, status: "granted", accessPrivileges: "all", }), ).toBe("all"); expect( libraryAccess({ granted: true, canAskAgain: true, status: "granted", accessPrivileges: "limited", }), ).toBe("limited"); expect(libraryAccess({ granted: false, canAskAgain: true, status: "undetermined" })).toBe( "undetermined", ); expect(libraryAccess({ granted: false, canAskAgain: true, status: "denied" })).toBe("denied"); expect(libraryAccess({ granted: false, canAskAgain: false, status: "denied" })).toBe("blocked"); }); });