Files
HiveGrid-Wireframes/hivegrid-cloud/packages/api-client-ts/src/generated-core.test.ts
T

180 lines
6.5 KiB
TypeScript

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<string, unknown> = {};
circular.self = circular;
expect(stringifyToJsonValue(circular)).toBeUndefined();
expect(stringifyToJsonValue(() => undefined)).toBeUndefined();
});
});