/** * Application Use Case Tests: OpenAdminVoteSessionUseCase */ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { OpenAdminVoteSessionUseCase } from './OpenAdminVoteSessionUseCase'; import { AdminVoteSessionRepository } from '../../domain/repositories/AdminVoteSessionRepository'; import { AdminVoteSession } from '../../domain/entities/AdminVoteSession'; // Mock repository const createMockRepository = () => ({ save: vi.fn(), findById: vi.fn(), findActiveForAdmin: vi.fn(), findByAdminAndLeague: vi.fn(), findByLeague: vi.fn(), findClosedUnprocessed: vi.fn(), }); describe('OpenAdminVoteSessionUseCase', () => { let useCase: OpenAdminVoteSessionUseCase; let mockRepository: ReturnType; beforeEach(() => { mockRepository = createMockRepository(); useCase = new OpenAdminVoteSessionUseCase(mockRepository as unknown as AdminVoteSessionRepository); vi.clearAllMocks(); }); describe('Input validation', () => { it('should reject when voteSessionId is missing', async () => { const result = await useCase.execute({ voteSessionId: '', leagueId: 'league-1', adminId: 'admin-1', startDate: '2026-01-01', endDate: '2026-01-07', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('voteSessionId is required'); }); it('should reject when leagueId is missing', async () => { const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: '', adminId: 'admin-1', startDate: '2026-01-01', endDate: '2026-01-07', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('leagueId is required'); }); it('should reject when adminId is missing', async () => { const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: '', startDate: '2026-01-01', endDate: '2026-01-07', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('adminId is required'); }); it('should reject when startDate is missing', async () => { const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: '', endDate: '2026-01-07', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('startDate is required'); }); it('should reject when endDate is missing', async () => { const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: '2026-01-01', endDate: '', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('endDate is required'); }); it('should reject when startDate is invalid', async () => { const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: 'invalid-date', endDate: '2026-01-07', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('startDate must be a valid date'); }); it('should reject when endDate is invalid', async () => { const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: '2026-01-01', endDate: 'invalid-date', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('endDate must be a valid date'); }); it('should reject when startDate is after endDate', async () => { const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: '2026-01-07', endDate: '2026-01-01', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('startDate must be before endDate'); }); it('should reject when eligibleVoters is empty', async () => { const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: '2026-01-01', endDate: '2026-01-07', eligibleVoters: [], }); expect(result.success).toBe(false); expect(result.errors).toContain('At least one eligible voter is required'); }); it('should reject when eligibleVoters has duplicates', async () => { const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: '2026-01-01', endDate: '2026-01-07', eligibleVoters: ['voter-1', 'voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('Duplicate eligible voters are not allowed'); }); }); describe('Business rules', () => { it('should reject when session ID already exists', async () => { mockRepository.findById.mockResolvedValue({ id: 'session-1' } as unknown as AdminVoteSession); const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: '2026-01-01', endDate: '2026-01-07', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('Vote session with this ID already exists'); }); it('should reject when there is an overlapping active session', async () => { mockRepository.findById.mockResolvedValue(null); mockRepository.findActiveForAdmin.mockResolvedValue([ { startDate: new Date('2026-01-05'), endDate: new Date('2026-01-10'), } ] as unknown as AdminVoteSession[]); const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: '2026-01-01', endDate: '2026-01-07', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors).toContain('Active vote session already exists for this admin in this league with overlapping dates'); }); it('should create and save a new session when valid', async () => { mockRepository.findById.mockResolvedValue(null); mockRepository.findActiveForAdmin.mockResolvedValue([]); const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: '2026-01-01', endDate: '2026-01-07', eligibleVoters: ['voter-1', 'voter-2'], }); expect(result.success).toBe(true); expect(mockRepository.save).toHaveBeenCalled(); const savedSession = mockRepository.save.mock.calls[0][0]; expect(savedSession).toBeInstanceOf(AdminVoteSession); expect(savedSession.id).toBe('session-1'); expect(savedSession.leagueId).toBe('league-1'); expect(savedSession.adminId).toBe('admin-1'); }); }); describe('Error handling', () => { it('should handle repository errors gracefully', async () => { mockRepository.findById.mockRejectedValue(new Error('Database error')); const result = await useCase.execute({ voteSessionId: 'session-1', leagueId: 'league-1', adminId: 'admin-1', startDate: '2026-01-01', endDate: '2026-01-07', eligibleVoters: ['voter-1'], }); expect(result.success).toBe(false); expect(result.errors?.[0]).toContain('Failed to open vote session: Database error'); }); }); });