test: cover confirmed canvas agent deletes

This commit is contained in:
134 2026-06-23 19:24:28 +08:00
parent 6d5604a84b
commit 6d66d126c8

View File

@ -1003,4 +1003,128 @@ test.describe("canvas agent operation mutation contract", () => {
"STALE_CANVAS_REVISION"
);
});
test("confirms delete-node mutations, removes connected edges, and keeps retries idempotent", () => {
const source = buildImageNode("image-source");
const target = buildImageNode("image-delete");
const unrelated = buildImageNode("image-unrelated");
const edge = {
id: "edge-source-delete",
source: "image-source",
target: "image-delete",
type: "reference",
createdAt: "2026-06-22T00:00:00.000Z",
};
const canvasData = {
...getCanvasData([source, target, unrelated]),
edges: [edge],
selectedNodeIds: ["image-delete"],
};
const plan: CanvasOperationPlan = {
version: 1,
operationId: "op-delete-node",
operation: "delete_nodes",
projectId,
targetNodeIds: ["image-delete"],
metadata: {
messageId: "assistant-message-delete",
chatId: "chat-1",
},
};
expect(() =>
applyCanvasOperationPlanToCanvasData({
canvasData,
plan,
})
).toThrow(/需要用户确认/);
const deleted = applyCanvasOperationPlanToCanvasData({
canvasData,
plan: {
...plan,
confirmed: true,
metadata: {
...plan.metadata,
confirmedByUser: true,
},
},
});
const deletedCanvasData = deleted.canvasData as {
nodes?: any[];
edges?: any[];
selectedNodeIds?: string[];
metadata?: Record<string, any>;
};
expect(deleted.createdNodeIds).toEqual([]);
expect(deleted.updatedNodeIds).toEqual(["image-delete"]);
expect(deletedCanvasData.nodes?.map((node) => node.id).sort()).toEqual([
"image-source",
"image-unrelated",
]);
expect(deletedCanvasData.edges).toEqual([]);
expect(deletedCanvasData.selectedNodeIds).toEqual([]);
expect(
deletedCanvasData.nodes?.find((node) => node.id === "image-source")?.connections
).toEqual([]);
expect(deletedCanvasData.metadata?.canvasAgentOperationAudit).toEqual([
expect.objectContaining({
operationId: "op-delete-node",
operation: "delete_nodes",
targetNodeIds: ["image-delete"],
deletedNodeIds: ["image-delete"],
deletedEdges: [edge],
metadata: expect.objectContaining({
confirmedByUser: true,
}),
}),
]);
const retry = applyCanvasOperationPlanToCanvasData({
canvasData: deleted.canvasData,
plan: {
...plan,
confirmed: true,
metadata: {
...plan.metadata,
confirmedByUser: true,
},
},
});
expect(retry.updatedNodeIds).toEqual(["image-delete"]);
expect(getResultNodes(retry.canvasData)).toHaveLength(2);
expect(getResultEdges(retry.canvasData)).toEqual([]);
});
test("rejects confirmed stale delete-node mutations", () => {
const target = buildImageNode("image-stale-delete");
let caughtError: unknown;
try {
applyCanvasOperationPlanToCanvasData({
canvasData: getCanvasData([target]),
baseCanvasWasStale: true,
plan: {
version: 1,
operationId: "op-stale-delete-node",
operation: "delete_nodes",
projectId,
targetNodeIds: ["image-stale-delete"],
confirmed: true,
metadata: {
confirmedByUser: true,
},
},
});
} catch (error) {
caughtError = error;
}
expect(caughtError).toBeInstanceOf(CanvasAgentMutationError);
expect((caughtError as CanvasAgentMutationError).code).toBe(
"STALE_CANVAS_REVISION"
);
});
});