import { describe, it, expect, vi, beforeEach } from 'vitest'; import { GetTeamRankingsUseCase, GetTeamRankingsUseCasePorts } from './GetTeamRankingsUseCase'; import { ValidationError } from '../../../shared/errors/ValidationError'; describe('GetTeamRankingsUseCase', () => { let mockLeaderboardsRepository: any; let mockEventPublisher: any; let ports: GetTeamRankingsUseCasePorts; let useCase: GetTeamRankingsUseCase; const mockTeams = [ { id: 't1', name: 'Team A', rating: 2500, memberCount: 0, raceCount: 20 }, { id: 't2', name: 'Team B', rating: 2200, memberCount: 0, raceCount: 15 }, ]; const mockDrivers = [ { id: 'd1', name: 'Alice', rating: 2000, raceCount: 10, teamId: 't1', teamName: 'Team A' }, { id: 'd2', name: 'Bob', rating: 1500, raceCount: 5, teamId: 't1', teamName: 'Team A' }, { id: 'd3', name: 'Charlie', rating: 1800, raceCount: 8, teamId: 't2', teamName: 'Team B' }, { id: 'd4', name: 'David', rating: 1600, raceCount: 2, teamId: 't3', teamName: 'Discovered Team' }, ]; beforeEach(() => { mockLeaderboardsRepository = { findAllTeams: vi.fn().mockResolvedValue([...mockTeams]), findAllDrivers: vi.fn().mockResolvedValue([...mockDrivers]), }; mockEventPublisher = { publishTeamRankingsAccessed: vi.fn().mockResolvedValue(undefined), publishLeaderboardsError: vi.fn().mockResolvedValue(undefined), }; ports = { leaderboardsRepository: mockLeaderboardsRepository, eventPublisher: mockEventPublisher, }; useCase = new GetTeamRankingsUseCase(ports); }); it('should return teams with aggregated member counts', async () => { const result = await useCase.execute(); expect(result.teams).toHaveLength(3); // Team A, Team B, and discovered Team t3 const teamA = result.teams.find(t => t.id === 't1'); expect(teamA?.memberCount).toBe(2); const teamB = result.teams.find(t => t.id === 't2'); expect(teamB?.memberCount).toBe(1); const teamDiscovered = result.teams.find(t => t.id === 't3'); expect(teamDiscovered?.memberCount).toBe(1); expect(teamDiscovered?.name).toBe('Discovered Team'); expect(mockEventPublisher.publishTeamRankingsAccessed).toHaveBeenCalled(); }); it('should filter teams by search term', async () => { const result = await useCase.execute({ search: 'team a' }); expect(result.teams).toHaveLength(1); expect(result.teams[0].name).toBe('Team A'); }); it('should filter teams by minMemberCount', async () => { const result = await useCase.execute({ minMemberCount: 2 }); expect(result.teams).toHaveLength(1); expect(result.teams[0].id).toBe('t1'); }); it('should sort teams by rating DESC by default', async () => { const result = await useCase.execute(); expect(result.teams[0].id).toBe('t1'); // 2500 expect(result.teams[1].id).toBe('t2'); // 2200 expect(result.teams[2].id).toBe('t3'); // 0 }); it('should throw ValidationError for invalid minMemberCount', async () => { await expect(useCase.execute({ minMemberCount: -1 })).rejects.toThrow(ValidationError); }); });