import type { MediaJobBlock } from "@rakazo/contracts"; import type { ReactNode } from "react"; import { renderToString } from "react-dom/server"; import { describe, expect, it, vi } from "vitest"; vi.mock("@lingui/react/macro", () => { const t = (parts: TemplateStringsArray, ...values: unknown[]) => parts.reduce((text, part, index) => `${text}${part}${values[index] ?? ""}`, ""); return { useLingui: () => ({ t }), Trans: ({ children }: { children: ReactNode }) => children }; }); vi.mock("@lingui/core/macro", () => ({ t: (parts: TemplateStringsArray, ...values: unknown[]) => parts.reduce((out, part, index) => `${out}${String(values[index - 1])}${part}`), })); vi.mock("../../pages/shell/message-cards", () => ({ ArtifactImage: ({ artifactId, name }: { artifactId: string; name: string }) => ( {name} ), })); vi.mock("../ArtifactFileCard", () => ({ ArtifactFileCard: ({ name }: { name: string }) => {name}, })); vi.mock("./MediaPlayer", () => ({ MediaPlayer: ({ artifactId, kind }: { artifactId: string; kind: string }) => ( ), })); vi.mock("../../lib/rpc", () => ({ rpc: {}, selectedSpaceId: () => null })); vi.mock("../../lib/artifact-url", () => ({ artifactUrl: (artifactId: string, options?: { download?: boolean }) => `/artifact/${artifactId}${options?.download ? "?download=1" : ""}`, })); import { exportPresetsFor, isActiveMediaStatus, MediaCardView } from "./MediaCard"; const video = { artifactId: "video-1", kind: "video" as const, mimeType: "video/mp4", name: "clip.mp4", size: 2048, width: 1920, height: 1080, }; function block(overrides: Partial): MediaJobBlock { return { kind: "media", jobId: "job-1", operation: "edit_video", status: "done", title: "Cut the intro", outputs: [], ...overrides, }; } const everything = { export: true, transcribe: true }; const noop = async () => undefined; describe("media card", () => { it.each([ ["queued", "Queued"], ["waiting", "Waiting for GPU"], ["running", "Working…"], ["done", "Done"], ["failed", "Failed"], ["cancelled", "Cancelled"], ] as const)("labels a %s job as %s", (status, label) => { const html = renderToString(); expect(html).toContain(`data-status="${status}"`); expect(html).toContain(label); expect(html).toContain("Cut the intro"); }); it("shows progress and a cancel action while the job runs, and no result actions", () => { const html = renderToString( , ); expect(html).toContain('role="progressbar"'); expect(html).toContain('aria-valuenow="42"'); expect(html).toContain("width:42%"); expect(html).toContain("Cancel"); expect(html).not.toContain("Export"); expect(html).not.toContain("Transcribe"); }); it("leaves the progress value out when the backend does not report one", () => { const html = renderToString(); expect(html).toContain('role="progressbar"'); expect(html).not.toContain("aria-valuenow"); }); it("offers download, export and transcribe for a finished video", () => { const html = renderToString( , ); expect(html).toContain('data-player="video"'); expect(html).toContain('href="/artifact/video-1?download=1"'); expect(html).toContain('download="clip.mp4"'); expect(html).toContain('aria-label="Download clip.mp4"'); expect(html).toContain("Export"); expect(html).toContain("Transcribe"); expect(html).not.toContain("progressbar"); expect(html).not.toContain("Cancel"); }); it("shows a finished analysis as done, with nothing to open or act on", () => { const html = renderToString( , ); expect(html).toContain('data-status="done"'); expect(html).toContain("Find the cut points"); expect(html).toContain("Done"); expect(html).toContain("lucide-scan-search"); expect(html).not.toContain("Download"); expect(html).not.toContain("Export"); expect(html).not.toContain("Transcribe"); }); it("offers only what the space can run and what fits the output", () => { const audio = { ...video, artifactId: "audio-1", kind: "audio" as const, name: "take.m4a" }; const onlyTranscribe = renderToString( , ); expect(onlyTranscribe).toContain('data-player="audio"'); expect(onlyTranscribe).toContain("Transcribe"); expect(onlyTranscribe).not.toContain("Export"); const nothingAvailable = renderToString( , ); expect(nothingAvailable).toContain("Download clip.mp4"); expect(nothingAvailable).not.toContain("Export"); expect(nothingAvailable).not.toContain("Transcribe"); }); it("renders images as thumbnails and subtitle files as file cards", () => { const html = renderToString( , ); expect(html).toContain('data-artifact="image-1"'); expect(html).toContain("clip.srt"); expect(html).toContain("clip.vtt"); expect(html).not.toContain("Transcribe"); }); it("names the platform of an export, and its first problem only when the check did not pass", () => { const tiktok = { ...video, artifactId: "tiktok-1", platform: "tiktok" as const, check: { status: "pass" as const, issues: [] }, }; const shorts = { ...video, artifactId: "shorts-1", platform: "youtube-shorts" as const, check: { status: "warn" as const, issues: [ { code: "loudness_off" as const, targetLufs: -14, actualLufs: -18 }, { code: "true_peak_high" as const, maxDb: -1, actualDb: 0 }, ], }, }; const html = renderToString( , ); expect(html).toContain('

TikTok

'); expect(html).toContain( '

Too quiet for YouTube Shorts (target -14 LUFS)

', ); expect(html).not.toContain("Peaks too high"); expect(html.match(/text-ui-body-sm text-(muted-foreground|warning|destructive)/g)).toHaveLength( 2, ); }); it("lists skipped platforms, which also explain a job that rendered nothing", () => { const skipped = [ { platform: "snapchat-spotlight" as const, issues: [{ code: "too_long" as const, maxMs: 60_000, actualMs: 75_000 }], }, ]; const partial = renderToString( , ); expect(partial).toContain("Too long for Snapchat Spotlight (max 1:00)"); const failed = renderToString( , ); expect(failed).toContain("Too long for Snapchat Spotlight (max 1:00)"); expect(failed).not.toContain("Not exported"); }); it("shows why a job failed", () => { const html = renderToString( , ); expect(html).toContain("GPU server is unreachable"); }); }); describe("exportPresetsFor", () => { it("leaves out the shape the video already has, labelled by aspect ratio elsewhere", () => { expect(exportPresetsFor({ width: 1920, height: 1080 })).toEqual([ "vertical", "square", "portrait", "classic", "cinema", ]); expect(exportPresetsFor({ width: 1080, height: 1920, preset: "vertical" })).not.toContain( "vertical", ); expect(exportPresetsFor({})).toHaveLength(6); }); }); describe("isActiveMediaStatus", () => { it("treats queued, waiting and running as active", () => { expect(["queued", "waiting", "running"].every((s) => isActiveMediaStatus(s as never))).toBe( true, ); expect(isActiveMediaStatus("done")).toBe(false); }); });