/* eslint-disable max-lines-per-function -- Test suites naturally have many cases */ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; describe("jwt service", () => { const ORIGINAL_ENV = process.env; beforeEach(() => { process.env = { ...ORIGINAL_ENV }; vi.resetModules(); }); afterEach(() => { process.env = ORIGINAL_ENV; }); describe("signToken", () => { it("throws when JWT_SECRET is not set", async () => { delete process.env["JWT_SECRET"]; const { signToken } = await import("../../src/services/jwt.js"); expect(() => signToken("test_id")).toThrow("JWT_SECRET environment variable is required"); }); it("returns a three-part dot-separated token", async () => { process.env["JWT_SECRET"] = "test_secret"; const { signToken } = await import("../../src/services/jwt.js"); const token = signToken("test_id"); expect(token.split(".")).toHaveLength(3); }); }); describe("verifyToken", () => { it("throws when JWT_SECRET is not set", async () => { delete process.env["JWT_SECRET"]; const { verifyToken } = await import("../../src/services/jwt.js"); expect(() => verifyToken("a.b.c")).toThrow("JWT_SECRET environment variable is required"); }); it("round-trips a token correctly", async () => { process.env["JWT_SECRET"] = "test_secret"; const { signToken, verifyToken } = await import("../../src/services/jwt.js"); const token = signToken("user_123"); const payload = verifyToken(token); expect(payload.discordId).toBe("user_123"); }); it("throws on wrong token format (not 3 parts)", async () => { process.env["JWT_SECRET"] = "test_secret"; const { verifyToken } = await import("../../src/services/jwt.js"); expect(() => verifyToken("only.two")).toThrow("Invalid token format"); }); it("throws on tampered signature", async () => { process.env["JWT_SECRET"] = "test_secret"; const { signToken, verifyToken } = await import("../../src/services/jwt.js"); const token = signToken("user_123"); const parts = token.split("."); const tampered = `${parts[0]}.${parts[1]}.BAD_SIGNATURE`; expect(() => verifyToken(tampered)).toThrow("Invalid token signature"); }); it("throws on expired token", async () => { process.env["JWT_SECRET"] = "test_secret"; const { verifyToken } = await import("../../src/services/jwt.js"); // Build a token with exp in the past const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url"); const payload = Buffer.from( JSON.stringify({ discordId: "x", iat: 1000, exp: 1001 }), ).toString("base64url"); const { createHmac } = await import("crypto"); const signature = createHmac("sha256", "test_secret") .update(`${header}.${payload}`) .digest("base64url"); expect(() => verifyToken(`${header}.${payload}.${signature}`)).toThrow("Token has expired"); }); }); });