import { describe, expect, it } from "vitest"; import { formDataBodySerializer, jsonBodySerializer, urlSearchParamsBodySerializer } from "./generated/core/bodySerializer.gen.js"; import { buildClientParams } from "./generated/core/params.gen.js"; import { defaultPathSerializer, getUrl, getValidRequestBody, } from "./generated/core/utils.gen.js"; import { separatorArrayExplode, separatorArrayNoExplode, separatorObjectExplode, serializeArrayParam, serializeObjectParam, serializePrimitiveParam, } from "./generated/core/pathSerializer.gen.js"; import { serializeQueryKeyValue, stringifyToJsonValue } from "./generated/core/queryKeySerializer.gen.js"; describe("generated core body serializers", () => { it("serializes JSON bodies with bigint values", () => { expect(jsonBodySerializer.bodySerializer({ id: 12n, name: "tool" })).toBe('{"id":"12","name":"tool"}'); }); it("serializes FormData bodies while skipping nullish values", async () => { const file = new Blob(["hello"], { type: "text/plain" }); const date = new Date("2026-05-25T10:30:00.000Z"); const data = formDataBodySerializer.bodySerializer({ ignored: undefined, list: ["a", 2], meta: { ok: true }, stamp: date, upload: file, }); expect(data.getAll("list")).toEqual(["a", "2"]); expect(data.get("meta")).toBe('{"ok":true}'); expect(data.get("stamp")).toBe(date.toISOString()); expect(data.get("upload")).toBeInstanceOf(Blob); expect(data.has("ignored")).toBe(false); }); it("serializes URLSearchParams bodies with repeated array entries", () => { expect( urlSearchParamsBodySerializer.bodySerializer({ filters: ["active", { owner: "me" }], page: 2, skipped: null, }) ).toBe("filters=active&filters=%7B%22owner%22%3A%22me%22%7D&page=2"); }); }); describe("generated core parameter mapping", () => { it("maps positional and object parameters into request slots", () => { const params = buildClientParams( [ "project-1", { raw: true }, { $headers_traceparent: "00-ab", $query_search: "drill", apiVersion: "2026-05", extra: "kept", payload: { name: "new tool" }, }, ], [ { in: "path", key: "projectId", map: "project_id" }, { in: "body" }, { allowExtra: { query: true }, args: [ { in: "headers", key: "apiVersion", map: "X-Api-Version" }, { key: "payload", map: "body" }, ], }, ] ); expect(params).toEqual({ body: { name: "new tool" }, headers: { "X-Api-Version": "2026-05", traceparent: "00-ab", }, path: { project_id: "project-1" }, query: { extra: "kept", search: "drill", }, }); }); it("removes empty slots from the mapped params", () => { expect(buildClientParams(["abc"], [{ in: "path", key: "id" }])).toEqual({ path: { id: "abc" } }); }); }); describe("generated core path and URL serializers", () => { it("serializes primitive, array, and object path params", () => { expect( defaultPathSerializer({ path: { coords: ["10", "20"], filter: { status: "open", owner: "ops" }, id: "tool/a", tag: "beta", }, url: "/v1/tools/{id}/{.tag}/{;coords*}/{filter}", }) ).toBe("/v1/tools/tool%2Fa/.beta/;coords=10;coords=20/status,open,owner,ops"); }); it("serializes query and path parameters into a full URL", () => { const url = getUrl({ baseUrl: "https://api.example.test", path: { id: "a/b" }, query: { active: true, tags: ["red", "blue"] }, querySerializer: (query) => `?active=${query.active}&tags=${(query.tags as string[]).join(",")}`, url: "v1/tools/{id}", }); expect(url).toBe("https://api.example.test/v1/tools/a%2Fb?active=true&tags=red,blue"); }); it("exposes OpenAPI separator and primitive serialization behavior", () => { expect(separatorArrayExplode("label")).toBe("."); expect(separatorArrayNoExplode("pipeDelimited")).toBe("|"); expect(separatorObjectExplode("matrix")).toBe(";"); expect(serializeArrayParam({ explode: false, name: "ids", style: "pipeDelimited", value: ["a/b", "c"] })).toBe("ids=a%2Fb|c"); expect(serializePrimitiveParam({ allowReserved: true, name: "q", value: "a/b?c" })).toBe("q=a/b?c"); expect(() => serializePrimitiveParam({ name: "bad", value: { nested: true } as never })).toThrow(/Deeply-nested/); }); it("serializes object params for dates, labels, and deep objects", () => { const date = new Date("2026-05-25T12:00:00.000Z"); expect(serializeObjectParam({ explode: true, name: "at", style: "form", value: date, valueOnly: true })).toBe(date.toISOString()); expect(serializeObjectParam({ explode: false, name: "filter", style: "label", value: { status: "open" } })).toBe(".status,open"); expect(serializeObjectParam({ explode: true, name: "filter", style: "deepObject", value: { status: "open" } })).toBe( "filter[status]=open" ); }); it("returns the valid request body shape for serialized, plain, and empty bodies", () => { expect(getValidRequestBody({ body: { ok: true } })).toEqual({ ok: true }); expect(getValidRequestBody({ body: "", bodySerializer: JSON.stringify })).toBeNull(); expect(getValidRequestBody({ body: { ok: true }, bodySerializer: JSON.stringify, serializedBody: '{"ok":true}' })).toBe('{"ok":true}'); expect(getValidRequestBody({ body: { ok: true }, bodySerializer: JSON.stringify, serializedBody: "" })).toBeNull(); expect(getValidRequestBody({})).toBeUndefined(); }); }); describe("generated core query key serialization", () => { it("normalizes query key values into JSON-safe shapes", () => { const params = new URLSearchParams([ ["b", "2"], ["a", "1"], ["a", "3"], ]); expect(serializeQueryKeyValue(params)).toEqual({ a: ["1", "3"], b: "2" }); expect(serializeQueryKeyValue({ createdAt: new Date("2026-05-25T00:00:00.000Z"), id: 123n })).toEqual({ createdAt: "2026-05-25T00:00:00.000Z", id: "123", }); expect(serializeQueryKeyValue(Object.create(null))).toEqual({}); expect(serializeQueryKeyValue(Symbol("skip"))).toBeUndefined(); }); it("returns undefined when JSON serialization cannot produce a value", () => { const circular: Record = {}; circular.self = circular; expect(stringifyToJsonValue(circular)).toBeUndefined(); expect(stringifyToJsonValue(() => undefined)).toBeUndefined(); }); });