87 lines
4.2 KiB
TypeScript
87 lines
4.2 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
||
|
||
import { isolateCopiedNodeMetadata, nextCopiedNodeTitle } from "@/lib/canvas/canvas-node-copy";
|
||
import { buildNodeGenerationContext } from "@/components/canvas/canvas-node-generation";
|
||
import { CanvasNodeType, type CanvasNodeData } from "@/types/canvas";
|
||
|
||
describe("canvas node copy title", () => {
|
||
test("首次复制使用 copy1,后续按已有最大序号递增", () => {
|
||
expect(nextCopiedNodeTitle("女明星角色三视图", ["女明星角色三视图"])).toBe("女明星角色三视图_copy1");
|
||
expect(nextCopiedNodeTitle("女明星角色三视图", ["女明星角色三视图", "女明星角色三视图_copy1"])).toBe("女明星角色三视图_copy2");
|
||
expect(nextCopiedNodeTitle("女明星角色三视图", ["女明星角色三视图_copy1", "女明星角色三视图_copy3"])).toBe("女明星角色三视图_copy4");
|
||
});
|
||
|
||
test("复制已有副本时仍使用原始名称计算下一序号", () => {
|
||
expect(nextCopiedNodeTitle("女明星角色三视图_copy1", ["女明星角色三视图", "女明星角色三视图_copy1"])).toBe("女明星角色三视图_copy2");
|
||
});
|
||
|
||
test("兼容旧版空格 Copy 后缀", () => {
|
||
expect(nextCopiedNodeTitle("女明星角色三视图 Copy", ["女明星角色三视图", "女明星角色三视图 Copy"])).toBe("女明星角色三视图_copy1");
|
||
});
|
||
|
||
test("同一批粘贴可以通过预留标题连续分配序号", () => {
|
||
const titles = new Set(["节点", "节点_copy1"]);
|
||
const first = nextCopiedNodeTitle("节点", titles);
|
||
titles.add(first);
|
||
const second = nextCopiedNodeTitle("节点", titles);
|
||
expect([first, second]).toEqual(["节点_copy2", "节点_copy3"]);
|
||
});
|
||
});
|
||
|
||
describe("canvas generation copy metadata", () => {
|
||
test("媒体副本保留提示词与参考字段,并明确原地回填生成结果", () => {
|
||
const source: CanvasNodeData = {
|
||
id: "source",
|
||
type: CanvasNodeType.Video,
|
||
title: "镜头",
|
||
position: { x: 0, y: 0 },
|
||
width: 340,
|
||
height: 240,
|
||
metadata: {
|
||
content: "video-url",
|
||
prompt: "相同提示词",
|
||
videoStartFrameNodeId: "reference-start",
|
||
videoEndFrameNodeId: "reference-end",
|
||
generationResultPlacement: "new-version",
|
||
generationEffectKeys: ["attach-node:source-task:source:0"],
|
||
},
|
||
};
|
||
|
||
const metadata = isolateCopiedNodeMetadata(source, new Map([[source.id, "copy"]]));
|
||
|
||
expect(metadata.prompt).toBe("相同提示词");
|
||
expect(metadata.videoStartFrameNodeId).toBe("reference-start");
|
||
expect(metadata.videoEndFrameNodeId).toBe("reference-end");
|
||
expect(metadata.copiedFromNodeId).toBe("source");
|
||
expect(metadata.generationResultPlacement).toBe("replace-node");
|
||
expect(metadata.generationEffectKeys).toBeUndefined();
|
||
expect(source.metadata?.generationEffectKeys).toEqual(["attach-node:source-task:source:0"]);
|
||
});
|
||
|
||
test("复制到副本的入边继续解析为同一张参考图", () => {
|
||
const reference: CanvasNodeData = {
|
||
id: "reference",
|
||
type: CanvasNodeType.Image,
|
||
title: "角色参考",
|
||
position: { x: 0, y: 0 },
|
||
width: 340,
|
||
height: 240,
|
||
metadata: { content: "reference-url", mimeType: "image/png" },
|
||
};
|
||
const copy: CanvasNodeData = {
|
||
id: "copy",
|
||
type: CanvasNodeType.Image,
|
||
title: "结果_copy1",
|
||
position: { x: 400, y: 0 },
|
||
width: 340,
|
||
height: 240,
|
||
metadata: { content: "old-result", prompt: "保持角色一致", copiedFromNodeId: "source", generationResultPlacement: "replace-node" },
|
||
};
|
||
|
||
const context = buildNodeGenerationContext(copy.id, [reference, copy], [{ id: "copy-reference", fromNodeId: reference.id, toNodeId: copy.id }], copy.metadata!.prompt!, []);
|
||
|
||
expect(context.prompt).toBe("保持角色一致");
|
||
expect(context.referenceImages.map((image) => image.id)).toEqual([reference.id]);
|
||
});
|
||
});
|