From 65dbf79c8aa52cfe9017a804259d0937c3a0fd64 Mon Sep 17 00:00:00 2001 From: shrimbly Date: Fri, 30 Jan 2026 21:14:39 +1300 Subject: [PATCH] test(quick-001): add regression tests for multi-image dynamicInputs aggregation - Test: multiple images to same schema-mapped handle aggregate into array - Test: single image to schema-mapped handle stays as plain string - Test: multiple images with distinct schema handles remain separate strings - Test: three images to same handle produce array of length 3 - Fix react-dom version mismatch (19.2.0 -> 19.2.3) to match react Co-Authored-By: Claude Opus 4.5 --- package-lock.json | 10 +- package.json | 2 +- .../workflowStore.integration.test.ts | 127 ++++++++++++++++++ 3 files changed, 133 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76009965..06c8625f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "next": "^16.0.6", "postcss": "^8.5.6", "react": "^19.2.0", - "react-dom": "^19.2.0", + "react-dom": "^19.2.3", "react-konva": "^19.2.1", "tailwindcss": "^4.1.17", "zustand": "^5.0.9" @@ -4767,15 +4767,15 @@ } }, "node_modules/react-dom": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", - "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.0" + "react": "^19.2.3" } }, "node_modules/react-is": { diff --git a/package.json b/package.json index bc06c2f8..51e5118c 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "next": "^16.0.6", "postcss": "^8.5.6", "react": "^19.2.0", - "react-dom": "^19.2.0", + "react-dom": "^19.2.3", "react-konva": "^19.2.1", "tailwindcss": "^4.1.17", "zustand": "^5.0.9" diff --git a/src/store/__tests__/workflowStore.integration.test.ts b/src/store/__tests__/workflowStore.integration.test.ts index 55e72234..315f4701 100644 --- a/src/store/__tests__/workflowStore.integration.test.ts +++ b/src/store/__tests__/workflowStore.integration.test.ts @@ -365,6 +365,133 @@ describe("workflowStore integration tests", () => { }); }); + describe("Multi-image dynamicInputs aggregation", () => { + it("should aggregate multiple images to same schema-mapped handle into array", () => { + const store = useWorkflowStore.getState(); + const img1 = "data:image/png;base64,img1"; + const img2 = "data:image/png;base64,img2"; + + useWorkflowStore.setState({ + nodes: [ + createTestNode("imageInput-1", "imageInput", { image: img1 }), + createTestNode("imageInput-2", "imageInput", { image: img2 }), + createTestNode("nanoBanana-1", "nanoBanana", { + inputSchema: [ + { name: "image_urls", type: "image", required: true, label: "Images" }, + ], + }), + ], + edges: [ + createTestEdge("imageInput-1", "nanoBanana-1", "image", "image"), + createTestEdge("imageInput-2", "nanoBanana-1", "image", "image"), + ], + }); + + const result = store.getConnectedInputs("nanoBanana-1"); + + // Both images should be aggregated into an array under the schema name + expect(Array.isArray(result.dynamicInputs["image_urls"])).toBe(true); + expect(result.dynamicInputs["image_urls"]).toHaveLength(2); + expect(result.dynamicInputs["image_urls"]).toContain(img1); + expect(result.dynamicInputs["image_urls"]).toContain(img2); + + // images array should also contain both + expect(result.images).toHaveLength(2); + expect(result.images).toContain(img1); + expect(result.images).toContain(img2); + }); + + it("should keep single image to schema-mapped handle as string", () => { + const store = useWorkflowStore.getState(); + const img1 = "data:image/png;base64,img1"; + + useWorkflowStore.setState({ + nodes: [ + createTestNode("imageInput-1", "imageInput", { image: img1 }), + createTestNode("nanoBanana-1", "nanoBanana", { + inputSchema: [ + { name: "image_urls", type: "image", required: true, label: "Images" }, + ], + }), + ], + edges: [ + createTestEdge("imageInput-1", "nanoBanana-1", "image", "image"), + ], + }); + + const result = store.getConnectedInputs("nanoBanana-1"); + + // Single image should be a plain string, not wrapped in array + expect(result.dynamicInputs["image_urls"]).toBe(img1); + expect(Array.isArray(result.dynamicInputs["image_urls"])).toBe(false); + }); + + it("should keep multiple images with distinct schema handles as separate strings", () => { + const store = useWorkflowStore.getState(); + const img1 = "data:image/png;base64,img1"; + const img2 = "data:image/png;base64,img2"; + + useWorkflowStore.setState({ + nodes: [ + createTestNode("imageInput-1", "imageInput", { image: img1 }), + createTestNode("imageInput-2", "imageInput", { image: img2 }), + createTestNode("generateVideo-1", "generateVideo", { + inputSchema: [ + { name: "start_image_url", type: "image", required: true, label: "Start" }, + { name: "end_image_url", type: "image", required: false, label: "End" }, + ], + }), + ], + edges: [ + createTestEdge("imageInput-1", "generateVideo-1", "image", "image-0"), + createTestEdge("imageInput-2", "generateVideo-1", "image", "image-1"), + ], + }); + + const result = store.getConnectedInputs("generateVideo-1"); + + // Each should be a plain string, not an array + expect(result.dynamicInputs["start_image_url"]).toBe(img1); + expect(result.dynamicInputs["end_image_url"]).toBe(img2); + expect(Array.isArray(result.dynamicInputs["start_image_url"])).toBe(false); + expect(Array.isArray(result.dynamicInputs["end_image_url"])).toBe(false); + }); + + it("should produce array of length 3 when three images connect to same handle", () => { + const store = useWorkflowStore.getState(); + const img1 = "data:image/png;base64,img1"; + const img2 = "data:image/png;base64,img2"; + const img3 = "data:image/png;base64,img3"; + + useWorkflowStore.setState({ + nodes: [ + createTestNode("imageInput-1", "imageInput", { image: img1 }), + createTestNode("imageInput-2", "imageInput", { image: img2 }), + createTestNode("imageInput-3", "imageInput", { image: img3 }), + createTestNode("nanoBanana-1", "nanoBanana", { + inputSchema: [ + { name: "image_urls", type: "image", required: true, label: "Images" }, + ], + }), + ], + edges: [ + createTestEdge("imageInput-1", "nanoBanana-1", "image", "image"), + createTestEdge("imageInput-2", "nanoBanana-1", "image", "image"), + createTestEdge("imageInput-3", "nanoBanana-1", "image", "image"), + ], + }); + + const result = store.getConnectedInputs("nanoBanana-1"); + + // Should be array of length 3 + expect(Array.isArray(result.dynamicInputs["image_urls"])).toBe(true); + expect(result.dynamicInputs["image_urls"]).toHaveLength(3); + expect(result.dynamicInputs["image_urls"]).toContain(img1); + expect(result.dynamicInputs["image_urls"]).toContain(img2); + expect(result.dynamicInputs["image_urls"]).toContain(img3); + }); + }); + describe("Edge cases", () => { it("should return empty images array and null text when no connections", () => { const store = useWorkflowStore.getState();