// Integration test for the minimal admin auth gate on /api/admin/* // (dev-plan.md T6). Spawns server.js on a throwaway port, same isolation // approach as uploads-route.test.js. const test = require("node:test"); const assert = require("node:assert/strict"); const { spawn } = require("node:child_process"); const PORT = 19934 + Math.floor(Math.random() * 1000); const BASE = `http://localhost:${PORT}`; const ADMIN_PASSWORD = "test-password-only-for-this-run"; function waitForServer(url, timeoutMs = 10000) { const deadline = Date.now() + timeoutMs; return (async function poll() { while (Date.now() < deadline) { try { await fetch(url); return; } catch { await new Promise((r) => setTimeout(r, 100)); } } throw new Error("server did not come up in time"); })(); } function sessionCookie(loginRes) { const setCookie = loginRes.headers.get("set-cookie") || ""; return setCookie.split(";")[0]; } let child; test.before(async () => { child = spawn(process.execPath, ["server.js"], { cwd: __dirname, env: { ...process.env, PORT: String(PORT), H3_CONSOLE_BASE: "", H3_CONSOLE_TOKEN: "", ADMIN_PASSWORD }, stdio: "pipe", }); await waitForServer(BASE); }); test.after(() => child.kill()); test("any /api/admin/* route returns 401 without a session cookie", async () => { const res = await fetch(`${BASE}/api/admin/library`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ prompt: "x", videoUrl: "http://example.com/x.mp4" }), }); assert.equal(res.status, 401); }); test("logging in with the wrong password is rejected and sets no cookie", async () => { const res = await fetch(`${BASE}/api/admin/login`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ password: "definitely-wrong" }), }); assert.equal(res.status, 401); assert.equal(res.headers.get("set-cookie"), null); }); test("logging in with the right password grants a session that unlocks /api/admin/*, and logout revokes it", async () => { const loginRes = await fetch(`${BASE}/api/admin/login`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ password: ADMIN_PASSWORD }), }); assert.equal(loginRes.status, 200); const cookie = sessionCookie(loginRes); assert.match(cookie, /^admin_session=.+/); const authedRes = await fetch(`${BASE}/api/admin/library`, { method: "POST", headers: { "Content-Type": "application/json", Cookie: cookie }, body: JSON.stringify({ prompt: "authed test entry", videoUrl: "http://example.com/x.mp4" }), }); assert.equal(authedRes.status, 200); const created = await authedRes.json(); // clean up the entry this test created in the real library.json await fetch(`${BASE}/api/admin/library/${created.id}`, { method: "DELETE", headers: { Cookie: cookie } }); const logoutRes = await fetch(`${BASE}/api/admin/logout`, { method: "POST", headers: { Cookie: cookie } }); assert.equal(logoutRes.status, 200); const afterLogout = await fetch(`${BASE}/api/admin/library`, { method: "POST", headers: { "Content-Type": "application/json", Cookie: cookie }, body: JSON.stringify({ prompt: "should be rejected", videoUrl: "http://example.com/x.mp4" }), }); assert.equal(afterLogout.status, 401); });