fix(canvas): 修复重新生成已有图片时错误将旧结果自动连线作为参考图的Bug

This commit is contained in:
Danborad
2026-09-14 00:11:26 +08:00
parent 01a2d171f5
commit 942e3dca30
3 changed files with 112 additions and 2 deletions

View File

@@ -0,0 +1,107 @@
import { describe, expect, test } from "bun:test";
import { CanvasNodeType, type CanvasConnection, type CanvasNodeData } from "../src/types/canvas";
import { imageGenerationReferenceConnections } from "../src/lib/canvas/canvas-resource-references";
describe("image generation connections", () => {
test("重新生成已有图片节点时,只有在用户显式引用源图时才连接源图,避免误将旧结果当作参考图", () => {
const sourceImageNode: CanvasNodeData = {
id: "img-1",
type: CanvasNodeType.Image,
title: "第一次生成结果",
position: { x: 0, y: 0 },
width: 300,
height: 300,
metadata: {
content: "data:image/png;base64,mock",
storageKey: "user:img-1:file",
},
};
const rootId = "img-2";
const workingNodes = [sourceImageNode];
const workingConnections: CanvasConnection[] = [];
// Case 1: 用户修改提示词重新生成(未显式 @ 源图)
const referenceImagesNone: any[] = [];
const isExistingImageNode = sourceImageNode.type === CanvasNodeType.Image && Boolean(sourceImageNode.metadata?.content);
const reuseSourceNode = false;
const connectsSelfNoMention = !isExistingImageNode || referenceImagesNone.some((img) => img.id === sourceImageNode.id);
expect(connectsSelfNoMention).toBe(false);
const batchConnectionsNoMention = [
...(reuseSourceNode ? [] : imageGenerationReferenceConnections(sourceImageNode.id, rootId, workingNodes, workingConnections, () => "c1")),
...(reuseSourceNode || !connectsSelfNoMention ? [] : [{ id: "c-self", fromNodeId: sourceImageNode.id, toNodeId: rootId }]),
];
// 验证:不应存在从 img-1 到 img-2 的连接
expect(batchConnectionsNoMention.some((c) => c.fromNodeId === sourceImageNode.id && c.toNodeId === rootId)).toBe(false);
expect(batchConnectionsNoMention.length).toBe(0);
// Case 2: 用户在提示词中显式 @图片1 进行图生图
const referenceImagesMention = [{ id: sourceImageNode.id, dataUrl: "mock" }];
const connectsSelfWithMention = !isExistingImageNode || referenceImagesMention.some((img) => img.id === sourceImageNode.id);
expect(connectsSelfWithMention).toBe(true);
const batchConnectionsWithMention = [
...(reuseSourceNode ? [] : imageGenerationReferenceConnections(sourceImageNode.id, rootId, workingNodes, workingConnections, () => "c1")),
...(reuseSourceNode || !connectsSelfWithMention ? [] : [{ id: "c-self", fromNodeId: sourceImageNode.id, toNodeId: rootId }]),
];
// 验证:显式引用时正确建立从 img-1 到 img-2 的连线
expect(batchConnectionsWithMention.some((c) => c.fromNodeId === sourceImageNode.id && c.toNodeId === rootId)).toBe(true);
});
test("若源图本身带有上游参考素材,新图片节点正确继承上游素材连线而不连接源图自身", () => {
const upstreamRefNode: CanvasNodeData = {
id: "ref-source",
type: CanvasNodeType.Image,
title: "原始参考图",
position: { x: 0, y: 0 },
width: 300,
height: 300,
metadata: {
content: "data:image/png;base64,ref",
storageKey: "user:ref-source:file",
},
};
const intermediateImageNode: CanvasNodeData = {
id: "img-intermediate",
type: CanvasNodeType.Image,
title: "中间生成图",
position: { x: 400, y: 0 },
width: 300,
height: 300,
metadata: {
content: "data:image/png;base64,mid",
storageKey: "user:img-intermediate:file",
},
};
const existingConnection: CanvasConnection = {
id: "c-upstream",
fromNodeId: upstreamRefNode.id,
toNodeId: intermediateImageNode.id,
};
const rootId = "img-new";
const workingNodes = [upstreamRefNode, intermediateImageNode];
const workingConnections = [existingConnection];
const isExistingImageNode = true;
const reuseSourceNode = false;
const referenceImagesNone: any[] = [];
const connectsSelf = !isExistingImageNode || referenceImagesNone.some((img) => img.id === intermediateImageNode.id);
const batchConnections = [
...(reuseSourceNode ? [] : imageGenerationReferenceConnections(intermediateImageNode.id, rootId, workingNodes, workingConnections, () => "c-inherited")),
...(reuseSourceNode || !connectsSelf ? [] : [{ id: "c-self", fromNodeId: intermediateImageNode.id, toNodeId: rootId }]),
];
// 验证:新节点继承了 upstreamRefNode 的连线,但绝不连接 intermediateImageNode 自身
expect(batchConnections).toHaveLength(1);
expect(batchConnections[0].fromNodeId).toBe(upstreamRefNode.id);
expect(batchConnections[0].toNodeId).toBe(rootId);
});
});