import { describe, expect, it } from "vitest"; import { assemblePrompt, extractMaterialRequirements } from "@/lib/prompt/assembler"; describe("prompt assembler", () => { it("preserves storyboard cards and @material references for video", () => { const result = assemblePrompt({ mode: "video", projectName: "咖啡门店", audience: "周边上班族", offer: "新品拿铁", storyboard: [ { id: "s1", title: "开场", visual: "门店外立面,参考@图片1", camera: "推进" }, { id: "s2", title: "新品", visual: "新品拿铁特写,参考@图片2", caption: "今日新品" } ], materials: [ { type: "image", url: "https://example.com/a.png", label: "@图片1" }, { type: "image", url: "https://example.com/b.png", label: "@图片2" } ] }); expect(result.prompt).toContain("咖啡门店"); expect(result.prompt).toContain("@图片1"); expect(result.prompt).toContain("@图片2"); expect(result.prompt).toContain("镜头=推进"); expect(result.warnings).toEqual([]); }); it("warns when prompt references unbound materials", () => { const result = assemblePrompt({ mode: "image", projectName: "品牌海报", manualPrompt: "使用@图片2生成主视觉", materials: [{ type: "image", url: "https://example.com/a.png", label: "@图片1" }] }); expect(result.warnings[0]).toContain("@图片2"); }); it("extracts image, video, and audio requirements", () => { expect(extractMaterialRequirements("参考@图片3、@视频2和@音频1")).toEqual({ image: 3, video: 2, audio: 1 }); }); });