import { INVALID_URL_MSG, QUEUE_FULL_MSG, SPACE_METADATA_ERROR_MSG } from "../constants"; import { beforeAll, afterEach, afterAll, it, expect, describe } from "vitest"; import { handle_message, get_description, get_type, process_endpoint, join_urls, map_data_to_params } from "../helpers/api_info"; import { initialise_server } from "./server"; import { transformed_api_info } from "./test_data"; const server = initialise_server(); beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close()); describe("handle_message", () => { it("should return type 'data' when msg is 'send_data'", () => { const data = { msg: "send_data" }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "data" }); }); it("should return type 'hash' when msg is 'send_hash'", () => { const data = { msg: "send_hash" }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "hash" }); }); it("should return type 'update' with queue full message when msg is 'queue_full'", () => { const data = { msg: "queue_full", code: 500, success: false }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "update", status: { queue: true, message: QUEUE_FULL_MSG, stage: "error", code: 500, success: false } }); }); it("should return type 'heartbeat' when msg is 'heartbeat'", () => { const data = { msg: "heartbeat" }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "heartbeat" }); }); it("should return type 'unexpected_error' with error message when msg is 'unexpected_error'", () => { const data = { msg: "unexpected_error", message: "Something went wrong" }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "unexpected_error", status: { queue: true, message: "Something went wrong", stage: "error", success: false } }); }); it("should return type 'update' with estimation status when msg is 'estimation'", () => { const data = { msg: "estimation", code: 200, queue_size: 10, rank: 5, rank_eta: 60, success: true }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "update", status: { queue: true, stage: "pending", code: 200, size: 10, position: 5, eta: 60, success: true } }); }); it("should return type 'update' with progress status when msg is 'progress'", () => { const data = { msg: "progress", code: 200, progress_data: { current: 50, total: 100 }, success: true }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "update", status: { queue: true, stage: "pending", code: 200, progress_data: { current: 50, total: 100 }, success: true } }); }); it("should return type 'log' with the provided data when msg is 'log'", () => { const data = { msg: "log", log_data: "Some log message" }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "log", data: { msg: "log", log_data: "Some log message" } }); }); it("should return type 'generating' with generating status when msg is 'process_generating' and success is true", () => { const data = { msg: "process_generating", success: true, code: 200, progress_data: { current: 50, total: 100 }, average_duration: 120, output: { result: "Some result" } }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "generating", status: { queue: true, message: null, stage: "generating", code: 200, progress_data: { current: 50, total: 100 }, eta: 120 }, data: { result: "Some result" } }); }); it("should return type 'update' with error status when msg is 'process_generating' and success is false", () => { const data = { msg: "process_generating", success: false, code: 500, progress_data: { current: 50, total: 100 }, average_duration: 120, output: { error: "Error" } }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "generating", data: null, status: { eta: 120, queue: true, message: "Error", stage: "error", code: 500, progress_data: { current: 50, total: 100 } } }); }); it("should return type 'complete' with success status when msg is 'process_completed' and success is true", () => { const data = { msg: "process_completed", success: true, code: 200, progress_data: { current: 100, total: 100 }, output: { result: "Some result" } }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "complete", status: { queue: true, message: undefined, stage: "complete", code: 200, progress_data: { current: 100, total: 100 } }, data: { result: "Some result" } }); }); it("should return type 'update' with error status when msg is 'process_completed' and success is false", () => { const data = { msg: "process_completed", success: false, code: 500, progress_data: { current: 100, total: 100 }, output: { error: "Some error message" } }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "update", status: { queue: true, message: "Some error message", stage: "error", code: 500, success: false } }); }); it("should return type 'update' with pending status when msg is 'process_starts'", () => { const data = { msg: "process_starts", code: 200, rank: 5, success: true, eta: 60 }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "update", original_msg: "process_starts", status: { queue: true, stage: "pending", code: 200, size: 5, position: 0, success: true, eta: 60 } }); }); it("should return type 'none' with error status when msg is unknown", () => { const data = { msg: "unknown" }; const last_status = "pending"; const result = handle_message(data, last_status); expect(result).toEqual({ type: "none", status: { stage: "error", queue: true } }); }); }); describe("get_description", () => { it("should return 'array of [file, label] tuples' when serializer is 'GallerySerializable'", () => { const type = { type: "string", description: "param description" }; const serializer = "GallerySerializable"; const result = get_description(type, serializer); expect(result).toEqual("array of [file, label] tuples"); }); it("should return 'array of strings' when serializer is 'ListStringSerializable'", () => { const type = { type: "string", description: "param description" }; const serializer = "ListStringSerializable"; const result = get_description(type, serializer); expect(result).toEqual("array of strings"); }); it("should return 'array of files or single file' when serializer is 'FileSerializable'", () => { const type = { type: "string", description: "param description" }; const serializer = "FileSerializable"; const result = get_description(type, serializer); expect(result).toEqual("array of files or single file"); }); it("should return the type's description when serializer is not 'GallerySerializable', 'ListStringSerializable', or 'FileSerializable'", () => { const type = { type: "string", description: "param description" }; const serializer = "SomeOtherSerializer"; const result = get_description(type, serializer); expect(result).toEqual(type.description); }); }); describe("get_type", () => { it("should return 'string' when type is 'string'", () => { const type = { type: "string", description: "param description" }; const component = "Component"; const serializer = "Serializer"; const signature_type = "parameter"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual("string"); }); it("should return 'boolean' when type is 'boolean'", () => { const type = { type: "boolean", description: "param description" }; const component = "Component"; const serializer = "Serializer"; const signature_type = "parameter"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual("boolean"); }); it("should return 'number' when type is 'number'", () => { const type = { type: "number", description: "param description" }; const component = "Component"; const serializer = "Serializer"; const signature_type = "parameter"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual("number"); }); it("should return 'any' when serializer is 'JSONSerializable'", () => { const type = { type: "any", description: "param description" }; const component = "Component"; const serializer = "JSONSerializable"; const signature_type = "parameter"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual("any"); }); it("should return 'any' when serializer is 'StringSerializable'", () => { const type = { type: "any", description: "param description" }; const component = "Component"; const serializer = "StringSerializable"; const signature_type = "parameter"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual("any"); }); it("should return 'string[]' when serializer is 'ListStringSerializable'", () => { const type = { type: "any", description: "param description" }; const component = "Component"; const serializer = "ListStringSerializable"; const signature_type = "parameter"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual("string[]"); }); it("should return 'Blob | File | Buffer' when component is 'Image' and signature_type is 'parameter'", () => { const type = { type: "any", description: "param description" }; const component = "Image"; const serializer = "Serializer"; const signature_type = "parameter"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual("Blob | File | Buffer"); }); it("should return 'string' when component is 'Image' and signature_type is 'return'", () => { const type = { type: "string", description: "param description" }; const component = "Image"; const serializer = "Serializer"; const signature_type = "return"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual("string"); }); it("should return '(Blob | File | Buffer)[]' when serializer is 'FileSerializable' and type is an array and signature_type is 'parameter'", () => { const type = { type: "array", description: "param description" }; const component = "Component"; const serializer = "FileSerializable"; const signature_type = "parameter"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual("(Blob | File | Buffer)[]"); }); it("should return 'Blob | File | Buffer' when serializer is 'FileSerializable' and type is not an array and signature_type is 'return'", () => { const type = { type: "any", description: "param description" }; const component = "Component"; const serializer = "FileSerializable"; const signature_type = "return"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual( "{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}" ); }); it("should return a FileData object when serializer is 'FileSerializable' and type is not an array and signature_type is 'return'", () => { const type = { type: "any", description: "param description" }; const component = "Component"; const serializer = "FileSerializable"; const signature_type = "return"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual( "{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}" ); }); it("should return '[(Blob | File | Buffer), (string | null)][]' when serializer is 'GallerySerializable' and signature_type is 'parameter'", () => { const type = { type: "any", description: "param description" }; const component = "Component"; const serializer = "GallerySerializable"; const signature_type = "parameter"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual("[(Blob | File | Buffer), (string | null)][]"); }); it("should return a FileData object when serializer is 'GallerySerializable' and signature_type is 'return'", () => { const type = { type: "any", description: "param description" }; const component = "Component"; const serializer = "GallerySerializable"; const signature_type = "return"; const result = get_type(type, component, serializer, signature_type); expect(result).toEqual( "[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]" ); }); }); describe("process_endpoint", () => { it("should return space_id, host, ws_protocol, and http_protocol when app_reference is a valid space name", async () => { const app_reference = "hmb/hello_world"; const host = "hmb-hello-world.hf.space"; const hf_token = "hf_token"; const expected = { space_id: app_reference, host, ws_protocol: "wss", http_protocol: "https:" }; const result = await process_endpoint(app_reference, hf_token); expect(result).toEqual(expected); }); it("should throw an error when fetching space metadata fails", async () => { const app_reference = "hmb/bye_world"; const hf_token = "hf_token"; try { await process_endpoint(app_reference, hf_token); } catch (error) { expect(error.message).toEqual(SPACE_METADATA_ERROR_MSG); } }); it("should return the correct data when app_reference is a valid space domain", async () => { const app_reference = "hmb/hello_world"; const host = "hmb-hello-world.hf.space"; const expected = { space_id: app_reference, host, ws_protocol: "wss", http_protocol: "https:" }; const result = await process_endpoint("hmb/hello_world"); expect(result).toEqual(expected); }); it("processes local server URLs correctly", async () => { const local_url = "http://localhost:7860/gradio"; const response_local_url = await process_endpoint(local_url); expect(response_local_url.space_id).toBe(false); expect(response_local_url.host).toBe("localhost:7860/gradio"); const local_url_2 = "http://localhost:7860/gradio/"; const response_local_url_2 = await process_endpoint(local_url_2); expect(response_local_url_2.space_id).toBe(false); expect(response_local_url_2.host).toBe("localhost:7860/gradio"); }); it("handles hugging face space references", async () => { const space_id = "hmb/hello_world"; const response = await process_endpoint(space_id); expect(response.space_id).toBe(space_id); expect(response.host).toContain("hf.space"); }); it("handles hugging face domain URLs", async () => { const app_reference = "https://hmb-hello-world.hf.space/"; const response = await process_endpoint(app_reference); expect(response.space_id).toBe("hmb-hello-world"); expect(response.host).toBe("hmb-hello-world.hf.space"); }); }); describe("join_urls", () => { it("joins URLs correctly", () => { expect(join_urls("http://localhost:7860", "/gradio")).toBe( "http://localhost:7860/gradio" ); expect(join_urls("http://localhost:7860/", "/gradio")).toBe( "http://localhost:7860/gradio" ); expect(join_urls("http://localhost:7860", "app/", "/gradio")).toBe( "http://localhost:7860/app/gradio" ); expect(join_urls("http://localhost:7860/", "/app/", "/gradio/")).toBe( "http://localhost:7860/app/gradio/" ); expect(join_urls("http://127.0.0.1:8000/app", "/config")).toBe( "http://127.0.0.1:8000/app/config" ); expect(join_urls("http://127.0.0.1:8000/app/gradio", "/config")).toBe( "http://127.0.0.1:8000/app/gradio/config" ); }); it("throws an error when the URLs are not valid", () => { expect(() => join_urls("localhost:7860", "/gradio")).toThrowError( INVALID_URL_MSG ); expect(() => join_urls("localhost:7860", "/gradio", "app")).toThrowError( INVALID_URL_MSG ); }); }); describe("map_data_params", () => { let test_data = transformed_api_info; test_data.named_endpoints["/predict"].parameters = [ { parameter_name: "param1", parameter_has_default: false, label: "", component: "", serializer: "", python_type: { type: "", description: "" }, type: { type: "", description: "" } }, { parameter_name: "param2", parameter_has_default: false, label: "", type: { type: "", description: "" }, component: "", serializer: "", python_type: { type: "", description: "" } }, { parameter_name: "param3", parameter_has_default: true, parameter_default: 3, label: "", type: { type: "", description: "" }, component: "", serializer: "", python_type: { type: "", description: "" } } ]; let endpoint_info = test_data.named_endpoints["/predict"]; it("should return an array of data when data is an array", () => { const data = [1, 2]; const result = map_data_to_params(data, endpoint_info); expect(result).toEqual(data); }); it("should return an empty array when data is an empty array", () => { const data = []; const result = map_data_to_params(data, endpoint_info); expect(result).toEqual(data); }); it("should return an empty array when data is not defined", () => { const data = undefined; const result = map_data_to_params(data, endpoint_info); expect(result).toEqual([]); }); it("should return the data when too many arguments are provided for the endpoint", () => { const data = [1, 2, 3, 4]; const result = map_data_to_params(data, endpoint_info); expect(result).toEqual(data); }); it("should return an array of resolved data when data is an object", () => { const data = { param1: 1, param2: 2, param3: 3 }; const result = map_data_to_params(data, endpoint_info); expect(result).toEqual([1, 2, 3]); }); it("should use the default value when a keyword argument is not provided and has a default value", () => { const data = { param1: 1, param2: 2 }; const result = map_data_to_params(data, endpoint_info); expect(result).toEqual([1, 2, 3]); }); it("should throw an error when an invalid keyword argument is provided", () => { const data = { param1: 1, param2: 2, param3: 3, param4: 4 }; expect(() => map_data_to_params(data, endpoint_info)).toThrowError( "Parameter `param4` is not a valid keyword argument. Please refer to the API for usage." ); }); it("should throw an error when no value is provided for a required parameter", () => { const data = {}; expect(() => map_data_to_params(data, endpoint_info)).toThrowError( "No value provided for required parameter: param1" ); }); });