import { beforeEach, describe, expect, it } from "bun:test"; import { Hono } from "hono"; import { authRoutes } from "../../src/server/routes/auth.ts"; import { createTestDb } from "../helpers/db.ts"; function createTestApp() { const db = createTestDb(); const app = new Hono<{ Variables: { db?: any } }>(); app.use("*", async (c, next) => { c.set("db", db); await next(); }); app.route("/api/auth", authRoutes); return { app, db }; } describe("Auth Routes", () => { let app: Hono; beforeEach(() => { const testApp = createTestApp(); app = testApp.app; }); describe("GET /api/auth/me", () => { it("returns null user and setupRequired true when no users exist", async () => { const res = await app.request("/api/auth/me"); expect(res.status).toBe(200); const body = await res.json(); expect(body.user).toBeNull(); expect(body.setupRequired).toBe(true); }); }); describe("POST /api/auth/setup", () => { it("creates first user and returns 201", async () => { const res = await app.request("/api/auth/setup", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: "admin", password: "secret123" }), }); expect(res.status).toBe(201); const body = await res.json(); expect(body.username).toBe("admin"); // Should set a session cookie const setCookie = res.headers.get("set-cookie"); expect(setCookie).toContain("gearbox_session"); }); it("rejects second setup attempt with 403", async () => { // First setup await app.request("/api/auth/setup", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: "admin", password: "secret123" }), }); // Second attempt const res = await app.request("/api/auth/setup", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: "other", password: "secret456" }), }); expect(res.status).toBe(403); }); it("rejects password shorter than 6 characters", async () => { const res = await app.request("/api/auth/setup", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: "admin", password: "short" }), }); expect(res.status).toBe(400); }); }); describe("POST /api/auth/login", () => { beforeEach(async () => { // Create a user first await app.request("/api/auth/setup", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: "admin", password: "secret123" }), }); }); it("returns session cookie on valid login", async () => { const res = await app.request("/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: "admin", password: "secret123" }), }); expect(res.status).toBe(200); const body = await res.json(); expect(body.username).toBe("admin"); const setCookie = res.headers.get("set-cookie"); expect(setCookie).toContain("gearbox_session"); }); it("rejects invalid credentials with 401", async () => { const res = await app.request("/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: "admin", password: "wrongpassword" }), }); expect(res.status).toBe(401); }); }); describe("POST /api/auth/logout", () => { it("clears session cookie", async () => { const res = await app.request("/api/auth/logout", { method: "POST", }); expect(res.status).toBe(200); }); }); });