import "reflect-metadata"; import { ConflictException, UnauthorizedException } from "@nestjs/common"; import { JwtService } from "@nestjs/jwt"; import * as bcrypt from "bcrypt"; import { AuthService } from "../src/auth/auth.service"; /** A fake `pg.Pool` — the goal here is auth logic (hashing, verification, * conflict handling, JWT claims), not exercising a real Postgres, which * `test_live_datastores.py`'s equivalent role covers for ai-service. */ function fakePool(rows: unknown[] = [], rejectCode?: string) { return { query: jest.fn().mockImplementation(async () => { if (rejectCode) { const error = new Error("duplicate") as Error & { code: string }; error.code = rejectCode; throw error; } return { rows }; }), } as unknown as import("pg").Pool; } const jwt = new JwtService({ secret: "test-secret-not-for-real-use" }); describe("AuthService", () => { it("registers a new user and returns username/role", async () => { const pool = fakePool([{ username: "demo", role: "user" }]); const service = new AuthService(pool, jwt); const result = await service.register("demo", "1"); expect(result).toEqual({ username: "demo", role: "user" }); }); it("rejects registering a username that already exists", async () => { const pool = fakePool([], "23505"); const service = new AuthService(pool, jwt); await expect(service.register("admin", "1")).rejects.toBeInstanceOf( ConflictException ); }); it("logs in with the correct password and issues a JWT carrying the role", async () => { const passwordHash = await bcrypt.hash("1", 12); const pool = fakePool([ { id: "u-1", username: "admin", password_hash: passwordHash, role: "admin" }, ]); const service = new AuthService(pool, jwt); const result = await service.login("admin", "1"); expect(result.user).toEqual({ username: "admin", role: "admin" }); const decoded = jwt.verify(result.token) as { sub: string; role: string }; expect(decoded.sub).toBe("u-1"); expect(decoded.role).toBe("admin"); }); it("rejects a wrong password", async () => { const passwordHash = await bcrypt.hash("1", 12); const pool = fakePool([ { id: "u-1", username: "admin", password_hash: passwordHash, role: "admin" }, ]); const service = new AuthService(pool, jwt); await expect(service.login("admin", "wrong")).rejects.toBeInstanceOf( UnauthorizedException ); }); it("rejects a username that does not exist without leaking that distinction", async () => { const pool = fakePool([]); const service = new AuthService(pool, jwt); await expect(service.login("nobody", "1")).rejects.toBeInstanceOf( UnauthorizedException ); }); });