import { test } from "node:test"; import assert from "node:assert/strict"; import path from "node:path"; import { fileURLToPath } from "node:url"; import dotenv from "dotenv"; import { createSession, hashPassword, verifyPassword } from "../lib/server/auth"; import { loginUser, registerUser } from "../lib/server/auth-service"; import getPool from "../lib/server/db"; import { cleanupTestData, cleanupTestDataFromPool } from "./test-helpers"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const envLoaded = dotenv.config({ path: path.resolve(__dirname, "../../../.env") }); const hasDb = Boolean(process.env.DATABASE_URL); test("password hashing works", async () => { const hash = await hashPassword("test-password"); assert.ok(await verifyPassword("test-password", hash)); assert.ok(!(await verifyPassword("wrong", hash))); }); test("createSession inserts row", async t => { if (!hasDb) { t.skip("DATABASE_URL not set"); return; } if (envLoaded.error) t.diagnostic(String(envLoaded.error)); const pool = getPool(); const client = await pool.connect(); const email = `test_${Date.now()}@example.com`; try { const { rows } = await client.query( "insert into users(email, password_hash) values($1,$2) returning id", [email, await hashPassword("test-password")] ); const userId = rows[0].id as number; const session = await createSession(userId); const { rows: sessionRows } = await client.query( "select id from sessions where user_id=$1 and expires_at > now()", [userId] ); assert.ok(session.token.length > 10); assert.ok(sessionRows.length === 1); } finally { await cleanupTestData(client, { emails: [email] }); client.release(); } }); test("createSession supports ttl override", async t => { if (!hasDb) { t.skip("DATABASE_URL not set"); return; } if (envLoaded.error) t.diagnostic(String(envLoaded.error)); const pool = getPool(); const client = await pool.connect(); const email = `test_${Date.now()}_ttl@example.com`; const ttlMs = 60 * 60 * 1000; const nowMs = Date.now(); try { const { rows } = await client.query( "insert into users(email, password_hash) values($1,$2) returning id", [email, await hashPassword("test-password")] ); const userId = rows[0].id as number; const session = await createSession(userId, { ttlMs }); const { rows: sessionRows } = await client.query( "select expires_at from sessions where user_id=$1 order by created_at desc limit 1", [userId] ); const dbExpiresAt = new Date(sessionRows[0].expires_at).getTime(); const expectedMin = nowMs + ttlMs - 5000; const expectedMax = nowMs + ttlMs + 5000; assert.ok(session.expiresAt.getTime() >= expectedMin); assert.ok(session.expiresAt.getTime() <= expectedMax); assert.ok(dbExpiresAt >= expectedMin); assert.ok(dbExpiresAt <= expectedMax); } finally { await cleanupTestData(client, { emails: [email] }); client.release(); } }); test("loginUser respects remember flag", async t => { if (!hasDb) { t.skip("DATABASE_URL not set"); return; } if (envLoaded.error) t.diagnostic(String(envLoaded.error)); const email = `remember_${Date.now()}@example.com`; const password = "test-password"; const result = await registerUser({ email, password, displayName: "" }); try { const rememberTrue = await loginUser({ email, password, remember: true }); const rememberFalse = await loginUser({ email, password, remember: false }); assert.ok(rememberTrue.session.ttlMs > rememberFalse.session.ttlMs); } finally { const pool = getPool(); await cleanupTestDataFromPool(pool, { userIds: [result.user.id] }); } }); test("registerUser rejects duplicate email", async t => { if (!hasDb) { t.skip("DATABASE_URL not set"); return; } if (envLoaded.error) t.diagnostic(String(envLoaded.error)); const pool = getPool(); const email = `dup_${Date.now()}@example.com`; const password = "test-password"; const mixedCase = email.toUpperCase(); const result = await registerUser({ email, password, displayName: "" }); try { await assert.rejects( () => registerUser({ email: mixedCase, password, displayName: "" }), { message: "EMAIL_EXISTS" } ); } finally { await cleanupTestDataFromPool(pool, { userIds: [result.user.id] }); } });