diff --git a/components/canvas/__tests__/compare-node.test.tsx b/components/canvas/__tests__/compare-node.test.tsx new file mode 100644 index 0000000..93b8df6 --- /dev/null +++ b/components/canvas/__tests__/compare-node.test.tsx @@ -0,0 +1,160 @@ +import React from "react"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { renderToStaticMarkup } from "react-dom/server"; + +type StoreState = { + nodes: Array<{ id: string; type?: string; data?: unknown }>; + edges: Array<{ + id: string; + source: string; + target: string; + className?: string; + targetHandle?: string; + }>; +}; + +const storeState: StoreState = { + nodes: [], + edges: [], +}; + +const compareSurfaceSpy = vi.fn(); + +vi.mock("@xyflow/react", () => ({ + Handle: () => null, + Position: { Left: "left", Right: "right" }, + useStore: (selector: (state: StoreState) => unknown) => selector(storeState), +})); + +vi.mock("../nodes/base-node-wrapper", () => ({ + default: ({ children }: { children: React.ReactNode }) =>
{children}
, +})); + +vi.mock("../nodes/compare-surface", () => ({ + default: (props: unknown) => { + compareSurfaceSpy(props); + return null; + }, +})); + +import CompareNode from "../nodes/compare-node"; + +describe("CompareNode render preview inputs", () => { + beforeEach(() => { + storeState.nodes = []; + storeState.edges = []; + compareSurfaceSpy.mockReset(); + }); + + it("passes previewInput to CompareSurface for a connected render node without final output", () => { + storeState.nodes = [ + { + id: "image-1", + type: "image", + data: { url: "https://cdn.example.com/source.png" }, + }, + { + id: "render-1", + type: "render", + data: {}, + }, + ]; + storeState.edges = [ + { id: "edge-image-render", source: "image-1", target: "render-1" }, + { + id: "edge-render-compare", + source: "render-1", + target: "compare-1", + targetHandle: "left", + }, + ]; + + renderToStaticMarkup( + React.createElement(CompareNode, { + id: "compare-1", + data: { leftUrl: "https://cdn.example.com/render-output.png" }, + selected: false, + dragging: false, + zIndex: 0, + isConnectable: true, + type: "compare", + xPos: 0, + yPos: 0, + width: 500, + height: 380, + sourcePosition: undefined, + targetPosition: undefined, + positionAbsoluteX: 0, + positionAbsoluteY: 0, + } as never), + ); + + expect(compareSurfaceSpy).toHaveBeenCalled(); + const previewCall = compareSurfaceSpy.mock.calls.find( + ([props]) => + Boolean( + (props as { previewInput?: { sourceUrl: string; steps: unknown[] } }).previewInput, + ), + ); + expect(previewCall).toBeDefined(); + expect( + (previewCall?.[0] as { previewInput?: { sourceUrl: string; steps: unknown[] } }) + .previewInput, + ).toEqual({ + sourceUrl: "https://cdn.example.com/source.png", + steps: [], + }); + }); + + it("defaults render-backed compare inputs to preview mode even when a final render output exists", () => { + storeState.nodes = [ + { + id: "image-1", + type: "image", + data: { url: "https://cdn.example.com/source.png" }, + }, + { + id: "render-1", + type: "render", + data: { + lastUploadUrl: "https://cdn.example.com/render-output.png", + }, + }, + ]; + storeState.edges = [ + { id: "edge-image-render", source: "image-1", target: "render-1" }, + { + id: "edge-render-compare", + source: "render-1", + target: "compare-1", + targetHandle: "left", + }, + ]; + + renderToStaticMarkup( + React.createElement(CompareNode, { + id: "compare-1", + data: { leftUrl: "https://cdn.example.com/render-output.png" }, + selected: false, + dragging: false, + zIndex: 0, + isConnectable: true, + type: "compare", + xPos: 0, + yPos: 0, + width: 500, + height: 380, + sourcePosition: undefined, + targetPosition: undefined, + positionAbsoluteX: 0, + positionAbsoluteY: 0, + } as never), + ); + + expect(compareSurfaceSpy).toHaveBeenCalledTimes(1); + expect(compareSurfaceSpy.mock.calls[0]?.[0]).toMatchObject({ + finalUrl: "https://cdn.example.com/render-output.png", + preferPreview: true, + }); + }); +}); diff --git a/components/canvas/nodes/compare-node.tsx b/components/canvas/nodes/compare-node.tsx index c533477..c69c918 100644 --- a/components/canvas/nodes/compare-node.tsx +++ b/components/canvas/nodes/compare-node.tsx @@ -148,7 +148,9 @@ export default function CompareNode({ id, data, selected, width }: NodeProps) { [incomingEdges, nodesById], ); const shouldDefaultToPreview = - resolvedSides.left.isStaleRenderOutput || resolvedSides.right.isStaleRenderOutput; + hasConnectedRenderInput || + resolvedSides.left.isStaleRenderOutput || + resolvedSides.right.isStaleRenderOutput; const effectiveDisplayMode = manualDisplayMode ?? (shouldDefaultToPreview ? "preview" : "render"); const previewNodeWidth = Math.max(240, Math.min(640, Math.round(width ?? 500))); diff --git a/vitest.config.ts b/vitest.config.ts index 654be67..141a59a 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -13,6 +13,7 @@ export default defineConfig({ "tests/**/*.test.ts", "components/canvas/__tests__/canvas-helpers.test.ts", "components/canvas/__tests__/canvas-flow-reconciliation-helpers.test.ts", + "components/canvas/__tests__/compare-node.test.tsx", "components/canvas/__tests__/use-canvas-flow-reconciliation.test.ts", "components/canvas/__tests__/use-canvas-drop.test.tsx", "components/canvas/__tests__/use-canvas-node-interactions.test.tsx",