Add comprehensive test suite for express modules

Tests for:
- user.ts: User class, roles, permissions, status checks
- util.ts: loadFile utility
- handlers.ts: multiHandler
- types.ts: methodParser, requireAuth, requirePermission
- logging.ts: module structure
- database.ts: connectionConfig, raw queries, PostgresAuthStore
- auth/token.ts: generateToken, hashToken, parseAuthorizationHeader
- auth/password.ts: hashPassword, verifyPassword (scrypt)
- auth/types.ts: Zod parsers, Session class, tokenLifetimes
- auth/store.ts: InMemoryAuthStore
- auth/service.ts: AuthService (login, register, verify, reset)
- basic/*.ts: route structure tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-25 20:40:49 -06:00
parent 408032c30d
commit 33251d9b77
16 changed files with 2152 additions and 2 deletions

View File

@@ -0,0 +1,80 @@
// Tests for auth/password.ts
// Pure unit tests - no database needed
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { hashPassword, verifyPassword } from "./password";
describe("password", () => {
describe("hashPassword", () => {
it("returns a scrypt formatted hash", async () => {
const hash = await hashPassword("testpassword");
assert.ok(hash.startsWith("$scrypt$"));
});
it("includes all scrypt parameters", async () => {
const hash = await hashPassword("testpassword");
const parts = hash.split("$");
// Format: $scrypt$N$r$p$salt$hash
assert.equal(parts.length, 7);
assert.equal(parts[0], "");
assert.equal(parts[1], "scrypt");
// N, r, p should be numbers
assert.ok(!Number.isNaN(parseInt(parts[2], 10)));
assert.ok(!Number.isNaN(parseInt(parts[3], 10)));
assert.ok(!Number.isNaN(parseInt(parts[4], 10)));
});
it("generates different hashes for same password (different salt)", async () => {
const hash1 = await hashPassword("testpassword");
const hash2 = await hashPassword("testpassword");
assert.notEqual(hash1, hash2);
});
});
describe("verifyPassword", () => {
it("returns true for correct password", async () => {
const hash = await hashPassword("correctpassword");
const result = await verifyPassword("correctpassword", hash);
assert.equal(result, true);
});
it("returns false for incorrect password", async () => {
const hash = await hashPassword("correctpassword");
const result = await verifyPassword("wrongpassword", hash);
assert.equal(result, false);
});
it("throws for invalid hash format", async () => {
await assert.rejects(
verifyPassword("password", "invalid-hash"),
/Invalid password hash format/,
);
});
it("throws for non-scrypt hash", async () => {
await assert.rejects(
verifyPassword("password", "$bcrypt$10$salt$hash"),
/Invalid password hash format/,
);
});
it("works with empty password", async () => {
const hash = await hashPassword("");
const result = await verifyPassword("", hash);
assert.equal(result, true);
});
it("works with unicode password", async () => {
const hash = await hashPassword("p@$$w0rd\u{1F511}");
const result = await verifyPassword("p@$$w0rd\u{1F511}", hash);
assert.equal(result, true);
});
it("is case sensitive", async () => {
const hash = await hashPassword("Password");
const result = await verifyPassword("password", hash);
assert.equal(result, false);
});
});
});