import { describe, it, expect, beforeAll, afterAll } from "vitest"; import { app } from "../index.js"; // Note: These tests require Puppeteer/Chrome to be available // For CI, use the Dockerfile which includes Chrome const BASE = "http://localhost:3199"; let server; beforeAll(async () => { process.env.API_KEYS = "test-key"; process.env.PORT = "3199"; // Import fresh to pick up env server = app.listen(3199); // Wait for browser init await new Promise((r) => setTimeout(r, 2000)); }); afterAll(async () => { server?.close(); }); describe("Auth", () => { it("rejects requests without API key", async () => { const res = await fetch(`${BASE}/v1/convert/html`, { method: "POST" }); expect(res.status).toBe(401); }); it("rejects invalid API key", async () => { const res = await fetch(`${BASE}/v1/convert/html`, { method: "POST", headers: { Authorization: "Bearer wrong-key" }, }); expect(res.status).toBe(403); }); }); describe("Health", () => { it("returns ok", async () => { const res = await fetch(`${BASE}/health`); expect(res.status).toBe(200); const data = await res.json(); expect(data.status).toBe("ok"); }); }); describe("HTML to PDF", () => { it("converts simple HTML", async () => { const res = await fetch(`${BASE}/v1/convert/html`, { method: "POST", headers: { Authorization: "Bearer test-key", "Content-Type": "application/json", }, body: JSON.stringify({ html: "

Test

" }), }); expect(res.status).toBe(200); expect(res.headers.get("content-type")).toBe("application/pdf"); const buf = await res.arrayBuffer(); expect(buf.byteLength).toBeGreaterThan(100); // PDF magic bytes const header = new Uint8Array(buf.slice(0, 5)); expect(String.fromCharCode(...header)).toBe("%PDF-"); }); it("rejects missing html field", async () => { const res = await fetch(`${BASE}/v1/convert/html`, { method: "POST", headers: { Authorization: "Bearer test-key", "Content-Type": "application/json", }, body: JSON.stringify({}), }); expect(res.status).toBe(400); }); }); describe("Markdown to PDF", () => { it("converts markdown", async () => { const res = await fetch(`${BASE}/v1/convert/markdown`, { method: "POST", headers: { Authorization: "Bearer test-key", "Content-Type": "application/json", }, body: JSON.stringify({ markdown: "# Hello\n\nWorld" }), }); expect(res.status).toBe(200); expect(res.headers.get("content-type")).toBe("application/pdf"); }); }); describe("Templates", () => { it("lists templates", async () => { const res = await fetch(`${BASE}/v1/templates`, { headers: { Authorization: "Bearer test-key" }, }); expect(res.status).toBe(200); const data = await res.json(); expect(data.templates).toBeInstanceOf(Array); expect(data.templates.length).toBeGreaterThan(0); }); it("renders invoice template", async () => { const res = await fetch(`${BASE}/v1/templates/invoice/render`, { method: "POST", headers: { Authorization: "Bearer test-key", "Content-Type": "application/json", }, body: JSON.stringify({ invoiceNumber: "TEST-001", date: "2026-02-14", from: { name: "Seller", email: "s@test.com" }, to: { name: "Buyer", email: "b@test.com" }, items: [{ description: "Widget", quantity: 2, unitPrice: 50, taxRate: 20 }], }), }); expect(res.status).toBe(200); expect(res.headers.get("content-type")).toBe("application/pdf"); }); it("returns 404 for unknown template", async () => { const res = await fetch(`${BASE}/v1/templates/nonexistent/render`, { method: "POST", headers: { Authorization: "Bearer test-key", "Content-Type": "application/json", }, body: JSON.stringify({}), }); expect(res.status).toBe(404); }); });