jest.mock("@noble/post-quantum/ml-kem.js", () => ({ ml_kem768: { keygen: jest.fn(), encapsulate: jest.fn(), decapsulate: jest.fn(), }, })); jest.mock("jose", () => ({ SignJWT: jest.fn(), jwtVerify: jest.fn(), })); import { UnauthorizedException } from "@nestjs/common"; import { Test, TestingModule } from "@nestjs/testing"; import { HashingService } from "../crypto/services/hashing.service"; import { JwtService } from "../crypto/services/jwt.service"; import { SessionsRepository } from "./repositories/sessions.repository"; import { SessionsService } from "./sessions.service"; describe("SessionsService", () => { let service: SessionsService; let repository: SessionsRepository; const mockSessionsRepository = { create: jest.fn(), findValidByRefreshToken: jest.fn(), update: jest.fn(), revoke: jest.fn(), revokeAllByUserId: jest.fn(), }; const mockHashingService = { hashIp: jest.fn().mockResolvedValue("hashed-ip"), }; const mockJwtService = { generateJwt: jest.fn().mockResolvedValue("new-token"), }; beforeEach(async () => { jest.clearAllMocks(); const module: TestingModule = await Test.createTestingModule({ providers: [ SessionsService, { provide: SessionsRepository, useValue: mockSessionsRepository }, { provide: HashingService, useValue: mockHashingService }, { provide: JwtService, useValue: mockJwtService }, ], }).compile(); service = module.get(SessionsService); repository = module.get(SessionsRepository); }); it("should be defined", () => { expect(service).toBeDefined(); }); describe("createSession", () => { it("should create a session", async () => { mockSessionsRepository.create.mockResolvedValue({ id: "s1" }); const result = await service.createSession("u1", "agent", "1.2.3.4"); expect(result).toEqual({ id: "s1" }); expect(repository.create).toHaveBeenCalled(); }); }); describe("refreshSession", () => { it("should refresh a valid session", async () => { const expiresAt = new Date(); expiresAt.setDate(expiresAt.getDate() + 1); mockSessionsRepository.findValidByRefreshToken.mockResolvedValue({ id: "s1", userId: "u1", expiresAt, }); mockSessionsRepository.update.mockResolvedValue({ id: "s1", refreshToken: "new-token", }); const result = await service.refreshSession("old-token"); expect(result.refreshToken).toBe("new-token"); expect(repository.update).toHaveBeenCalled(); }); it("should throw if session not found", async () => { mockSessionsRepository.findValidByRefreshToken.mockResolvedValue(null); await expect(service.refreshSession("invalid")).rejects.toThrow( UnauthorizedException, ); }); it("should throw and revoke if session expired", async () => { const expiresAt = new Date(); expiresAt.setDate(expiresAt.getDate() - 1); mockSessionsRepository.findValidByRefreshToken.mockResolvedValue({ id: "s1", userId: "u1", expiresAt, }); await expect(service.refreshSession("expired")).rejects.toThrow( UnauthorizedException, ); expect(repository.revoke).toHaveBeenCalledWith("s1"); }); }); describe("revokeSession", () => { it("should revoke a session", async () => { await service.revokeSession("s1"); expect(repository.revoke).toHaveBeenCalledWith("s1"); }); }); });