From c9fbacf481cdc22720d3f7b2f9972035b2ac8a42 Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Mon, 25 Aug 2025 15:36:00 -0700 Subject: [PATCH 1/6] file support now works --- .gitignore | 3 ++- src/audio/audio.ts | 4 +++- src/general/index.ts | 4 +++- src/request.ts | 8 +++++--- src/utils.ts | 36 ++++++++++++++++++++++++++++++++++++ src/validate/index.ts | 12 +++++++++--- src/vision/vision.ts | 24 ++++++++++++++++++++---- test.ts | 16 ---------------- tests/test-helpers.ts | 1 + 9 files changed, 79 insertions(+), 29 deletions(-) create mode 100644 src/utils.ts delete mode 100644 test.ts diff --git a/.gitignore b/.gitignore index 5a38a0b..2f77907 100644 --- a/.gitignore +++ b/.gitignore @@ -129,7 +129,8 @@ dist .yarn/install-state.gz .pnp.* -test.js + +test.ts .DS_Store diff --git a/src/audio/audio.ts b/src/audio/audio.ts index 9dcea28..2bdb8fa 100644 --- a/src/audio/audio.ts +++ b/src/audio/audio.ts @@ -1,4 +1,5 @@ import { RequestClient } from "../request"; +import { createFileUploadFormData } from "../utils"; import { SpeechToTextParams, SpeechToTextResponse } from "./interfaces"; class Audio { constructor(private readonly client: RequestClient) {} @@ -6,7 +7,8 @@ class Audio { speech_to_text(file: Blob | Buffer, params?: Omit): Promise; async speech_to_text(params: SpeechToTextParams | Blob | Buffer, options?: SpeechToTextParams): Promise { if (params instanceof Blob || params instanceof Buffer) { - return await this.client.fetchJSS("/ai/transcribe", "POST", params, options); + const formData = createFileUploadFormData(params, options); + return await this.client.fetchJSS("/ai/transcribe", "POST", formData); } return await this.client.fetchJSS("/ai/transcribe", "POST", params); } diff --git a/src/general/index.ts b/src/general/index.ts index bf1fa00..05bf6c0 100644 --- a/src/general/index.ts +++ b/src/general/index.ts @@ -1,6 +1,7 @@ import { BaseResponse } from "../../types"; import { respToFileChoice } from "../helpers"; import { RequestClient } from "../request"; +import { createFileUploadFormData } from "../utils"; import { EmbeddingParams, EmbeddingResponse, @@ -36,7 +37,8 @@ class General { options?: Omit ): Promise> => { if (params instanceof Blob || params instanceof Buffer) { - const resp = await this.client.fetchJSS("/ai/translate/image", "POST", params, options); + const formData = createFileUploadFormData(params, options); + const resp = await this.client.fetchJSS("/ai/translate/image", "POST", formData); return respToFileChoice(resp); } const resp = await this.client.fetchJSS("/ai/translate/image", "POST", params); diff --git a/src/request.ts b/src/request.ts index 2eb9672..a6716c3 100644 --- a/src/request.ts +++ b/src/request.ts @@ -2,6 +2,7 @@ import { BaseConfig } from "../types"; import { removeUndefinedProperties } from "./helpers"; const baseURL = "https://api.jigsawstack.com/v1"; +// const baseURL = "http://localhost:3000"; export class RequestClient { constructor(private readonly config: BaseConfig) {} @@ -9,7 +10,7 @@ export class RequestClient { readonly fetchJSS = async ( path: string, method: "POST" | "GET" | "DELETE", - body?: Record | Blob, + body?: Record | Blob | FormData, searchParams?: { [key: string]: any; }, @@ -19,17 +20,18 @@ export class RequestClient { ) => { const disableRequestLogging = this.config?.disableRequestLogging; const isFileUpload = body instanceof Blob || body instanceof Buffer; + const isFormData = body instanceof FormData; searchParams = searchParams ? removeUndefinedProperties(searchParams) : undefined; const _headers = { "x-api-key": this.config?.apiKey, - "Content-Type": isFileUpload ? "application/octet-stream" : "application/json", + ...(!isFormData && { "Content-Type": isFileUpload ? "application/octet-stream" : "application/json" }), ...headers, ["x-jigsaw-no-request-log"]: disableRequestLogging && "true", }; - const _body = isFileUpload ? body : JSON.stringify(body); + const _body = isFormData ? body : isFileUpload ? body : JSON.stringify(body); const url = `${this.config?.baseURL || baseURL}${path}`; const urlParams = searchParams && Object.keys(searchParams).length ? `?${new URLSearchParams(searchParams).toString()}` : ""; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..a189153 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,36 @@ +/** + * Creates FormData for file uploads with optional parameters + * @param file - The file to upload (Blob or Buffer) + * @param options - Optional parameters to include in the form data + * @param fileFieldName - The field name for the file (defaults to "file") + * @returns FormData object ready for upload + */ +export function createFileUploadFormData(file: Blob | Buffer, options?: Record, fileFieldName: string = "file"): FormData { + const formData = new FormData(); + + // Convert Buffer to Blob if needed + const fileToAppend = file instanceof Buffer ? new Blob([file]) : file; + formData.append(fileFieldName, fileToAppend); + + // Add options as form fields, handling arrays and objects properly + if (options) { + for (const [key, value] of Object.entries(options)) { + if (value === undefined || value === null) { + continue; // Skip undefined/null values + } + + if (Array.isArray(value)) { + // Convert arrays to JSON strings + formData.append(key, JSON.stringify(value)); + } else if (typeof value === "object") { + // Convert objects to JSON strings + formData.append(key, JSON.stringify(value)); + } else { + // Convert primitives to strings + formData.append(key, String(value)); + } + } + } + + return formData; +} diff --git a/src/validate/index.ts b/src/validate/index.ts index f05b5ac..586443a 100644 --- a/src/validate/index.ts +++ b/src/validate/index.ts @@ -1,6 +1,6 @@ import { RequestClient } from "../request"; +import { createFileUploadFormData } from "../utils"; import { - EmailValidationResponse, NSFWParams, NSFWValidationResponse, ProfanityParams, @@ -16,8 +16,14 @@ class Validate { this.spamcheck = this.spamcheck.bind(this); } - nsfw(params: NSFWParams | Blob | Buffer): Promise { - return this.client.fetchJSS("/validate/nsfw", "POST", params); + nsfw(params: NSFWParams): Promise; + nsfw(file: Blob | Buffer, params?: Omit): Promise; + async nsfw(params: NSFWParams | Blob | Buffer, options?: NSFWParams): Promise { + if (params instanceof Blob || params instanceof Buffer) { + const formData = createFileUploadFormData(params, options); + return await this.client.fetchJSS("/validate/nsfw", "POST", formData); + } + return await this.client.fetchJSS("/validate/nsfw", "POST", params); } profanity = async ({ text, censor_replacement = "*" }: ProfanityParams): Promise => { diff --git a/src/vision/vision.ts b/src/vision/vision.ts index 2c4402a..cb7a4fc 100644 --- a/src/vision/vision.ts +++ b/src/vision/vision.ts @@ -1,13 +1,29 @@ import { RequestClient } from "../request"; +import { createFileUploadFormData } from "../utils"; import { ObjectDetectionParams, ObjectDetectionResponse, VOCRParams, VOCRResponse } from "./interfaces"; class Vision { constructor(private readonly client: RequestClient) {} - vocr = async (params: VOCRParams): Promise => { + + vocr(params: VOCRParams): Promise; + vocr(file: Blob | Buffer, params?: Omit): Promise; + async vocr(params: VOCRParams | Blob | Buffer, options?: VOCRParams): Promise { + if (params instanceof Blob || params instanceof Buffer) { + const formData = createFileUploadFormData(params, options); + return await this.client.fetchJSS("/vocr", "POST", formData); + } return await this.client.fetchJSS("/vocr", "POST", params); - }; - object_detection = async (params: ObjectDetectionParams): Promise => { + } + + object_detection(params: ObjectDetectionParams): Promise; + object_detection(file: Blob | Buffer, params?: Omit): Promise; + async object_detection(params: ObjectDetectionParams | Blob | Buffer, options?: ObjectDetectionParams): Promise { + if (params instanceof Blob || params instanceof Buffer) { + const formData = createFileUploadFormData(params, options); + console.log(formData); + return await this.client.fetchJSS("/object_detection", "POST", formData); + } return await this.client.fetchJSS("/object_detection", "POST", params); - }; + } } export default Vision; diff --git a/test.ts b/test.ts deleted file mode 100644 index 14e860d..0000000 --- a/test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { createJigsawStackClient } from "./tests/test-helpers"; - -const client = createJigsawStackClient(); - -const result = await client.classification.text({ - dataset: [ - { type: "text" as const, value: "This is a great product! I love it." }, - { type: "text" as const, value: "This is a great product! I hate it." }, - ], - labels: [ - { key: "positive", type: "text" as const, value: "positive sentiment" }, - { key: "negative", type: "text" as const, value: "negative sentiment" }, - ], -}); - -console.log(result); diff --git a/tests/test-helpers.ts b/tests/test-helpers.ts index c761a5d..6452f66 100644 --- a/tests/test-helpers.ts +++ b/tests/test-helpers.ts @@ -21,6 +21,7 @@ export function createJigsawStackClient() { sentiment: (params: any) => new General(client).sentiment(params), translate: { text: (params: any) => new General(client).translate.text(params), + image: (params: any) => new General(client).translate.image(params), }, summary: (params: any) => new General(client).summary(params), embedding: (params: any) => new General(client).embedding(params), From c205f0d579ceba4be9e35a7571d13e45b3044395 Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Mon, 25 Aug 2025 16:11:19 -0700 Subject: [PATCH 2/6] update tests --- src/vision/vision.ts | 1 - tests/audio.test.ts | 10 ++++++++++ tests/validate.test.ts | 23 ----------------------- tests/vision.test.ts | 27 ++++++++++++++++++++++++--- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/vision/vision.ts b/src/vision/vision.ts index cb7a4fc..a5599e1 100644 --- a/src/vision/vision.ts +++ b/src/vision/vision.ts @@ -19,7 +19,6 @@ class Vision { async object_detection(params: ObjectDetectionParams | Blob | Buffer, options?: ObjectDetectionParams): Promise { if (params instanceof Blob || params instanceof Buffer) { const formData = createFileUploadFormData(params, options); - console.log(formData); return await this.client.fetchJSS("/object_detection", "POST", formData); } return await this.client.fetchJSS("/object_detection", "POST", params); diff --git a/tests/audio.test.ts b/tests/audio.test.ts index 94a4fec..9a371fc 100644 --- a/tests/audio.test.ts +++ b/tests/audio.test.ts @@ -66,4 +66,14 @@ describe("STT APIs", () => { expectProperty(result, "text"); expectType(result.text, "string"); }); + + test("speech to text with file upload", async () => { + const audioResponse = await fetch("https://jigsawstack.com/preview/stt-example.wav"); + const audioBlob = await audioResponse.blob(); + const result = await client.audio.speech_to_text(audioBlob); + + expectSuccess(result); + expectProperty(result, "text"); + expectType(result.text, "string"); + }); }); diff --git a/tests/validate.test.ts b/tests/validate.test.ts index 631d61f..a22588c 100644 --- a/tests/validate.test.ts +++ b/tests/validate.test.ts @@ -1014,27 +1014,4 @@ describe("SpellCheck validation", () => { expectType(misspelling.auto_corrected, "boolean"); }); }); - - test("should handle whitespace-only text", async () => { - const result = await client.validate.spellcheck({ - text: " \t\n ", - language_code: "en", - }); - - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "misspellings"); - expectProperty(result, "auto_correct_text"); - - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - - // Whitespace-only text should have no misspellings - if (result.misspellings_found !== false) { - console.log("Note: Misspellings found in whitespace-only text"); - } - }); }); diff --git a/tests/vision.test.ts b/tests/vision.test.ts index 5cba11c..efba724 100644 --- a/tests/vision.test.ts +++ b/tests/vision.test.ts @@ -2,10 +2,9 @@ import { beforeEach, describe, test } from "node:test"; import { createJigsawStackClient, expectArray, expectProperty, expectSuccess, expectType } from "./test-helpers.js"; const TEST_URLS = { - image: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/280px-PNG_transparency_demonstration_1.png", + 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://upload.wikimedia.org/wikipedia/commons/thumb/5/50/Vd-Orig.png/256px-Vd-Orig.png", - receipt: "https://jigsawstack.com/preview/receipt-example.jpg", // Example receipt image + textImage: "https://jigsawstack.com/preview/vocr-example.jpg", }; // Comprehensive VOCR API Tests @@ -37,6 +36,19 @@ describe("VOCR (Visual OCR) API", () => { } }); + test("should work with file upload", async () => { + try { + const imageResponse = await fetch(TEST_URLS.image); + const imageBlob = await imageResponse.blob(); + const result = await client.vision.vocr(imageBlob); + + expectSuccess(result); + expectType(result, "object"); + } catch (error) { + expectType(error, "object"); + } + }); + test("should fail when both url and file_store_key are missing", async () => { try { await client.vision.vocr({ @@ -735,4 +747,13 @@ describe("Object Detection API", () => { 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 2984f4b96e2885089fe131dd398ca2f1ecb2985c Mon Sep 17 00:00:00 2001 From: Yoeven D Khemlani Date: Mon, 25 Aug 2025 16:29:39 -0700 Subject: [PATCH 3/6] Update index.ts --- src/general/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/general/index.ts b/src/general/index.ts index 05bf6c0..8dc3f18 100644 --- a/src/general/index.ts +++ b/src/general/index.ts @@ -98,7 +98,8 @@ class General { embedding(file: Blob | Buffer, params: Omit): Promise; async embedding(params: EmbeddingParams | Blob | Buffer, options?: EmbeddingParams): Promise { if (params instanceof Blob || params instanceof Buffer) { - return await this.client.fetchJSS("/embedding", "POST", params, options); + const formData = createFileUploadFormData(params, options); + return await this.client.fetchJSS("/embedding", "POST", formData); } return await this.client.fetchJSS("/embedding", "POST", params); } From 8cbeb9c42279d2ca12ff3246670f909e0d4d00cd Mon Sep 17 00:00:00 2001 From: Yoeven D Khemlani Date: Mon, 25 Aug 2025 16:38:46 -0700 Subject: [PATCH 4/6] Update request.ts --- src/request.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/request.ts b/src/request.ts index a6716c3..df3ea31 100644 --- a/src/request.ts +++ b/src/request.ts @@ -31,7 +31,17 @@ export class RequestClient { ["x-jigsaw-no-request-log"]: disableRequestLogging && "true", }; - const _body = isFormData ? body : isFileUpload ? body : JSON.stringify(body); + let _body; + + switch (true) { + case isFileUpload: + case isFormData: + _body = body; + break; + default: + _body = JSON.stringify(body); + } + const url = `${this.config?.baseURL || baseURL}${path}`; const urlParams = searchParams && Object.keys(searchParams).length ? `?${new URLSearchParams(searchParams).toString()}` : ""; From e09ab8bed4c23b87c6d11613fa98fa73d35d23a3 Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Tue, 26 Aug 2025 17:00:27 -0700 Subject: [PATCH 5/6] rm spell check test --- tests/validate.test.ts | 714 ++++++++++++++++++++--------------------- 1 file changed, 357 insertions(+), 357 deletions(-) diff --git a/tests/validate.test.ts b/tests/validate.test.ts index a22588c..dbbf5b4 100644 --- a/tests/validate.test.ts +++ b/tests/validate.test.ts @@ -1,6 +1,7 @@ import { beforeEach, describe, test } from "node:test"; import { createJigsawStackClient, expectArray, expectProperty, expectSuccess, expectType } from "./test-helpers.js"; +const imageUrl = "https://jigsawstack.com/preview/object-detection-example-input.jpg"; // Comprehensive Profanity API Tests describe("Profanity validation", () => { let client: ReturnType; @@ -333,7 +334,7 @@ describe("NSFW validation", () => { test("should work with valid URL parameter", async () => { const result = await client.validate.nsfw({ - url: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Logo_of_Twitter.svg/512px-Logo_of_Twitter.svg.png", + url: imageUrl, }); // Verify success @@ -425,8 +426,7 @@ describe("NSFW validation", () => { test("should work with different image formats", async () => { const imageUrls = [ - "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Logo_of_Twitter.svg/512px-Logo_of_Twitter.svg.png", // PNG - "https://upload.wikimedia.org/wikipedia/commons/a/a7/React-icon.svg", // SVG + imageUrl, // jpg ]; // Run all API calls in parallel @@ -661,357 +661,357 @@ describe("NSFW validation", () => { }); // Comprehensive SpellCheck API Tests -describe("SpellCheck validation", () => { - let client: ReturnType; - - beforeEach(() => { - client = createJigsawStackClient(); - }); - - test("should fail when text parameter is missing", async () => { - try { - // @ts-expect-error Testing missing required parameter - await client.validate.spellcheck({}); - throw new Error("Expected API call to fail with missing text parameter"); - } catch (error) { - // Should throw an error for missing required parameter - expectType(error, "object"); - } - }); - - test("should fail when text parameter is undefined", async () => { - try { - // @ts-expect-error Testing undefined required parameter - await client.validate.spellcheck({ text: undefined }); - throw new Error("Expected API call to fail with undefined text parameter"); - } catch (error) { - expectType(error, "object"); - } - }); - - test("should fail when text parameter is null", async () => { - try { - // @ts-expect-error Testing null required parameter - await client.validate.spellcheck({ text: null }); - throw new Error("Expected API call to fail with null text parameter"); - } catch (error) { - expectType(error, "object"); - } - }); - - test("should work with only required text parameter", async () => { - const result = await client.validate.spellcheck({ - text: "This is a correctly spelled sentence.", - }); - - // Verify success - expectSuccess(result); - - // Verify all required response properties exist - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "misspellings"); - expectProperty(result, "auto_correct_text"); - - // Verify correct types - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - }); - - test("should work with custom language_code parameter", async () => { - const result = await client.validate.spellcheck({ - text: "Hola mundo como estas", - language_code: "es", - }); - - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "misspellings"); - expectProperty(result, "auto_correct_text"); - - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - }); - - test("should handle empty text", async () => { - const result = await client.validate.spellcheck({ - text: "", - }); - - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "misspellings"); - expectProperty(result, "auto_correct_text"); - - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - - // Empty text should have no misspellings - if (result.misspellings_found !== false) { - console.log("Note: Misspellings found in empty text"); - } - }); - - test("should handle text with intentional misspellings", async () => { - const result = await client.validate.spellcheck({ - text: "Ths is a mispelled sentance with erors.", - language_code: "en", - }); - - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "misspellings"); - expectProperty(result, "auto_correct_text"); - - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - - // Should find misspellings in our intentionally misspelled text - if (result.misspellings_found === false) { - console.log("Note: No misspellings found in intentionally misspelled text"); - } - - // Validate misspellings array structure when misspellings are found - if (result.misspellings_found === true) { - result.misspellings.forEach((misspelling) => { - expectType(misspelling, "object"); - expectProperty(misspelling, "word"); - expectProperty(misspelling, "startIndex"); - expectProperty(misspelling, "endIndex"); - expectProperty(misspelling, "expected"); - expectProperty(misspelling, "auto_corrected"); - expectType(misspelling.word, "string"); - expectType(misspelling.startIndex, "number"); - expectType(misspelling.endIndex, "number"); - expectArray(misspelling.expected); - expectType(misspelling.auto_corrected, "boolean"); - }); - } - - // Auto-corrected text should be different from original - if (result.auto_correct_text === "Ths is a mispelled sentance with erors.") { - console.log("Note: Auto-corrected text is identical to original misspelled text"); - } - }); - - test("should handle text with special characters", async () => { - const result = await client.validate.spellcheck({ - text: "Special chars: !@#$%^&*()_+-=[]{}|;':\",./<>?", - language_code: "en", - }); - - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "misspellings"); - expectProperty(result, "auto_correct_text"); - - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - }); - - test("should handle text with numbers", async () => { - const result = await client.validate.spellcheck({ - text: "The year 2024 has 365 days and 12 months.", - language_code: "en", - }); - - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "misspellings"); - expectProperty(result, "auto_correct_text"); - - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - }); - - test("should handle unicode characters", async () => { - const result = await client.validate.spellcheck({ - text: "Unicode: 你好 🌟 émojis 🚀 ñoño café résumé", - language_code: "en", - }); - - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "misspellings"); - expectProperty(result, "auto_correct_text"); - - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - }); - - test("should handle very long text", async () => { - const longText = "This is a very long text that contains many words. ".repeat(50); - const result = await client.validate.spellcheck({ - text: longText, - language_code: "en", - }); - - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "misspellings"); - expectProperty(result, "auto_correct_text"); - - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - }); - - test("should handle different supported language codes", async () => { - const testCases = [ - { text: "Hello world", language_code: "en", name: "English" }, - { text: "Hola mundo", language_code: "es", name: "Spanish" }, - { text: "Bonjour monde", language_code: "fr", name: "French" }, - { text: "Hallo Welt", language_code: "de", name: "German" }, - { text: "Ciao mondo", language_code: "it", name: "Italian" }, - ]; - - // Run all API calls in parallel - const results = await Promise.allSettled( - testCases.map(async (testCase) => { - try { - const result = await client.validate.spellcheck({ - text: testCase.text, - language_code: testCase.language_code, - }); - - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "misspellings"); - expectProperty(result, "auto_correct_text"); - - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - - return { success: true, testCase }; - } catch (error) { - expectType(error, "object"); - return { success: false, testCase, error }; - } - }) - ); - - // Process results and log outcomes - results.forEach((result, index) => { - const testCase = testCases[index]; - if (result.status === "fulfilled") { - if (result.value.success) { - console.log(`✓ ${testCase.name} (${testCase.language_code}) works`); - } else { - console.log(`Note: ${testCase.name} (${testCase.language_code}) failed - may not be supported`); - } - } else { - console.log(`Note: ${testCase.name} (${testCase.language_code}) failed - may not be supported`); - } - }); - }); - - test("should handle invalid language code", async () => { - try { - const result = await client.validate.spellcheck({ - text: "This is a test sentence.", - language_code: "invalid_code", - }); - - // If it doesn't throw an error, validate the response - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "auto_correct_text"); - - console.log("Note: Invalid language code was accepted"); - } catch (error) { - console.log("Note: Invalid language code was rejected (expected)"); - expectType(error, "object"); - } - }); - - test("should handle empty language code", async () => { - try { - const result = await client.validate.spellcheck({ - text: "This is a test sentence.", - language_code: "", - }); - - expectSuccess(result); - expectProperty(result, "success"); - expectProperty(result, "misspellings_found"); - expectProperty(result, "auto_correct_text"); - } catch (error) { - console.log("Note: Empty language code was rejected"); - expectType(error, "object"); - } - }); - - test("should validate response structure completely", async () => { - const result = await client.validate.spellcheck({ - text: "This is a test sentence with some mispellings.", - language_code: "en", - }); - - // Verify the complete response structure - expectSuccess(result); - expectType(result, "object"); - - // Check if response has expected properties - const expectedProperties = ["success", "misspellings_found", "misspellings", "auto_correct_text"]; - const resultKeys = Object.keys(result); - - // Ensure all expected properties exist - for (const expectedProp of expectedProperties) { - expectProperty(result, expectedProp); - } - - // Log any unexpected properties (might be from documentation but not in interface) - for (const key of resultKeys) { - if (!expectedProperties.includes(key)) { - console.log(`Note: Additional property '${key}' found in SpellCheck response`); - } - } - - // Validate types - expectType(result.success, "boolean"); - expectType(result.misspellings_found, "boolean"); - expectArray(result.misspellings); - expectType(result.auto_correct_text, "string"); - - // Validate misspellings array structure - result.misspellings.forEach((misspelling) => { - expectType(misspelling, "object"); - expectProperty(misspelling, "word"); - expectProperty(misspelling, "startIndex"); - expectProperty(misspelling, "endIndex"); - expectProperty(misspelling, "expected"); - expectProperty(misspelling, "auto_corrected"); - expectType(misspelling.word, "string"); - expectType(misspelling.startIndex, "number"); - expectType(misspelling.endIndex, "number"); - expectArray(misspelling.expected); - expectType(misspelling.auto_corrected, "boolean"); - }); - }); -}); +// describe("SpellCheck validation", () => { +// let client: ReturnType; + +// beforeEach(() => { +// client = createJigsawStackClient(); +// }); + +// test("should fail when text parameter is missing", async () => { +// try { +// // @ts-expect-error Testing missing required parameter +// await client.validate.spellcheck({}); +// throw new Error("Expected API call to fail with missing text parameter"); +// } catch (error) { +// // Should throw an error for missing required parameter +// expectType(error, "object"); +// } +// }); + +// test("should fail when text parameter is undefined", async () => { +// try { +// // @ts-expect-error Testing undefined required parameter +// await client.validate.spellcheck({ text: undefined }); +// throw new Error("Expected API call to fail with undefined text parameter"); +// } catch (error) { +// expectType(error, "object"); +// } +// }); + +// test("should fail when text parameter is null", async () => { +// try { +// // @ts-expect-error Testing null required parameter +// await client.validate.spellcheck({ text: null }); +// throw new Error("Expected API call to fail with null text parameter"); +// } catch (error) { +// expectType(error, "object"); +// } +// }); + +// test("should work with only required text parameter", async () => { +// const result = await client.validate.spellcheck({ +// text: "This is a correctly spelled sentence.", +// }); + +// // Verify success +// expectSuccess(result); + +// // Verify all required response properties exist +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "misspellings"); +// expectProperty(result, "auto_correct_text"); + +// // Verify correct types +// expectType(result.success, "boolean"); +// expectType(result.misspellings_found, "boolean"); +// expectArray(result.misspellings); +// expectType(result.auto_correct_text, "string"); +// }); + +// test("should work with custom language_code parameter", async () => { +// const result = await client.validate.spellcheck({ +// text: "Hola mundo como estas", +// language_code: "es", +// }); + +// expectSuccess(result); +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "misspellings"); +// expectProperty(result, "auto_correct_text"); + +// expectType(result.success, "boolean"); +// expectType(result.misspellings_found, "boolean"); +// expectArray(result.misspellings); +// expectType(result.auto_correct_text, "string"); +// }); + +// test("should handle empty text", async () => { +// const result = await client.validate.spellcheck({ +// text: "", +// }); + +// expectSuccess(result); +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "misspellings"); +// expectProperty(result, "auto_correct_text"); + +// expectType(result.success, "boolean"); +// expectType(result.misspellings_found, "boolean"); +// expectArray(result.misspellings); +// expectType(result.auto_correct_text, "string"); + +// // Empty text should have no misspellings +// if (result.misspellings_found !== false) { +// console.log("Note: Misspellings found in empty text"); +// } +// }); + +// test("should handle text with intentional misspellings", async () => { +// const result = await client.validate.spellcheck({ +// text: "Ths is a mispelled sentance with erors.", +// language_code: "en", +// }); + +// expectSuccess(result); +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "misspellings"); +// expectProperty(result, "auto_correct_text"); + +// expectType(result.success, "boolean"); +// expectType(result.misspellings_found, "boolean"); +// expectArray(result.misspellings); +// expectType(result.auto_correct_text, "string"); + +// // Should find misspellings in our intentionally misspelled text +// if (result.misspellings_found === false) { +// console.log("Note: No misspellings found in intentionally misspelled text"); +// } + +// // Validate misspellings array structure when misspellings are found +// if (result.misspellings_found === true) { +// result.misspellings.forEach((misspelling) => { +// expectType(misspelling, "object"); +// expectProperty(misspelling, "word"); +// expectProperty(misspelling, "startIndex"); +// expectProperty(misspelling, "endIndex"); +// expectProperty(misspelling, "expected"); +// expectProperty(misspelling, "auto_corrected"); +// expectType(misspelling.word, "string"); +// expectType(misspelling.startIndex, "number"); +// expectType(misspelling.endIndex, "number"); +// expectArray(misspelling.expected); +// expectType(misspelling.auto_corrected, "boolean"); +// }); +// } + +// // Auto-corrected text should be different from original +// if (result.auto_correct_text === "Ths is a mispelled sentance with erors.") { +// console.log("Note: Auto-corrected text is identical to original misspelled text"); +// } +// }); + +// test("should handle text with special characters", async () => { +// const result = await client.validate.spellcheck({ +// text: "Special chars: !@#$%^&*()_+-=[]{}|;':\",./<>?", +// language_code: "en", +// }); + +// expectSuccess(result); +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "misspellings"); +// expectProperty(result, "auto_correct_text"); + +// expectType(result.success, "boolean"); +// expectType(result.misspellings_found, "boolean"); +// expectArray(result.misspellings); +// expectType(result.auto_correct_text, "string"); +// }); + +// test("should handle text with numbers", async () => { +// const result = await client.validate.spellcheck({ +// text: "The year 2024 has 365 days and 12 months.", +// language_code: "en", +// }); + +// expectSuccess(result); +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "misspellings"); +// expectProperty(result, "auto_correct_text"); + +// expectType(result.success, "boolean"); +// expectType(result.misspellings_found, "boolean"); +// expectArray(result.misspellings); +// expectType(result.auto_correct_text, "string"); +// }); + +// test("should handle unicode characters", async () => { +// const result = await client.validate.spellcheck({ +// text: "Unicode: 你好 🌟 émojis 🚀 ñoño café résumé", +// language_code: "en", +// }); + +// expectSuccess(result); +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "misspellings"); +// expectProperty(result, "auto_correct_text"); + +// expectType(result.success, "boolean"); +// expectType(result.misspellings_found, "boolean"); +// expectArray(result.misspellings); +// expectType(result.auto_correct_text, "string"); +// }); + +// test("should handle very long text", async () => { +// const longText = "This is a very long text that contains many words. ".repeat(50); +// const result = await client.validate.spellcheck({ +// text: longText, +// language_code: "en", +// }); + +// expectSuccess(result); +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "misspellings"); +// expectProperty(result, "auto_correct_text"); + +// expectType(result.success, "boolean"); +// expectType(result.misspellings_found, "boolean"); +// expectArray(result.misspellings); +// expectType(result.auto_correct_text, "string"); +// }); + +// test("should handle different supported language codes", async () => { +// const testCases = [ +// { text: "Hello world", language_code: "en", name: "English" }, +// { text: "Hola mundo", language_code: "es", name: "Spanish" }, +// { text: "Bonjour monde", language_code: "fr", name: "French" }, +// { text: "Hallo Welt", language_code: "de", name: "German" }, +// { text: "Ciao mondo", language_code: "it", name: "Italian" }, +// ]; + +// // Run all API calls in parallel +// const results = await Promise.allSettled( +// testCases.map(async (testCase) => { +// try { +// const result = await client.validate.spellcheck({ +// text: testCase.text, +// language_code: testCase.language_code, +// }); + +// expectSuccess(result); +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "misspellings"); +// expectProperty(result, "auto_correct_text"); + +// expectType(result.success, "boolean"); +// expectType(result.misspellings_found, "boolean"); +// expectArray(result.misspellings); +// expectType(result.auto_correct_text, "string"); + +// return { success: true, testCase }; +// } catch (error) { +// expectType(error, "object"); +// return { success: false, testCase, error }; +// } +// }) +// ); + +// // Process results and log outcomes +// results.forEach((result, index) => { +// const testCase = testCases[index]; +// if (result.status === "fulfilled") { +// if (result.value.success) { +// console.log(`✓ ${testCase.name} (${testCase.language_code}) works`); +// } else { +// console.log(`Note: ${testCase.name} (${testCase.language_code}) failed - may not be supported`); +// } +// } else { +// console.log(`Note: ${testCase.name} (${testCase.language_code}) failed - may not be supported`); +// } +// }); +// }); + +// test("should handle invalid language code", async () => { +// try { +// const result = await client.validate.spellcheck({ +// text: "This is a test sentence.", +// language_code: "invalid_code", +// }); + +// // If it doesn't throw an error, validate the response +// expectSuccess(result); +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "auto_correct_text"); + +// console.log("Note: Invalid language code was accepted"); +// } catch (error) { +// console.log("Note: Invalid language code was rejected (expected)"); +// expectType(error, "object"); +// } +// }); + +// test("should handle empty language code", async () => { +// try { +// const result = await client.validate.spellcheck({ +// text: "This is a test sentence.", +// language_code: "", +// }); + +// expectSuccess(result); +// expectProperty(result, "success"); +// expectProperty(result, "misspellings_found"); +// expectProperty(result, "auto_correct_text"); +// } catch (error) { +// console.log("Note: Empty language code was rejected"); +// expectType(error, "object"); +// } +// }); + +// test("should validate response structure completely", async () => { +// const result = await client.validate.spellcheck({ +// text: "This is a test sentence with some mispellings.", +// language_code: "en", +// }); + +// // Verify the complete response structure +// expectSuccess(result); +// expectType(result, "object"); + +// // Check if response has expected properties +// const expectedProperties = ["success", "misspellings_found", "misspellings", "auto_correct_text"]; +// const resultKeys = Object.keys(result); + +// // Ensure all expected properties exist +// for (const expectedProp of expectedProperties) { +// expectProperty(result, expectedProp); +// } + +// // Log any unexpected properties (might be from documentation but not in interface) +// for (const key of resultKeys) { +// if (!expectedProperties.includes(key)) { +// console.log(`Note: Additional property '${key}' found in SpellCheck response`); +// } +// } + +// // Validate types +// expectType(result.success, "boolean"); +// expectType(result.misspellings_found, "boolean"); +// expectArray(result.misspellings); +// expectType(result.auto_correct_text, "string"); + +// // Validate misspellings array structure +// result.misspellings.forEach((misspelling) => { +// expectType(misspelling, "object"); +// expectProperty(misspelling, "word"); +// expectProperty(misspelling, "startIndex"); +// expectProperty(misspelling, "endIndex"); +// expectProperty(misspelling, "expected"); +// expectProperty(misspelling, "auto_corrected"); +// expectType(misspelling.word, "string"); +// expectType(misspelling.startIndex, "number"); +// expectType(misspelling.endIndex, "number"); +// expectArray(misspelling.expected); +// expectType(misspelling.auto_corrected, "boolean"); +// }); +// }); +// }); From 599d590527418f883628c31d2fbe5a7a19206a78 Mon Sep 17 00:00:00 2001 From: Win Cheng Date: Tue, 26 Aug 2025 17:02:45 -0700 Subject: [PATCH 6/6] linting --- tests/validate.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/validate.test.ts b/tests/validate.test.ts index dbbf5b4..276638b 100644 --- a/tests/validate.test.ts +++ b/tests/validate.test.ts @@ -426,7 +426,7 @@ describe("NSFW validation", () => { test("should work with different image formats", async () => { const imageUrls = [ - imageUrl, // jpg + imageUrl, // jpg ]; // Run all API calls in parallel