import { describe, expect, test } from "bun:test"; import { mkdtempSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { createApp } from "../src/app"; import { openDb } from "../src/db"; import { loadOrCreateKey } from "../src/lib/crypto"; // Minimal one-page PDF with a text object — enough for unpdf to open and read. const TINY_PDF = `%PDF-1.4 1 0 obj<>endobj 2 0 obj<>endobj 3 0 obj<>>>>>endobj 4 0 obj<>stream BT /F1 12 Tf 72 720 Td (Glucose 100 mg/dL 70-99 H) Tj ET endstream endobj 5 0 obj<>endobj trailer<>`; async function authedApp(fetchImpl: typeof fetch) { const dir = mkdtempSync(join(tmpdir(), "helios-")); const app = createApp({ db: openDb(dir), key: loadOrCreateKey(dir), dataDir: dir, llmFetch: fetchImpl }); const j = (b: unknown) => ({ method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(b) }); await app.request("/api/setup", j({ password: "hunter2hunter2" })); const cookie = (await app.request("/api/login", j({ password: "hunter2hunter2" }))).headers.get("set-cookie")!; return { app, cookie }; } const llmOk = (async () => new Response(JSON.stringify({ choices: [{ message: { content: JSON.stringify({ collectedDate: "2026-01-15", labName: "Sample Diagnostics", markers: [{ panel: null, name: "Glucose", value: "100", unit: "mg/dL", referenceRange: "70-99", flagged: true }], }) } }] }), { status: 200 })) as unknown as typeof fetch; describe("labs upload", () => { test("PDF upload → pending draft with extracted markers", async () => { const { app, cookie } = await authedApp(llmOk); const fd = new FormData(); fd.append("file", new File([TINY_PDF], "results.pdf", { type: "application/pdf" })); const up = await app.request("/api/labs/upload", { method: "POST", headers: { cookie }, body: fd }); expect(up.status).toBe(201); const { id } = await up.json(); const list = await (await app.request("/api/labs/drafts", { headers: { cookie } })).json(); expect(list.drafts).toHaveLength(1); expect(list.drafts[0].id).toBe(id); expect(list.drafts[0].status).toBe("pending"); expect(list.drafts[0].markerCount).toBe(1); }); test("non-PDF rejected", async () => { const { app, cookie } = await authedApp(llmOk); const fd = new FormData(); fd.append("file", new File(["hi"], "notes.txt", { type: "text/plain" })); const up = await app.request("/api/labs/upload", { method: "POST", headers: { cookie }, body: fd }); expect(up.status).toBe(400); }); test("LLM failure → draft stored with error, not a 500", async () => { const llmDown = (async () => new Response("x", { status: 500 })) as unknown as typeof fetch; const { app, cookie } = await authedApp(llmDown); const fd = new FormData(); fd.append("file", new File([TINY_PDF], "r.pdf", { type: "application/pdf" })); const up = await app.request("/api/labs/upload", { method: "POST", headers: { cookie }, body: fd }); expect(up.status).toBe(201); const list = await (await app.request("/api/labs/drafts", { headers: { cookie } })).json(); expect(list.drafts[0].error).toMatch(/llm_error/); expect(list.drafts[0].markerCount).toBe(0); }); });