/** * Audit Service Tests */ import { Test, TestingModule } from '@nestjs/testing'; import { AuditService } from './audit.service'; import { AUDIT_LOG_REPOSITORY, AuditLogRepository } from '../../domain/ports/out/audit-log.repository'; import { AuditAction, AuditStatus, AuditLog } from '../../domain/entities/audit-log.entity'; describe('AuditService', () => { let service: AuditService; let repository: jest.Mocked; beforeEach(async () => { const mockRepository: jest.Mocked = { save: jest.fn(), findById: jest.fn(), findByFilters: jest.fn(), count: jest.fn(), findByResource: jest.fn(), findRecentByOrganization: jest.fn(), findByUser: jest.fn(), }; const module: TestingModule = await Test.createTestingModule({ providers: [ AuditService, { provide: AUDIT_LOG_REPOSITORY, useValue: mockRepository, }, ], }).compile(); service = module.get(AuditService); repository = module.get(AUDIT_LOG_REPOSITORY); }); describe('log', () => { it('should create and save an audit log', async () => { const input = { action: AuditAction.BOOKING_CREATED, status: AuditStatus.SUCCESS, userId: 'user-123', userEmail: 'user@example.com', organizationId: 'org-123', }; await service.log(input); expect(repository.save).toHaveBeenCalledWith( expect.objectContaining({ action: AuditAction.BOOKING_CREATED, status: AuditStatus.SUCCESS, userId: 'user-123', }) ); }); it('should not throw error if save fails', async () => { repository.save.mockRejectedValue(new Error('Database error')); const input = { action: AuditAction.BOOKING_CREATED, status: AuditStatus.SUCCESS, userId: 'user-123', userEmail: 'user@example.com', organizationId: 'org-123', }; await expect(service.log(input)).resolves.not.toThrow(); }); }); describe('logSuccess', () => { it('should log a successful action', async () => { await service.logSuccess( AuditAction.BOOKING_CREATED, 'user-123', 'user@example.com', 'org-123', { resourceType: 'booking', resourceId: 'booking-123' } ); expect(repository.save).toHaveBeenCalledWith( expect.objectContaining({ status: AuditStatus.SUCCESS, }) ); }); }); describe('logFailure', () => { it('should log a failed action with error message', async () => { await service.logFailure( AuditAction.BOOKING_CREATED, 'user-123', 'user@example.com', 'org-123', 'Validation failed', { resourceType: 'booking' } ); expect(repository.save).toHaveBeenCalledWith( expect.objectContaining({ status: AuditStatus.FAILURE, errorMessage: 'Validation failed', }) ); }); }); describe('getAuditLogs', () => { it('should return audit logs with filters', async () => { const mockLogs = [ AuditLog.create({ id: '1', action: AuditAction.BOOKING_CREATED, status: AuditStatus.SUCCESS, userId: 'user-123', userEmail: 'user@example.com', organizationId: 'org-123', }), ]; repository.findByFilters.mockResolvedValue(mockLogs); repository.count.mockResolvedValue(1); const result = await service.getAuditLogs({ organizationId: 'org-123' }); expect(result.logs).toEqual(mockLogs); expect(result.total).toBe(1); }); }); describe('getResourceAuditTrail', () => { it('should return audit trail for a resource', async () => { const mockLogs = [ AuditLog.create({ id: '1', action: AuditAction.BOOKING_CREATED, status: AuditStatus.SUCCESS, userId: 'user-123', userEmail: 'user@example.com', organizationId: 'org-123', resourceType: 'booking', resourceId: 'booking-123', }), ]; repository.findByResource.mockResolvedValue(mockLogs); const result = await service.getResourceAuditTrail('booking', 'booking-123'); expect(result).toEqual(mockLogs); expect(repository.findByResource).toHaveBeenCalledWith('booking', 'booking-123'); }); }); });