import { Test, TestingModule } from "@nestjs/testing"; import { HashingService } from "../crypto/services/hashing.service"; import { ApiKeysService } from "./api-keys.service"; import { ApiKeysRepository } from "./repositories/api-keys.repository"; describe("ApiKeysService", () => { let service: ApiKeysService; let repository: ApiKeysRepository; const mockApiKeysRepository = { create: jest.fn(), findAll: jest.fn(), revoke: jest.fn(), findActiveByKeyHash: jest.fn(), updateLastUsed: jest.fn(), }; const mockHashingService = { hashSha256: jest.fn().mockResolvedValue("hashed-key"), }; beforeEach(async () => { jest.clearAllMocks(); const module: TestingModule = await Test.createTestingModule({ providers: [ ApiKeysService, { provide: ApiKeysRepository, useValue: mockApiKeysRepository, }, { provide: HashingService, useValue: mockHashingService, }, ], }).compile(); service = module.get(ApiKeysService); repository = module.get(ApiKeysRepository); }); it("should be defined", () => { expect(service).toBeDefined(); }); describe("create", () => { it("should create an API key", async () => { const userId = "user-id"; const name = "Test Key"; const expiresAt = new Date(); const result = await service.create(userId, name, expiresAt); expect(repository.create).toHaveBeenCalledWith( expect.objectContaining({ userId, name, prefix: "mg_live_", expiresAt, }), ); expect(result).toHaveProperty("key"); expect(result.name).toBe(name); expect(result.expiresAt).toBe(expiresAt); expect(result.key).toMatch(/^mg_live_/); }); }); describe("findAll", () => { it("should find all API keys for a user", async () => { const userId = "user-id"; const expectedKeys = [{ id: "1", name: "Key 1" }]; mockApiKeysRepository.findAll.mockResolvedValue(expectedKeys); const result = await service.findAll(userId); expect(repository.findAll).toHaveBeenCalledWith(userId); expect(result).toEqual(expectedKeys); }); }); describe("revoke", () => { it("should revoke an API key", async () => { const userId = "user-id"; const keyId = "key-id"; const expectedResult = [{ id: keyId, isActive: false }]; mockApiKeysRepository.revoke.mockResolvedValue(expectedResult); const result = await service.revoke(userId, keyId); expect(repository.revoke).toHaveBeenCalledWith(userId, keyId); expect(result).toEqual(expectedResult); }); }); describe("validateKey", () => { it("should validate a valid API key", async () => { const key = "mg_live_testkey"; const apiKey = { id: "1", isActive: true, expiresAt: null }; mockApiKeysRepository.findActiveByKeyHash.mockResolvedValue(apiKey); const result = await service.validateKey(key); expect(result).toEqual(apiKey); expect(repository.findActiveByKeyHash).toHaveBeenCalled(); expect(repository.updateLastUsed).toHaveBeenCalledWith(apiKey.id); }); it("should return null for invalid API key", async () => { mockApiKeysRepository.findActiveByKeyHash.mockResolvedValue(null); const result = await service.validateKey("invalid-key"); expect(result).toBeNull(); }); it("should return null for expired API key", async () => { const key = "mg_live_testkey"; const expiredDate = new Date(); expiredDate.setFullYear(expiredDate.getFullYear() - 1); const apiKey = { id: "1", isActive: true, expiresAt: expiredDate }; mockApiKeysRepository.findActiveByKeyHash.mockResolvedValue(apiKey); const result = await service.validateKey(key); expect(result).toBeNull(); }); }); });