import { describe, expect, test } from "bun:test"; import { type DeviceStart, pollDeviceLogin, startDeviceLogin, validateKey } from "./login"; interface SeenRequest { url: string; method: string | undefined; authorization: string | undefined; body: unknown; } function fetchReturning(status: number, seen: SeenRequest[] = []): typeof fetch { const fake = async (input: string | URL | Request, init?: RequestInit): Promise => { const headers = new Headers(init?.headers); seen.push({ url: String(input), method: init?.method, authorization: headers.get("authorization") ?? undefined, body: init?.body, }); return new Response("{}", { status }); }; return fake as typeof fetch; } describe("validateKey", () => { test("posts an empty JSON body with the Bearer key to /v1/tales", async () => { const seen: SeenRequest[] = []; await validateKey("https://example.test/", "tk_abc", fetchReturning(400, seen)); expect(seen).toEqual([ { url: "https://example.test/v1/tales", // trailing slash collapsed method: "POST", authorization: "Bearer tk_abc", body: "{}", }, ]); }); test("401 means the key is bad", async () => { expect(await validateKey("https://example.test", "tk_bad", fetchReturning(401))).toEqual({ verdict: "invalid" }); }); test("400 means the key authenticated (the empty body is invalid, as expected)", async () => { expect(await validateKey("https://example.test", "tk_good", fetchReturning(400))).toEqual({ verdict: "valid" }); }); test("422 also means the key authenticated — the live server's answer to an empty tale", async () => { expect(await validateKey("https://example.test", "tk_good", fetchReturning(422))).toEqual({ verdict: "valid" }); }); test("any other status is inconclusive, naming the status", async () => { const result = await validateKey("https://example.test", "tk_maybe", fetchReturning(503)); expect(result.verdict).toBe("unknown"); if (result.verdict === "unknown") expect(result.detail).toContain("503"); }); test("a network failure is inconclusive, carrying the error message", async () => { const failing = (async () => { throw new Error("connect ECONNREFUSED 127.0.0.1:443"); }) as unknown as typeof fetch; const result = await validateKey("https://example.test", "tk_offline", failing); expect(result.verdict).toBe("unknown"); if (result.verdict === "unknown") expect(result.detail).toContain("ECONNREFUSED"); }); }); const START: DeviceStart = { device: "dev-secret", code: "TS-ABCD-EFGH", url: "https://example.test/cli?code=TS-ABCD-EFGH", interval: 2, expiresIn: 600, }; /** answers /v1/cli/poll with each body in turn (repeating the last), recording every request */ function fetchScript(responses: Array<{ status?: number; body: unknown }>, seen: SeenRequest[] = []): typeof fetch { let i = 0; const fake = async (input: string | URL | Request, init?: RequestInit): Promise => { const headers = new Headers(init?.headers); seen.push({ url: String(input), method: init?.method, authorization: headers.get("authorization") ?? undefined, body: init?.body, }); const next = responses[Math.min(i, responses.length - 1)]; i += 1; return new Response(JSON.stringify(next?.body ?? {}), { status: next?.status ?? 200 }); }; return fake as typeof fetch; } const instantSleep = async (): Promise => {}; describe("startDeviceLogin", () => { test("posts the key name to /v1/cli/start and returns the handshake", async () => { const seen: SeenRequest[] = []; const result = await startDeviceLogin("https://example.test/", "CLI · box", fetchScript([{ body: START }], seen)); expect(result).toEqual(START); expect(seen[0]?.url).toBe("https://example.test/v1/cli/start"); // trailing slash collapsed expect(seen[0]?.body).toBe(JSON.stringify({ name: "CLI · box" })); }); test("a non-2xx answer throws, naming the status", async () => { await expect( startDeviceLogin("https://example.test", "CLI", fetchScript([{ status: 503, body: {} }])), ).rejects.toThrow("503"); }); test("a malformed body throws rather than returning a half-handshake", async () => { await expect( startDeviceLogin("https://example.test", "CLI", fetchScript([{ body: { device: "x" } }])), ).rejects.toThrow("unexpected response shape"); }); }); describe("pollDeviceLogin", () => { test("rides out pending answers and returns the key on approval", async () => { const seen: SeenRequest[] = []; const script = fetchScript( [ { body: { status: "pending" } }, { body: { status: "pending" } }, { body: { status: "approved", key: "tk_fresh", email: "you@example.test" } }, ], seen, ); const result = await pollDeviceLogin("https://example.test", START, script, instantSleep); expect(result).toEqual({ status: "approved", key: "tk_fresh", email: "you@example.test" }); expect(seen).toHaveLength(3); expect(seen[0]?.url).toBe("https://example.test/v1/cli/poll"); expect(seen[0]?.body).toBe(JSON.stringify({ device: "dev-secret" })); }); test("an explicit expired answer ends the poll", async () => { const result = await pollDeviceLogin( "https://example.test", START, fetchScript([{ body: { status: "expired" } }]), instantSleep, ); expect(result).toEqual({ status: "expired" }); }); test("network blips and junk answers are ridden out, not fatal", async () => { let calls = 0; const flaky = (async () => { calls += 1; if (calls === 1) throw new Error("ECONNRESET"); if (calls === 2) return new Response("not json", { status: 502 }); return new Response(JSON.stringify({ status: "approved", key: "tk_fresh" }), { status: 200 }); }) as unknown as typeof fetch; const result = await pollDeviceLogin("https://example.test", START, flaky, instantSleep); expect(result).toEqual({ status: "approved", key: "tk_fresh", email: undefined }); }); test("the local deadline ends a poll the server never resolves", async () => { let t = 0; const clock = (): number => { t += 300_000; // each check advances five minutes; the 600s deadline passes on the third return t; }; const result = await pollDeviceLogin( "https://example.test", START, fetchScript([{ body: { status: "pending" } }]), instantSleep, clock, ); expect(result).toEqual({ status: "expired" }); }); });