import { describe, it, expect, vi } from "vitest"; import { verifyAccessToken, hashToken } from "../services/auth"; import jwt from "jsonwebtoken"; import { config } from "../config/env"; describe("auth service", () => { describe("verifyAccessToken", () => { it("returns null and logs error for invalid JWT", async () => { const consoleSpy = vi .spyOn(console, "error") .mockImplementation(() => {}); const result = await verifyAccessToken("invalid-token"); expect(result).toBeNull(); expect(consoleSpy).toHaveBeenCalled(); expect(consoleSpy.mock.calls[0][0]).toMatch(/JWT verification error/); consoleSpy.mockRestore(); }); it("returns null for expired JWT", async () => { const consoleSpy = vi .spyOn(console, "error") .mockImplementation(() => {}); const expiredToken = jwt.sign( { sub: 1, username: "test", role: "user" }, config.jwt.secret, { expiresIn: -1 }, ); const result = await verifyAccessToken(expiredToken); expect(result).toBeNull(); expect(consoleSpy).toHaveBeenCalled(); consoleSpy.mockRestore(); }); }); describe("hashToken", () => { it("produces deterministic SHA-256 hex output", () => { const t1 = hashToken("hello"); const t2 = hashToken("hello"); expect(t1).toBe(t2); expect(t1).toMatch(/^[a-f0-9]{64}$/); }); it("produces different hashes for different inputs", () => { const t1 = hashToken("a"); const t2 = hashToken("b"); expect(t1).not.toBe(t2); }); }); });