Files
ttstd-infinite-canvas/web/test/canvas-node-copy.test.ts
T
2026-10-05 15:26:51 +08:00

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]);
});
});