Files
ttstd-infinite-canvas/web/test/workflow-shot-generation.test.ts

86 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, test } from "bun:test";
import { defaultConfig } from "../src/stores/use-config-store";
import { submitBackendGenerationTask, type GenerationTaskDependencies } from "../src/services/api/generation-task";
import type { GenerationTask } from "../src/services/api/task-center";
import type { ProjectDetail } from "../src/services/api/projects";
import { buildShotAssetReferenceContext, resolveShotAssetMentionPrompt } from "../src/pages/projects/detail/workflow-shot-references";
test("shot asset prompt keeps character names and maps character image, voice and scene assets", () => {
const detail = {
assets: [
{
id: "character-1",
title: "张天昊",
category: "character",
mediaType: "image",
primaryVersionId: "character-version-1",
character: {
versionId: "character-version-1",
definition: { voiceLanguage: "普通话", voiceAge: "青年男性", voiceTimbre: "略带疲惫和震惊" },
representations: [{ id: "representation-1", resourceId: "character-image-1", mediaType: "image/png", role: "primary" }],
voice: { profile: { sampleResourceId: "character-audio-1", language: "普通话", timbre: "沉稳" }, instructions: "内心独白语气" },
},
},
{
id: "scene-1",
title: "坑底场景",
category: "environment",
mediaType: "image",
primaryVersionId: "scene-version-1",
storageKey: "resource:scene-image-1",
},
],
shotReferences: [
{ shotId: "shot-1", assetVersionId: "character-version-1", status: "linked" },
{ shotId: "shot-1", assetVersionId: "scene-version-1", status: "linked" },
],
} as ProjectDetail;
const context = buildShotAssetReferenceContext(detail, "shot-1");
const prompt = resolveShotAssetMentionPrompt("张天昊在 @[asset:scene-1] 睁开眼睛", context);
expect(context.referenceImages).toHaveLength(2);
expect(context.referenceAudios).toHaveLength(1);
expect(context.referenceAudios[0]?.storageKey).toBe("resource:character-audio-1");
expect(context.resolvedCharacterVersions).toEqual([{ assetId: "character-1", versionId: "character-version-1" }]);
expect(prompt).toContain("张天昊在 图片2 睁开眼睛");
expect(prompt).toContain("- 张天昊:人物参考:图片1;声音参考:音频1");
expect(prompt).toContain("声音说明:普通话;青年男性;略带疲惫和震惊;内心独白语气");
expect(prompt).toContain("- 坑底场景:场景参考:图片2");
});
test("background generation submission returns after task creation without waiting", async () => {
let waitCalls = 0;
const task = {
id: "task-1",
type: "canvas_video",
status: "queued",
prompt: "角色表演",
attempts: 0,
createdAt: "2026-08-30T00:00:00.000Z",
updatedAt: "2026-08-30T00:00:00.000Z",
} satisfies GenerationTask;
const dependencies: GenerationTaskDependencies = {
createTask: async () => task,
waitTask: async () => {
waitCalls += 1;
throw new Error("should not wait");
},
runLocal: async () => ({ mode: "video" }),
createId: () => "id-1",
now: () => "2026-08-30T00:00:00.000Z",
};
const submitted = await submitBackendGenerationTask({
projectId: "project-1",
mode: "video",
prompt: "角色表演",
config: { ...defaultConfig, model: "MiniMax-H3", videoModel: "MiniMax-H3" },
metadata: { shotId: "shot-1", videoEditOperation: "reference_to_video" },
}, dependencies);
expect(submitted).toBe(task);
expect(waitCalls).toBe(0);
});