import { afterEach, describe, expect, it, vi } from "vitest"; import { ApiClient, ApiError } from "./client"; afterEach(() => { vi.unstubAllGlobals(); }); describe("ApiClient", () => { it("preserves HTTP status on failed requests", async () => { vi.stubGlobal( "fetch", vi.fn().mockResolvedValue( new Response(JSON.stringify({ error: "workspace slug already exists" }), { status: 409, statusText: "Conflict", headers: { "Content-Type": "application/json" }, }), ), ); const client = new ApiClient("https://api.example.test"); try { await client.createWorkspace({ name: "Test", slug: "test" }); throw new Error("expected createWorkspace to fail"); } catch (error) { expect(error).toBeInstanceOf(ApiError); expect(error).toMatchObject({ message: "workspace slug already exists", status: 409, statusText: "Conflict", }); } }); it("uses the expected HTTP contract for autopilot endpoints", async () => { const fetchMock = vi.fn().mockImplementation(() => Promise.resolve( new Response(JSON.stringify({ autopilots: [], runs: [], total: 0 }), { status: 200, headers: { "Content-Type": "application/json" }, }), )); vi.stubGlobal("fetch", fetchMock); const client = new ApiClient("https://api.example.test"); await client.listAutopilots({ status: "active" }); await client.getAutopilot("ap-1"); await client.createAutopilot({ title: "Daily triage", assignee_id: "agent-1", execution_mode: "create_issue", }); await client.updateAutopilot("ap-1", { status: "paused" }); await client.deleteAutopilot("ap-1"); await client.triggerAutopilot("ap-1"); await client.listAutopilotRuns("ap-1", { limit: 10, offset: 20 }); await client.createAutopilotTrigger("ap-1", { kind: "schedule", cron_expression: "0 9 * * *", timezone: "UTC", }); await client.updateAutopilotTrigger("ap-1", "tr-1", { enabled: false }); await client.deleteAutopilotTrigger("ap-1", "tr-1"); const calls = fetchMock.mock.calls.map(([url, init]) => ({ url, method: init?.method ?? "GET", body: init?.body, })); expect(calls).toMatchObject([ { url: "https://api.example.test/api/autopilots?status=active", method: "GET" }, { url: "https://api.example.test/api/autopilots/ap-1", method: "GET" }, { url: "https://api.example.test/api/autopilots", method: "POST", body: JSON.stringify({ title: "Daily triage", assignee_id: "agent-1", execution_mode: "create_issue", }), }, { url: "https://api.example.test/api/autopilots/ap-1", method: "PATCH", body: JSON.stringify({ status: "paused" }), }, { url: "https://api.example.test/api/autopilots/ap-1", method: "DELETE" }, { url: "https://api.example.test/api/autopilots/ap-1/trigger", method: "POST" }, { url: "https://api.example.test/api/autopilots/ap-1/runs?limit=10&offset=20", method: "GET" }, { url: "https://api.example.test/api/autopilots/ap-1/triggers", method: "POST", body: JSON.stringify({ kind: "schedule", cron_expression: "0 9 * * *", timezone: "UTC", }), }, { url: "https://api.example.test/api/autopilots/ap-1/triggers/tr-1", method: "PATCH", body: JSON.stringify({ enabled: false }), }, { url: "https://api.example.test/api/autopilots/ap-1/triggers/tr-1", method: "DELETE" }, ]); }); });