import { describe, expect, it, vi } from "vitest"; vi.mock("@toolctrl/db/entities.server", () => ({ getAllLegacyEntities: vi.fn(), })); vi.mock("~/locale/i18next.server", () => ({ getTranslations: vi.fn(async () => ({ t: (value: string) => value, translations: {}, locale: "en" })), })); vi.mock("~/utils/url.server", () => ({ getAbsoluteApiUrl: vi.fn((_request: Request, path: string) => `https://api.example.com${path.startsWith("/") ? path : `/${path}`}`), })); import { getAllLegacyEntities } from "@toolctrl/db/entities.server"; import ApiSpecsService from "./ApiSpecsService"; const entity = { id: "entity_1", slug: "contacts", title: "Contact", titlePlural: "Contacts", hasApi: true, active: true, properties: [], childEntities: [{ id: "child_relation" }], parentEntities: [], }; describe("ApiSpecsService", () => { it("documents canonical API auth and idempotency for generated specs and Postman requests", async () => { vi.mocked(getAllLegacyEntities).mockResolvedValue([entity] as never); const specs = await ApiSpecsService.generateSpecs({ request: new Request("https://admin.example.com/api/docs") }); const openApi = specs.openApi; expect(openApi.servers).toEqual([{ url: "https://api.example.com", description: "API host" }]); expect(openApi.components.securitySchemes.bearerAuth).toMatchObject({ type: "http", scheme: "bearer", bearerFormat: "service-token", }); expect(openApi.paths["/v1/entities/{entity}/rows"].post.parameters).toContainEqual(expect.objectContaining({ name: "Idempotency-Key", required: true })); expect(openApi.paths["/v1/entities/{entity}/rows/{rowId}"].patch.parameters).toContainEqual(expect.objectContaining({ name: "Idempotency-Key", required: true })); expect(openApi.paths["/v1/entities/{entity}/rows/{rowId}"].delete.parameters).toContainEqual(expect.objectContaining({ name: "Idempotency-Key", required: true })); expect(openApi.paths["/v1/relationships"].post.parameters).toContainEqual(expect.objectContaining({ name: "Idempotency-Key", required: true })); expect(openApi.paths["/v1/relationships/{id}"].delete.parameters).toContainEqual(expect.objectContaining({ name: "Idempotency-Key", required: true })); const postmanItems = specs.postmanCollection.item as Array<{ name: string; request: { header: Array<{ key: string; value?: string }>; url: { raw: string; query?: Array<{ key: string; value: string; disabled?: boolean }> } }; }>; expect(postmanItems.find((item) => item.name === "GET /v1/session/current-user")?.request.header).toEqual([ expect.objectContaining({ key: "Authorization", value: "Bearer " }), ]); expect(postmanItems.find((item) => item.name === "POST /v1/api-keys/validate")?.request.header).toEqual([ expect.objectContaining({ key: "x-api-key", value: "" }), ]); expect(postmanItems.some((item) => item.name.startsWith("POST /v1/workflows") || item.name.startsWith("GET /v1/workflows"))).toBe(false); expect(postmanItems.find((item) => item.name === "GET /v1/entities/:entity/rows")?.request.header).toEqual([ expect.objectContaining({ key: "x-api-key", value: "" }), ]); expect(postmanItems.find((item) => item.name === "GET /v1/entities/:entity/rows")?.request.url.query).toContainEqual( expect.objectContaining({ key: "tenantId", value: "" }) ); expect(postmanItems.find((item) => item.name === "GET /v1/entities/:entity/rows")?.request.url.raw).toContain("tenantId=%3CtenantId%3E"); expect(postmanItems.find((item) => item.name === "POST /v1/entities/:entity/rows")?.request.header).toEqual([ expect.objectContaining({ key: "x-api-key", value: "" }), expect.objectContaining({ key: "Idempotency-Key" }), ]); expect(postmanItems.find((item) => item.name === "POST /v1/ai/upload")?.request.header).toContainEqual( expect.objectContaining({ key: "x-tenant-id", value: "" }) ); expect(postmanItems.find((item) => item.name === "POST /v1/analytics/events")?.request.header).toEqual([ expect.objectContaining({ key: "x-analytics-token" }), ]); expect(postmanItems.find((item) => item.name === "GET /v1/exports/:exportJobId/download-url")?.request.header).toEqual([ expect.objectContaining({ key: "x-api-key", value: "" }), ]); expect(postmanItems.find((item) => item.name === "POST /v1/billing/stripe/webhooks")?.request.header).toEqual([ expect.objectContaining({ key: "stripe-signature" }), ]); expect(postmanItems.find((item) => item.name === "POST /v1/events/webhooks/attempts/:id")?.request.header).toEqual([ expect.objectContaining({ key: "Authorization", value: "Basic " }), ]); expect((specs.endpoints ?? []).map((endpoint) => endpoint.route)).toEqual([ "https://api.example.com/v1/entities/contacts/rows", "https://api.example.com/v1/entities/contacts/rows/:rowId", "https://api.example.com/v1/entities/contacts/rows", "https://api.example.com/v1/entities/contacts/rows/:rowId", "https://api.example.com/v1/entities/contacts/rows/:rowId", ]); }); });