import { describe, expect, it } from "vitest"; import { buildRequestTarget } from "../../src/adapters/http/request-builder.js"; import type { ApiOperation } from "../../src/contracts/api-operations.js"; 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/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" }); }); });