diff --git a/tests/routes/canvas-chat-helpers.test.ts b/tests/routes/canvas-chat-helpers.test.ts index ed1e358e8..66605df32 100644 --- a/tests/routes/canvas-chat-helpers.test.ts +++ b/tests/routes/canvas-chat-helpers.test.ts @@ -114,6 +114,7 @@ import { buildCanvasSaveRequestBody, mergeCanvasSaveRevisionOptions, } from "@/lib/canvas/canvas-save-request"; +import { canvasService } from "@/services/canvas"; import { hasCanvasAgentNonGenerativeControlIntent, shouldBypassCanvasImagePointsPrecheckForAgentControl, @@ -388,6 +389,84 @@ test.describe("canvas chat pure helpers", () => { }); }); + test("canvas service save uses store revision fallback when options are omitted", async () => { + const canvasData = { + nodes: [], + edges: [], + selectedNodeIds: [], + viewport: { x: 0, y: 0, zoom: 1 }, + tool: "select" as const, + }; + const originalFetch = globalThis.fetch; + const hadWindow = Object.prototype.hasOwnProperty.call(globalThis, "window"); + const originalWindow = (globalThis as typeof globalThis & { window?: unknown }) + .window; + const bodies: Array> = []; + + useCanvasStore + .getState() + .setCanvasRevision( + "2026-06-22T00:00:10.000Z", + "2026-06-22T00:00:10.000Z" + ); + Object.defineProperty(globalThis, "window", { + configurable: true, + value: {}, + writable: true, + }); + globalThis.fetch = (async (_input: RequestInfo | URL, init?: RequestInit) => { + bodies.push(JSON.parse(String(init?.body || "{}"))); + return { + ok: true, + status: 200, + json: async () => ({ + success: true, + data: { updatedAt: "2026-06-22T00:00:11.000Z" }, + }), + } as Response; + }) as typeof fetch; + + try { + await canvasService.saveCanvasState( + "11111111-1111-4111-8111-111111111111", + canvasData + ); + await canvasService.saveCanvasState( + "11111111-1111-4111-8111-111111111111", + canvasData, + "canvas", + { + baseCanvasRevision: "2026-06-22T00:00:12.000Z", + } + ); + } finally { + globalThis.fetch = originalFetch; + if (hadWindow) { + Object.defineProperty(globalThis, "window", { + configurable: true, + value: originalWindow, + writable: true, + }); + } else { + Reflect.deleteProperty(globalThis, "window"); + } + useCanvasStore.getState().setCanvasRevision(null, null); + } + + expect(bodies).toHaveLength(2); + expect(bodies[0]).toMatchObject({ + canvasData, + baseCanvasRevision: "2026-06-22T00:00:10.000Z", + baseCanvasUpdatedAt: "2026-06-22T00:00:10.000Z", + }); + expect(bodies[1]).toMatchObject({ + canvasData, + workspaceType: "canvas", + baseCanvasRevision: "2026-06-22T00:00:12.000Z", + baseCanvasUpdatedAt: "2026-06-22T00:00:10.000Z", + }); + }); + const plannerContext: CanvasAgentContext = { version: 1, source: "canvas",