From 6b0bb25a7a8592c9209bd4513b87b860cc0edc08 Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Mon, 6 Oct 2025 23:22:26 -0700 Subject: [PATCH 1/8] update to embedding v2 --- src/vercel-ai-toolkit.ts | 2 +- tests/object-detection.test.ts | 424 +++++++++++++++++++++++++++++++++ 2 files changed, 425 insertions(+), 1 deletion(-) create mode 100644 tests/object-detection.test.ts diff --git a/src/vercel-ai-toolkit.ts b/src/vercel-ai-toolkit.ts index 610e50d..adbae74 100644 --- a/src/vercel-ai-toolkit.ts +++ b/src/vercel-ai-toolkit.ts @@ -106,7 +106,7 @@ export class JigsawStackToolSet { token_overflow_mode: z.enum(["truncate", "error"]).optional().describe("How to handle token overflow"), }), execute: async ({ text, url, file_store_key, type, token_overflow_mode }) => { - return await this.jigsawStack.embedding({ + return await this.jigsawStack.embedding_v2({ text, url, file_store_key, diff --git a/tests/object-detection.test.ts b/tests/object-detection.test.ts new file mode 100644 index 0000000..5da5bc9 --- /dev/null +++ b/tests/object-detection.test.ts @@ -0,0 +1,424 @@ +import { beforeEach, describe, test } from "node:test"; +import { createJigsawStackClient, expectArray, expectProperty, expectSuccess, expectType } from "./test-helpers.js"; + +const TEST_URLS = { + image: "https://jigsawstack.com/preview/object-detection-example-input.jpg", + pdf: "https://www.w3.org/WAI/WCAG21/working-examples/pdf-table/table.pdf", + textImage: "https://jigsawstack.com/preview/vocr-example.jpg", +}; + +const FAILURE_TEST_CASES = [ + { + name: "should fail when no parameters are provided", + params: {}, + expected: { + error: "object", + }, + }, +]; + +const SUCCESS_TEST_CASES = [ + { + name: "should fail when no parameters are provided", + params: {}, + expected: { + error: "object", + }, + }, +]; + +// Comprehensive Object Detection API Tests +describe("Object Detection API", () => { + let client: ReturnType; + + beforeEach(() => { + client = createJigsawStackClient(); + }); + + // Test missing required parameters + test("should fail when no parameters are provided", async () => { + try { + await client.vision.object_detection({}); + throw new Error("Expected API call to fail with no parameters"); + } catch (error) { + expectType(error, "object"); + } + }); + + test("should fail when both url and file_store_key are missing", async () => { + try { + await client.vision.object_detection({ + prompts: ["detect objects"], + } as any); + throw new Error("Expected API call to fail with missing url/file_store_key"); + } catch (error) { + expectType(error, "object"); + } + }); + + test("should fail when both url and file_store_key are provided", async () => { + try { + await client.vision.object_detection({ + url: TEST_URLS.image, + file_store_key: "test_key", + } as any); + throw new Error("Expected API call to fail with both url and file_store_key"); + } catch (error) { + expectType(error, "object"); + } + }); + + // Basic functionality tests + test("should work with URL only (default parameters)", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + }); + + expectSuccess(result); + expectType(result, "object"); + + // Check for optional properties based on default features + if (result.objects !== undefined) { + expectArray(result.objects); + + // Validate objects structure + for (const obj of result.objects) { + expectType(obj, "object"); + expectProperty(obj, "bounds"); + expectType(obj.bounds, "object"); + + // Validate bounds structure + expectProperty(obj.bounds, "top_left"); + expectProperty(obj.bounds, "top_right"); + expectProperty(obj.bounds, "bottom_left"); + expectProperty(obj.bounds, "bottom_right"); + expectProperty(obj.bounds, "width"); + expectProperty(obj.bounds, "height"); + + expectType(obj.bounds.width, "number"); + expectType(obj.bounds.height, "number"); + + // Validate points + expectProperty(obj.bounds.top_left, "x"); + expectProperty(obj.bounds.top_left, "y"); + expectType(obj.bounds.top_left.x, "number"); + expectType(obj.bounds.top_left.y, "number"); + + // Check for optional mask + if (obj.mask !== undefined) { + expectType(obj.mask, "string"); + } + } + } + }); + + test("should work with file_store_key parameter", async () => { + try { + const result = await client.vision.object_detection({ + file_store_key: "test_file_store_key", + }); + + expectSuccess(result); + expectType(result, "object"); + } catch (error) { + // Expected to fail with invalid file_store_key, but structure should be correct + expectType(error, "object"); + console.log("Note: Failed with invalid file_store_key (expected)"); + } + }); + + // Test features parameter + test("should work with object_detection feature", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + features: ["object"], + }); + + expectSuccess(result); + expectType(result, "object"); + + if (result.objects !== undefined) { + expectArray(result.objects); + } + }); + + test("should work with gui feature", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + features: ["gui"], + }); + + expectSuccess(result); + expectType(result, "object"); + + if (result.gui_elements !== undefined) { + expectArray(result.gui_elements); + + // Validate GUI elements structure + for (const element of result.gui_elements) { + expectType(element, "object"); + expectProperty(element, "bounds"); + expectProperty(element, "content"); + expectType(element.bounds, "object"); + // content can be string or null + if (element.content !== null) { + expectType(element.content, "string"); + } + } + } + }); + + test("should work with both object_detection and gui features", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + features: ["object", "gui"], + }); + + expectSuccess(result); + expectType(result, "object"); + + if (result.objects !== undefined) { + expectArray(result.objects); + } + + if (result.gui_elements !== undefined) { + expectArray(result.gui_elements); + } + }); + + test("should fail with invalid feature", async () => { + try { + await client.vision.object_detection({ + url: TEST_URLS.image, + features: ["invalid_feature" as any], + }); + throw new Error("Expected API call to fail with invalid feature"); + } catch (error) { + expectType(error, "object"); + } + }); + + // Test prompts parameter + test("should work with single prompt", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + prompts: ["detect all visible objects"], + }); + + expectSuccess(result); + expectType(result, "object"); + }); + + test("should work with multiple prompts", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + prompts: ["find people", "detect vehicles", "identify buildings"], + }); + + expectSuccess(result); + expectType(result, "object"); + }); + + test("should work with empty prompts array", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + prompts: [], + }); + + expectSuccess(result); + expectType(result, "object"); + }); + + // Test annotated_image parameter + test("should work with annotated_image enabled", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + annotated_image: true, + }); + + expectSuccess(result); + expectType(result, "object"); + + // annotated_image should be included only if objects or gui_elements exist + if (result.annotated_image !== undefined) { + expectType(result.annotated_image, "string"); + } + }); + + test("should work with annotated_image disabled", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + annotated_image: false, + }); + + expectSuccess(result); + expectType(result, "object"); + + // annotated_image should not be present when disabled + if (result.annotated_image !== undefined) { + console.log("Note: annotated_image present even when disabled"); + } + }); + + // Test return_type parameter + test("should work with return_type url", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + return_type: "url", + annotated_image: true, + }); + + expectSuccess(result); + expectType(result, "object"); + + if (result.annotated_image !== undefined) { + expectType(result.annotated_image, "string"); + // Should be a URL when return_type is "url" + if (!result.annotated_image.startsWith("http")) { + console.log("Note: annotated_image doesn't look like a URL"); + } + } + }); + + test("should work with return_type base64", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + return_type: "base64", + annotated_image: true, + }); + + expectSuccess(result); + expectType(result, "object"); + + if (result.annotated_image !== undefined) { + expectType(result.annotated_image, "string"); + // Should be base64 when return_type is "base64" + if (!result.annotated_image.startsWith("data:") && !result.annotated_image.match(/^[A-Za-z0-9+/=]+$/)) { + console.log("Note: annotated_image doesn't look like base64"); + } + } + }); + + test("should fail with invalid return_type", async () => { + try { + await client.vision.object_detection({ + url: TEST_URLS.image, + return_type: "invalid" as any, + }); + throw new Error("Expected API call to fail with invalid return_type"); + } catch (error) { + expectType(error, "object"); + } + }); + + // Edge cases and error handling + test("should handle invalid URL gracefully", async () => { + try { + await client.vision.object_detection({ + url: "not-a-valid-url", + }); + throw new Error("Expected API call to fail with invalid URL"); + } catch (error) { + expectType(error, "object"); + } + }); + + test("should handle unreachable URL gracefully", async () => { + try { + await client.vision.object_detection({ + url: "https://example.com/non-existent-image.jpg", + }); + throw new Error("Expected API call to fail with unreachable URL"); + } catch (error) { + expectType(error, "object"); + } + }); + + test("should handle empty file_store_key gracefully", async () => { + try { + await client.vision.object_detection({ + file_store_key: "", + }); + throw new Error("Expected API call to fail with empty file_store_key"); + } catch (error) { + expectType(error, "object"); + } + }); + + test("should work with different image formats", async () => { + const imageUrls = [ + "https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/280px-PNG_transparency_demonstration_1.png", // PNG + "https://upload.wikimedia.org/wikipedia/commons/a/a7/React-icon.svg", // SVG + ]; + + // Run all API calls in parallel + const results = await Promise.allSettled( + imageUrls.map(async (url) => { + try { + const result = await client.vision.object_detection({ + url: url, + }); + + expectSuccess(result); + expectType(result, "object"); + + return { success: true, url }; + } catch (error) { + expectType(error, "object"); + return { success: false, url, error }; + } + }) + ); + + // Process results and log outcomes + results.forEach((result, index) => { + const url = imageUrls[index]; + const format = url.split(".").pop()?.toUpperCase(); + + if (result.status === "fulfilled") { + if (result.value.success) { + console.log(`✓ ${format} format works`); + } else { + console.log(`Note: ${url} failed - may not be accessible or supported format`); + } + } else { + console.log(`Note: ${url} failed - may not be accessible or supported format`); + } + }); + }); + + // Complex scenario tests + test("should work with comprehensive configuration", async () => { + const result = await client.vision.object_detection({ + url: TEST_URLS.image, + prompts: ["detect all objects", "find text elements"], + features: ["object", "gui"], + annotated_image: true, + return_type: "url", + }); + + expectSuccess(result); + expectType(result, "object"); + + if (result.objects !== undefined) { + expectArray(result.objects); + } + + if (result.gui_elements !== undefined) { + expectArray(result.gui_elements); + } + + if (result.annotated_image !== undefined) { + expectType(result.annotated_image, "string"); + } + }); + + test("should work with file upload", async () => { + const imageResponse = await fetch(TEST_URLS.image); + const imageBlob = await imageResponse.blob(); + const result = await client.vision.object_detection(imageBlob); + + expectSuccess(result); + expectType(result, "object"); + }); +}); From 2db156e96ff9bd499fc03cf47ae6b247a8c0b3c3 Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Wed, 8 Oct 2025 12:17:18 -0700 Subject: [PATCH 2/8] update test helpers to not use cache, update web test for new web search, update helpers for file --- src/helpers.ts | 2 +- tests/test-helpers.ts | 2 +- tests/web.test.ts | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/helpers.ts b/src/helpers.ts index a08e3c6..821b6b7 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -17,7 +17,7 @@ export const respToFileChoice = ( }, file: async (filename: string, options?: FilePropertyBag) => { const arr = await resp.arrayBuffer(); - return new File([Buffer.from(arr)], filename, options); + return new File([arr], filename, options); }, }; }; diff --git a/tests/test-helpers.ts b/tests/test-helpers.ts index fb6c1aa..aaabd2e 100644 --- a/tests/test-helpers.ts +++ b/tests/test-helpers.ts @@ -8,7 +8,7 @@ export function createJigsawStackClient() { throw new Error("JIGSAWSTACK_API_KEY environment variable is required for testing"); } - return JigsawStack({ apiKey }); + return JigsawStack({ apiKey, headers: { "x-jigsaw-skip-cache": "true" } }); } export function expectSuccess(result: any): void { diff --git a/tests/web.test.ts b/tests/web.test.ts index 235d6c6..fe39409 100644 --- a/tests/web.test.ts +++ b/tests/web.test.ts @@ -1002,10 +1002,12 @@ describe("Web Search API", () => { // Check structure of search results for (const searchResult of result.results) { + console.log(searchResult.title); expectProperty(searchResult, "title"); expectProperty(searchResult, "url"); expectProperty(searchResult, "description"); - expectProperty(searchResult, "content"); + // this could also be null after 4 search results + // expectProperty(searchResult, "content"); expectProperty(searchResult, "is_safe"); expectProperty(searchResult, "site_name"); expectProperty(searchResult, "language"); @@ -1014,6 +1016,11 @@ describe("Web Search API", () => { expectType(searchResult.url, "string"); expectType(searchResult.description, "string"); expectType(searchResult.is_safe, "boolean"); + + // content can be string or null + if (searchResult.content !== null && typeof searchResult.content !== "string") { + throw new Error(`Expected content to be string or null, got ${typeof searchResult.content}`); + } } }); From 9aef8449f338d1f8606ad774bb97236d12d73dcf Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Wed, 8 Oct 2025 12:56:33 -0700 Subject: [PATCH 3/8] update vision test --- src/vision/interfaces.ts | 2 +- tests/object-detection.test.ts | 424 --------------------------------- tests/vision.test.ts | 4 +- 3 files changed, 4 insertions(+), 426 deletions(-) delete mode 100644 tests/object-detection.test.ts diff --git a/src/vision/interfaces.ts b/src/vision/interfaces.ts index 1a1bbb8..b7107bb 100644 --- a/src/vision/interfaces.ts +++ b/src/vision/interfaces.ts @@ -61,7 +61,7 @@ interface GuiElement { interface DetectedObject { bounds: BoundingBox; label: string; - mask?: string; // URL or base64 string depending on return_type - only present for some objects + mask: string | null; // URL or base64 string depending on return_type - only present for some objects } interface BoundingBox { diff --git a/tests/object-detection.test.ts b/tests/object-detection.test.ts deleted file mode 100644 index 5da5bc9..0000000 --- a/tests/object-detection.test.ts +++ /dev/null @@ -1,424 +0,0 @@ -import { beforeEach, describe, test } from "node:test"; -import { createJigsawStackClient, expectArray, expectProperty, expectSuccess, expectType } from "./test-helpers.js"; - -const TEST_URLS = { - image: "https://jigsawstack.com/preview/object-detection-example-input.jpg", - pdf: "https://www.w3.org/WAI/WCAG21/working-examples/pdf-table/table.pdf", - textImage: "https://jigsawstack.com/preview/vocr-example.jpg", -}; - -const FAILURE_TEST_CASES = [ - { - name: "should fail when no parameters are provided", - params: {}, - expected: { - error: "object", - }, - }, -]; - -const SUCCESS_TEST_CASES = [ - { - name: "should fail when no parameters are provided", - params: {}, - expected: { - error: "object", - }, - }, -]; - -// Comprehensive Object Detection API Tests -describe("Object Detection API", () => { - let client: ReturnType; - - beforeEach(() => { - client = createJigsawStackClient(); - }); - - // Test missing required parameters - test("should fail when no parameters are provided", async () => { - try { - await client.vision.object_detection({}); - throw new Error("Expected API call to fail with no parameters"); - } catch (error) { - expectType(error, "object"); - } - }); - - test("should fail when both url and file_store_key are missing", async () => { - try { - await client.vision.object_detection({ - prompts: ["detect objects"], - } as any); - throw new Error("Expected API call to fail with missing url/file_store_key"); - } catch (error) { - expectType(error, "object"); - } - }); - - test("should fail when both url and file_store_key are provided", async () => { - try { - await client.vision.object_detection({ - url: TEST_URLS.image, - file_store_key: "test_key", - } as any); - throw new Error("Expected API call to fail with both url and file_store_key"); - } catch (error) { - expectType(error, "object"); - } - }); - - // Basic functionality tests - test("should work with URL only (default parameters)", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - }); - - expectSuccess(result); - expectType(result, "object"); - - // Check for optional properties based on default features - if (result.objects !== undefined) { - expectArray(result.objects); - - // Validate objects structure - for (const obj of result.objects) { - expectType(obj, "object"); - expectProperty(obj, "bounds"); - expectType(obj.bounds, "object"); - - // Validate bounds structure - expectProperty(obj.bounds, "top_left"); - expectProperty(obj.bounds, "top_right"); - expectProperty(obj.bounds, "bottom_left"); - expectProperty(obj.bounds, "bottom_right"); - expectProperty(obj.bounds, "width"); - expectProperty(obj.bounds, "height"); - - expectType(obj.bounds.width, "number"); - expectType(obj.bounds.height, "number"); - - // Validate points - expectProperty(obj.bounds.top_left, "x"); - expectProperty(obj.bounds.top_left, "y"); - expectType(obj.bounds.top_left.x, "number"); - expectType(obj.bounds.top_left.y, "number"); - - // Check for optional mask - if (obj.mask !== undefined) { - expectType(obj.mask, "string"); - } - } - } - }); - - test("should work with file_store_key parameter", async () => { - try { - const result = await client.vision.object_detection({ - file_store_key: "test_file_store_key", - }); - - expectSuccess(result); - expectType(result, "object"); - } catch (error) { - // Expected to fail with invalid file_store_key, but structure should be correct - expectType(error, "object"); - console.log("Note: Failed with invalid file_store_key (expected)"); - } - }); - - // Test features parameter - test("should work with object_detection feature", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - features: ["object"], - }); - - expectSuccess(result); - expectType(result, "object"); - - if (result.objects !== undefined) { - expectArray(result.objects); - } - }); - - test("should work with gui feature", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - features: ["gui"], - }); - - expectSuccess(result); - expectType(result, "object"); - - if (result.gui_elements !== undefined) { - expectArray(result.gui_elements); - - // Validate GUI elements structure - for (const element of result.gui_elements) { - expectType(element, "object"); - expectProperty(element, "bounds"); - expectProperty(element, "content"); - expectType(element.bounds, "object"); - // content can be string or null - if (element.content !== null) { - expectType(element.content, "string"); - } - } - } - }); - - test("should work with both object_detection and gui features", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - features: ["object", "gui"], - }); - - expectSuccess(result); - expectType(result, "object"); - - if (result.objects !== undefined) { - expectArray(result.objects); - } - - if (result.gui_elements !== undefined) { - expectArray(result.gui_elements); - } - }); - - test("should fail with invalid feature", async () => { - try { - await client.vision.object_detection({ - url: TEST_URLS.image, - features: ["invalid_feature" as any], - }); - throw new Error("Expected API call to fail with invalid feature"); - } catch (error) { - expectType(error, "object"); - } - }); - - // Test prompts parameter - test("should work with single prompt", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - prompts: ["detect all visible objects"], - }); - - expectSuccess(result); - expectType(result, "object"); - }); - - test("should work with multiple prompts", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - prompts: ["find people", "detect vehicles", "identify buildings"], - }); - - expectSuccess(result); - expectType(result, "object"); - }); - - test("should work with empty prompts array", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - prompts: [], - }); - - expectSuccess(result); - expectType(result, "object"); - }); - - // Test annotated_image parameter - test("should work with annotated_image enabled", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - annotated_image: true, - }); - - expectSuccess(result); - expectType(result, "object"); - - // annotated_image should be included only if objects or gui_elements exist - if (result.annotated_image !== undefined) { - expectType(result.annotated_image, "string"); - } - }); - - test("should work with annotated_image disabled", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - annotated_image: false, - }); - - expectSuccess(result); - expectType(result, "object"); - - // annotated_image should not be present when disabled - if (result.annotated_image !== undefined) { - console.log("Note: annotated_image present even when disabled"); - } - }); - - // Test return_type parameter - test("should work with return_type url", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - return_type: "url", - annotated_image: true, - }); - - expectSuccess(result); - expectType(result, "object"); - - if (result.annotated_image !== undefined) { - expectType(result.annotated_image, "string"); - // Should be a URL when return_type is "url" - if (!result.annotated_image.startsWith("http")) { - console.log("Note: annotated_image doesn't look like a URL"); - } - } - }); - - test("should work with return_type base64", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - return_type: "base64", - annotated_image: true, - }); - - expectSuccess(result); - expectType(result, "object"); - - if (result.annotated_image !== undefined) { - expectType(result.annotated_image, "string"); - // Should be base64 when return_type is "base64" - if (!result.annotated_image.startsWith("data:") && !result.annotated_image.match(/^[A-Za-z0-9+/=]+$/)) { - console.log("Note: annotated_image doesn't look like base64"); - } - } - }); - - test("should fail with invalid return_type", async () => { - try { - await client.vision.object_detection({ - url: TEST_URLS.image, - return_type: "invalid" as any, - }); - throw new Error("Expected API call to fail with invalid return_type"); - } catch (error) { - expectType(error, "object"); - } - }); - - // Edge cases and error handling - test("should handle invalid URL gracefully", async () => { - try { - await client.vision.object_detection({ - url: "not-a-valid-url", - }); - throw new Error("Expected API call to fail with invalid URL"); - } catch (error) { - expectType(error, "object"); - } - }); - - test("should handle unreachable URL gracefully", async () => { - try { - await client.vision.object_detection({ - url: "https://example.com/non-existent-image.jpg", - }); - throw new Error("Expected API call to fail with unreachable URL"); - } catch (error) { - expectType(error, "object"); - } - }); - - test("should handle empty file_store_key gracefully", async () => { - try { - await client.vision.object_detection({ - file_store_key: "", - }); - throw new Error("Expected API call to fail with empty file_store_key"); - } catch (error) { - expectType(error, "object"); - } - }); - - test("should work with different image formats", async () => { - const imageUrls = [ - "https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/280px-PNG_transparency_demonstration_1.png", // PNG - "https://upload.wikimedia.org/wikipedia/commons/a/a7/React-icon.svg", // SVG - ]; - - // Run all API calls in parallel - const results = await Promise.allSettled( - imageUrls.map(async (url) => { - try { - const result = await client.vision.object_detection({ - url: url, - }); - - expectSuccess(result); - expectType(result, "object"); - - return { success: true, url }; - } catch (error) { - expectType(error, "object"); - return { success: false, url, error }; - } - }) - ); - - // Process results and log outcomes - results.forEach((result, index) => { - const url = imageUrls[index]; - const format = url.split(".").pop()?.toUpperCase(); - - if (result.status === "fulfilled") { - if (result.value.success) { - console.log(`✓ ${format} format works`); - } else { - console.log(`Note: ${url} failed - may not be accessible or supported format`); - } - } else { - console.log(`Note: ${url} failed - may not be accessible or supported format`); - } - }); - }); - - // Complex scenario tests - test("should work with comprehensive configuration", async () => { - const result = await client.vision.object_detection({ - url: TEST_URLS.image, - prompts: ["detect all objects", "find text elements"], - features: ["object", "gui"], - annotated_image: true, - return_type: "url", - }); - - expectSuccess(result); - expectType(result, "object"); - - if (result.objects !== undefined) { - expectArray(result.objects); - } - - if (result.gui_elements !== undefined) { - expectArray(result.gui_elements); - } - - if (result.annotated_image !== undefined) { - expectType(result.annotated_image, "string"); - } - }); - - test("should work with file upload", async () => { - const imageResponse = await fetch(TEST_URLS.image); - const imageBlob = await imageResponse.blob(); - const result = await client.vision.object_detection(imageBlob); - - expectSuccess(result); - expectType(result, "object"); - }); -}); diff --git a/tests/vision.test.ts b/tests/vision.test.ts index 8dee80f..562a576 100644 --- a/tests/vision.test.ts +++ b/tests/vision.test.ts @@ -441,7 +441,9 @@ describe("Object Detection API", () => { // Check for optional mask if (obj.mask !== undefined) { - expectType(obj.mask, "string"); + if (obj.mask !== null) { + throw new Error(`Expected mask to be null, got ${typeof obj.mask}`); + } } } } From 579e686189af6ff31ed8b86bd8db9c228a139654 Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Wed, 8 Oct 2025 14:23:53 -0700 Subject: [PATCH 4/8] update to run with cicd from main --- package.json | 4 +++- tests/test-helpers.ts | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ae619e8..5fd0671 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,9 @@ "test:audio": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/audio.test.ts", "test:vision": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/vision.test.ts", "test:web": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/web.test.ts", - "test:validate": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/validate.test.ts" + "test:validate": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/validate.test.ts", + "test:main-ci": "yarn build && JIGSAWSTACK_BASE_URL=${PREVIEW_URL} node --test --no-warnings --import tsx --test-reporter=spec tests/*.ts" + }, "dependencies": { "isomorphic-fetch": "^3.0.0", diff --git a/tests/test-helpers.ts b/tests/test-helpers.ts index aaabd2e..ff90a9b 100644 --- a/tests/test-helpers.ts +++ b/tests/test-helpers.ts @@ -8,7 +8,13 @@ export function createJigsawStackClient() { throw new Error("JIGSAWSTACK_API_KEY environment variable is required for testing"); } - return JigsawStack({ apiKey, headers: { "x-jigsaw-skip-cache": "true" } }); + const client = JigsawStack({ + apiKey, + baseURL: process.env.JIGSAWSTACK_BASE_URL + "/api" || "https://api.jigsawstack.com", + headers: { "x-jigsaw-skip-cache": "true" }, + }); + + return client; } export function expectSuccess(result: any): void { From 3e5bfcab49d670cecae28bdd777caaa23d85618d Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Wed, 8 Oct 2025 14:26:06 -0700 Subject: [PATCH 5/8] formatting --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 5fd0671..a87f78b 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "test:web": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/web.test.ts", "test:validate": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/validate.test.ts", "test:main-ci": "yarn build && JIGSAWSTACK_BASE_URL=${PREVIEW_URL} node --test --no-warnings --import tsx --test-reporter=spec tests/*.ts" - }, "dependencies": { "isomorphic-fetch": "^3.0.0", From e837ff7a3bbb4431f74bd2f4087fc4335650186d Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Wed, 8 Oct 2025 14:29:07 -0700 Subject: [PATCH 6/8] update test script --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index a87f78b..ae619e8 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,7 @@ "test:audio": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/audio.test.ts", "test:vision": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/vision.test.ts", "test:web": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/web.test.ts", - "test:validate": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/validate.test.ts", - "test:main-ci": "yarn build && JIGSAWSTACK_BASE_URL=${PREVIEW_URL} node --test --no-warnings --import tsx --test-reporter=spec tests/*.ts" + "test:validate": "yarn build && node --test --no-warnings --import tsx --test-reporter=spec tests/validate.test.ts" }, "dependencies": { "isomorphic-fetch": "^3.0.0", From 2ee91c425e39b6ee9c9b3c9960454cf471aa74c1 Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Wed, 8 Oct 2025 14:33:14 -0700 Subject: [PATCH 7/8] update path --- tests/test-helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-helpers.ts b/tests/test-helpers.ts index ff90a9b..3edde5c 100644 --- a/tests/test-helpers.ts +++ b/tests/test-helpers.ts @@ -10,7 +10,7 @@ export function createJigsawStackClient() { const client = JigsawStack({ apiKey, - baseURL: process.env.JIGSAWSTACK_BASE_URL + "/api" || "https://api.jigsawstack.com", + baseURL: (process.env.JIGSAWSTACK_BASE_URL || "https://api.jigsawstack.com") + "/api", headers: { "x-jigsaw-skip-cache": "true" }, }); From 1dd751b4c38ec567a63ea86b4ced72e559041413 Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Wed, 8 Oct 2025 14:37:12 -0700 Subject: [PATCH 8/8] update --- tests/test-helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-helpers.ts b/tests/test-helpers.ts index 3edde5c..267ea9a 100644 --- a/tests/test-helpers.ts +++ b/tests/test-helpers.ts @@ -10,7 +10,7 @@ export function createJigsawStackClient() { const client = JigsawStack({ apiKey, - baseURL: (process.env.JIGSAWSTACK_BASE_URL || "https://api.jigsawstack.com") + "/api", + baseURL: process.env.JIGSAWSTACK_BASE_URL ? `${process.env.JIGSAWSTACK_BASE_URL}/api` : "https://api.jigsawstack.com", headers: { "x-jigsaw-skip-cache": "true" }, });