fiddy/apps/web/__tests__/auth.test.ts
2026-02-11 23:45:15 -08:00

131 lines
4.4 KiB
TypeScript

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] });
}
});