import { describe, expect, it } from "vitest"; import { BAILIAN_27_VIDEO_MODEL, BAILIAN_30_VIDEO_MODEL, videoImageFileError, videoMaterialError } from "@/lib/video-input"; import { SEEDANCE_20_MODEL, SEEDANCE_25_MODEL } from "@/lib/video-settings"; const images = (count: number) => Array.from({ length: count }, () => ({ type: "image" as const })); describe("video input mode limits", () => { it("preserves two-frame mode while allowing ten Wan 3.0 reference images", () => { expect(videoMaterialError({ engine: "bailian", model: BAILIAN_27_VIDEO_MODEL, inputMode: "frames" }, images(2))).toBeNull(); expect(videoMaterialError({ engine: "bailian", model: BAILIAN_27_VIDEO_MODEL, inputMode: "frames" }, images(3))).toMatch(/Wan 3.0/); expect(videoMaterialError({ engine: "bailian", model: BAILIAN_30_VIDEO_MODEL, inputMode: "reference" }, images(10))).toBeNull(); expect(videoMaterialError({ engine: "bailian", model: BAILIAN_30_VIDEO_MODEL, inputMode: "reference" }, images(11))).toMatch(/10 张/); expect(videoMaterialError({ engine: "bailian", model: BAILIAN_30_VIDEO_MODEL, inputMode: "frames" }, images(3))).toMatch(/首尾帧/); }); it("explains MiniMax first-frame and reference alternatives", () => { expect(videoMaterialError({ engine: "minimax", model: "MiniMax-H3", inputMode: "frames" }, images(2))).toMatch(/切换到「多图参考」/); expect(videoMaterialError({ engine: "minimax", model: "MiniMax-H3", inputMode: "reference" }, images(9))).toBeNull(); expect(videoMaterialError({ engine: "minimax", model: "MiniMax-H3", inputMode: "reference" }, images(10))).toMatch(/9 张/); }); it("allows Seedance 2.0 category maxima and rejects audio alone", () => { const selection = { engine: "seedance" as const, model: SEEDANCE_20_MODEL, inputMode: "reference" as const }; expect(videoMaterialError(selection, [...images(9), ...Array.from({ length: 3 }, () => ({ type: "video" as const })), ...Array.from({ length: 3 }, () => ({ type: "audio" as const }))])).toBeNull(); expect(videoMaterialError(selection, [{ type: "audio" }])).toMatch(/不能单独/); expect(videoMaterialError({ ...selection, model: SEEDANCE_25_MODEL }, [{ type: "audio" }])).toBeNull(); }); it("explains local reference-image format and size failures", () => { const selection = { engine: "bailian" as const, model: BAILIAN_30_VIDEO_MODEL, inputMode: "reference" as const }; expect(videoImageFileError(selection, { name: "design.heic", size: 12, type: "image/heic" })).toMatch(/格式/); expect(videoImageFileError(selection, { name: "design.png", size: 21 * 1024 * 1024, type: "image/png" })).toMatch(/20 MB/); }); });