Files

73 lines
2.7 KiB
TypeScript

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