66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { buildRequestTarget } from "../../src/adapters/http/request-builder.ts";
|
|
import type { ApiOperation } from "../../src/contracts/api-operations.ts";
|
|
|
|
const operation: ApiOperation = {
|
|
method: "GET",
|
|
path: "/api/resources/{resourceId}",
|
|
operationId: "GET_RESOURCE",
|
|
auth: "none",
|
|
timeoutMs: null,
|
|
idempotency: "safe",
|
|
retry: "runtime",
|
|
requestSource: "search",
|
|
requestSchema: "ResourceQuery",
|
|
responseSchema: "ResourcePayload",
|
|
owner: "test",
|
|
};
|
|
|
|
describe("deterministic HTTP request target", () => {
|
|
it("escapes path values and serializes optional/array search in key order", () => {
|
|
const result = buildRequestTarget(
|
|
"https://api.test/base/",
|
|
operation,
|
|
{ resourceId: "folder/item" },
|
|
{
|
|
tags: ["beta", "alpha"],
|
|
omitted: undefined,
|
|
limit: 20,
|
|
cursor: "next page",
|
|
},
|
|
);
|
|
|
|
expect(result.success).toBe(true);
|
|
if (!result.success) return;
|
|
expect(result.url.href).toBe(
|
|
"https://api.test/base/api/resources/folder%2Fitem?cursor=next+page&limit=20&tags=beta&tags=alpha",
|
|
);
|
|
});
|
|
|
|
it("fails closed when a path value or scalar search value is invalid", () => {
|
|
expect(
|
|
buildRequestTarget("https://api.test", operation, {}, {}),
|
|
).toEqual({ success: false, code: "PATH_PARAMETER_MISSING" });
|
|
expect(
|
|
buildRequestTarget(
|
|
"https://api.test",
|
|
operation,
|
|
{ resourceId: "one" },
|
|
{ nested: { secret: true } },
|
|
),
|
|
).toEqual({ success: false, code: "SEARCH_PARAMETER_INVALID" });
|
|
expect(
|
|
buildRequestTarget(
|
|
"https://api.test",
|
|
operation,
|
|
{ resourceId: "one", unexpected: "two" },
|
|
{},
|
|
),
|
|
).toEqual({ success: false, code: "PATH_PARAMETER_UNEXPECTED" });
|
|
expect(
|
|
buildRequestTarget("http://api.test", operation, { resourceId: "one" }),
|
|
).toEqual({ success: false, code: "BASE_URL_INVALID" });
|
|
});
|
|
});
|