import { assertEquals } from "@std/assert"; import { find, insert } from "utils/db.ts"; import { getCryptoString } from "utils/server.ts"; let testCounter = 0; function getTestDbPath() { testCounter++; return `data/test_api_user_${testCounter}_${Date.now()}.db`; } function cleanup(dbPath: string) { try { Deno.removeSync(dbPath); } catch { // File may not exist } } function makeCtx(method: string, body?: object, cookie?: string) { const headers: Record = { "Content-Type": "application/json" }; if (cookie) headers["Cookie"] = cookie; const req = new Request("http://localhost", { method, headers, body: method === "GET" ? undefined : JSON.stringify(body || {}), }); return { req }; } async function seedUser(email: string, password: string) { const hashedPw = await getCryptoString(password, "MD5"); const user = insert("User", { name: email.split("@")[0], email, password: hashedPw, }); return user; } async function seedToken(userId: string | number) { const token = await getCryptoString("test-token-" + userId + Date.now(), "MD5"); insert("Token", { token, user_id: userId }); return token; } Deno.test("API user/register - successful registration", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const { handler } = await import("../../routes/api/user/register.tsx"); const ctx = makeCtx("POST", { email: "newuser@example.com", password: "password123", }); const res = await handler.POST!(ctx as any); const body = await res.json(); assertEquals(body.success, true); assertEquals(body.data, true); const users = find("User", { email: "newuser@example.com" }, ["id"]); assertEquals(users.length, 1); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/register - missing email returns error", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const { handler } = await import("../../routes/api/user/register.tsx"); const ctx = makeCtx("POST", { password: "password123" }); const res = await handler.POST!(ctx as any); const body = await res.json(); assertEquals(body.success, false); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/register - missing password returns error", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const { handler } = await import("../../routes/api/user/register.tsx"); const ctx = makeCtx("POST", { email: "test@example.com" }); const res = await handler.POST!(ctx as any); const body = await res.json(); assertEquals(body.success, false); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/login - successful login", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { await seedUser("login@example.com", "mypassword"); const { handler } = await import("../../routes/api/user/login.tsx"); const ctx = makeCtx("POST", { email: "login@example.com", password: "mypassword", }); const res = await handler.POST!(ctx as any); const body = await res.json(); assertEquals(body.success, true); assertEquals(body.data, true); const setCookie = res.headers.get("set-cookie"); assertEquals(setCookie !== null, true); assertEquals(setCookie!.includes("pd-user-token="), true); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/login - wrong email returns error", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const { handler } = await import("../../routes/api/user/login.tsx"); const ctx = makeCtx("POST", { email: "nonexistent@example.com", password: "password", }); const res = await handler.POST!(ctx as any); const body = await res.json(); assertEquals(body.success, false); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/login - missing fields returns error", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const { handler } = await import("../../routes/api/user/login.tsx"); const ctx = makeCtx("POST", { email: "test@example.com" }); const res = await handler.POST!(ctx as any); const body = await res.json(); assertEquals(body.success, false); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/login GET - returns user info with valid token", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const user = await seedUser("getuser@example.com", "password"); const userId = user[0]["id"] as string | number; const token = await seedToken(userId); const { handler } = await import("../../routes/api/user/login.tsx"); const ctx = makeCtx("GET", undefined, `pd-user-token=${token}`); const res = await handler.GET!(ctx as any); const body = await res.json(); assertEquals(body.success, true); assertEquals(body.data.name, "getuser"); assertEquals(body.data.email, "getuser@example.com"); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/login GET - returns error without token", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const { handler } = await import("../../routes/api/user/login.tsx"); const ctx = makeCtx("GET"); const res = await handler.GET!(ctx as any); const body = await res.json(); assertEquals(body.success, false); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/logout - returns success and clears cookie", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const { handler } = await import("../../routes/api/user/logout.tsx"); const ctx = makeCtx("GET"); const res = await handler.GET!(ctx as any); const body = await res.json(); assertEquals(body.success, true); const setCookie = res.headers.get("set-cookie"); assertEquals(setCookie !== null, true); assertEquals(setCookie!.includes("pd-user-token="), true); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/reset - successful password reset", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const user = await seedUser("reset@example.com", "oldpassword"); const userId = user[0]["id"] as string | number; const token = await seedToken(userId); const { handler } = await import("../../routes/api/user/reset.tsx"); const ctx = makeCtx("POST", { old: "oldpassword", new: "newpassword", }, `pd-user-token=${token}`); const res = await handler.POST!(ctx as any); const body = await res.json(); assertEquals(body.success, true); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/reset - wrong old password returns error", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const user = await seedUser("resetwrong@example.com", "oldpassword"); const userId = user[0]["id"] as string | number; const token = await seedToken(userId); const { handler } = await import("../../routes/api/user/reset.tsx"); const ctx = makeCtx("POST", { old: "wrongpassword", new: "newpassword", }, `pd-user-token=${token}`); const res = await handler.POST!(ctx as any); const body = await res.json(); assertEquals(body.success, false); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } }); Deno.test("API user/reset - without token returns error", async () => { const dbPath = getTestDbPath(); Deno.env.set("POSTDOWN_DB_PATH", dbPath); try { const { handler } = await import("../../routes/api/user/reset.tsx"); const ctx = makeCtx("POST", { old: "oldpassword", new: "newpassword", }); const res = await handler.POST!(ctx as any); const body = await res.json(); assertEquals(body.success, false); } finally { Deno.env.delete("POSTDOWN_DB_PATH"); cleanup(dbPath); } });