/** * @ai-summary Admin service unit tests * @ai-context Tests business logic for admin management */ import { AdminService } from '../../domain/admin.service'; import { AdminRepository } from '../../data/admin.repository'; describe('AdminService', () => { let adminService: AdminService; let mockRepository: jest.Mocked; beforeEach(() => { mockRepository = { getAdminByAuth0Sub: jest.fn(), getAdminByEmail: jest.fn(), getAllAdmins: jest.fn(), getActiveAdmins: jest.fn(), createAdmin: jest.fn(), revokeAdmin: jest.fn(), reinstateAdmin: jest.fn(), logAuditAction: jest.fn(), getAuditLogs: jest.fn(), } as any; adminService = new AdminService(mockRepository); }); describe('getAdminByAuth0Sub', () => { it('should return admin when found', async () => { const mockAdmin = { auth0Sub: 'auth0|123456', email: 'admin@motovaultpro.com', role: 'admin', createdAt: new Date(), createdBy: 'system', revokedAt: null, updatedAt: new Date(), }; mockRepository.getAdminByAuth0Sub.mockResolvedValue(mockAdmin); const result = await adminService.getAdminByAuth0Sub('auth0|123456'); expect(result).toEqual(mockAdmin); expect(mockRepository.getAdminByAuth0Sub).toHaveBeenCalledWith('auth0|123456'); }); it('should return null when admin not found', async () => { mockRepository.getAdminByAuth0Sub.mockResolvedValue(null); const result = await adminService.getAdminByAuth0Sub('auth0|unknown'); expect(result).toBeNull(); }); }); describe('createAdmin', () => { it('should create new admin and log audit', async () => { const mockAdmin = { auth0Sub: 'auth0|newadmin', email: 'newadmin@motovaultpro.com', role: 'admin', createdAt: new Date(), createdBy: 'auth0|existing', revokedAt: null, updatedAt: new Date(), }; mockRepository.getAdminByEmail.mockResolvedValue(null); mockRepository.createAdmin.mockResolvedValue(mockAdmin); mockRepository.logAuditAction.mockResolvedValue({} as any); const result = await adminService.createAdmin( 'newadmin@motovaultpro.com', 'admin', 'auth0|newadmin', 'auth0|existing' ); expect(result).toEqual(mockAdmin); expect(mockRepository.createAdmin).toHaveBeenCalled(); expect(mockRepository.logAuditAction).toHaveBeenCalledWith( 'auth0|existing', 'CREATE', mockAdmin.auth0Sub, 'admin_user', mockAdmin.email, expect.any(Object) ); }); it('should reject if admin already exists', async () => { const existingAdmin = { auth0Sub: 'auth0|existing', email: 'admin@motovaultpro.com', role: 'admin', createdAt: new Date(), createdBy: 'system', revokedAt: null, updatedAt: new Date(), }; mockRepository.getAdminByEmail.mockResolvedValue(existingAdmin); await expect( adminService.createAdmin('admin@motovaultpro.com', 'admin', 'auth0|new', 'auth0|existing') ).rejects.toThrow('already exists'); }); }); describe('revokeAdmin', () => { it('should revoke admin when multiple active admins exist', async () => { const revokedAdmin = { auth0Sub: 'auth0|toadmin', email: 'toadmin@motovaultpro.com', role: 'admin', createdAt: new Date(), createdBy: 'system', revokedAt: new Date(), updatedAt: new Date(), }; const activeAdmins = [ { auth0Sub: 'auth0|admin1', email: 'admin1@motovaultpro.com', role: 'admin', createdAt: new Date(), createdBy: 'system', revokedAt: null, updatedAt: new Date(), }, { auth0Sub: 'auth0|admin2', email: 'admin2@motovaultpro.com', role: 'admin', createdAt: new Date(), createdBy: 'system', revokedAt: null, updatedAt: new Date(), }, ]; mockRepository.getActiveAdmins.mockResolvedValue(activeAdmins); mockRepository.revokeAdmin.mockResolvedValue(revokedAdmin); mockRepository.logAuditAction.mockResolvedValue({} as any); const result = await adminService.revokeAdmin('auth0|toadmin', 'auth0|admin1'); expect(result).toEqual(revokedAdmin); expect(mockRepository.revokeAdmin).toHaveBeenCalledWith('auth0|toadmin'); expect(mockRepository.logAuditAction).toHaveBeenCalled(); }); it('should prevent revoking last active admin', async () => { const lastAdmin = { auth0Sub: 'auth0|lastadmin', email: 'last@motovaultpro.com', role: 'admin', createdAt: new Date(), createdBy: 'system', revokedAt: null, updatedAt: new Date(), }; mockRepository.getActiveAdmins.mockResolvedValue([lastAdmin]); await expect( adminService.revokeAdmin('auth0|lastadmin', 'auth0|lastadmin') ).rejects.toThrow('Cannot revoke the last active admin'); }); }); describe('reinstateAdmin', () => { it('should reinstate revoked admin and log audit', async () => { const reinstatedAdmin = { auth0Sub: 'auth0|reinstate', email: 'reinstate@motovaultpro.com', role: 'admin', createdAt: new Date(), createdBy: 'system', revokedAt: null, updatedAt: new Date(), }; mockRepository.reinstateAdmin.mockResolvedValue(reinstatedAdmin); mockRepository.logAuditAction.mockResolvedValue({} as any); const result = await adminService.reinstateAdmin('auth0|reinstate', 'auth0|admin'); expect(result).toEqual(reinstatedAdmin); expect(mockRepository.reinstateAdmin).toHaveBeenCalledWith('auth0|reinstate'); expect(mockRepository.logAuditAction).toHaveBeenCalledWith( 'auth0|admin', 'REINSTATE', 'auth0|reinstate', 'admin_user', reinstatedAdmin.email ); }); }); });