import { describe, it, expect, vi, Mocked, beforeEach } from 'vitest'; import { LeagueService } from './LeagueService'; import { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient'; import type { CreateLeagueInputDTO } from '@/lib/types/generated/CreateLeagueInputDTO'; import type { CreateLeagueOutputDTO } from '@/lib/types/generated/CreateLeagueOutputDTO'; import type { RemoveLeagueMemberOutputDTO } from '@/lib/types/generated/RemoveLeagueMemberOutputDTO'; describe('LeagueService', () => { let mockApiClient: Mocked; let service: LeagueService; beforeEach(() => { mockApiClient = { getAllWithCapacity: vi.fn(), getAllWithCapacityAndScoring: vi.fn(), getStandings: vi.fn(), getTotal: vi.fn(), getSchedule: vi.fn(), getMemberships: vi.fn(), create: vi.fn(), removeRosterMember: vi.fn(), updateRosterMemberRole: vi.fn(), } as unknown as Mocked; service = new LeagueService(mockApiClient); }); describe('getAllLeagues', () => { it('should call apiClient.getAllWithCapacityAndScoring and return DTO', async () => { const mockDto = { totalCount: 2, leagues: [ { id: 'league-1', name: 'League One' }, { id: 'league-2', name: 'League Two' }, ], } as any; mockApiClient.getAllWithCapacityAndScoring.mockResolvedValue(mockDto); const result = await service.getAllLeagues(); expect(mockApiClient.getAllWithCapacityAndScoring).toHaveBeenCalled(); expect(result.isOk()).toBe(true); expect(result.unwrap()).toEqual(mockDto); }); it('should handle empty leagues array', async () => { const mockDto = { totalCount: 0, leagues: [] } as any; mockApiClient.getAllWithCapacityAndScoring.mockResolvedValue(mockDto); const result = await service.getAllLeagues(); expect(result.isOk()).toBe(true); expect(result.unwrap()).toEqual(mockDto); }); it('should throw error when apiClient.getAllWithCapacityAndScoring fails', async () => { const error = new Error('API call failed'); mockApiClient.getAllWithCapacityAndScoring.mockRejectedValue(error); const result = await service.getAllLeagues(); expect(result.isErr()).toBe(true); expect(result.getError().message).toBe('API call failed'); }); }); describe('getLeagueStandings', () => { it('should call apiClient.getStandings and return DTO', async () => { const leagueId = 'league-123'; const mockDto = { standings: [] } as any; mockApiClient.getStandings.mockResolvedValue(mockDto); const result = await service.getLeagueStandings(leagueId); expect(mockApiClient.getStandings).toHaveBeenCalledWith(leagueId); expect(result).toEqual(mockDto); }); it('should throw error when apiClient.getStandings fails', async () => { const leagueId = 'league-123'; const error = new Error('API call failed'); mockApiClient.getStandings.mockRejectedValue(error); await expect(service.getLeagueStandings(leagueId)).rejects.toThrow('API call failed'); }); }); describe('getLeagueStats', () => { it('should call apiClient.getTotal and return DTO', async () => { const mockDto = { totalLeagues: 42 }; mockApiClient.getTotal.mockResolvedValue(mockDto); const result = await service.getLeagueStats(); expect(mockApiClient.getTotal).toHaveBeenCalled(); expect(result).toEqual(mockDto); }); it('should throw error when apiClient.getTotal fails', async () => { const error = new Error('API call failed'); mockApiClient.getTotal.mockRejectedValue(error); await expect(service.getLeagueStats()).rejects.toThrow('API call failed'); }); }); describe('getLeagueSchedule', () => { it('should call apiClient.getSchedule and return DTO', async () => { const leagueId = 'league-123'; const mockDto = { races: [ { id: 'race-1', name: 'Race One', date: '2024-12-31T20:00:00Z' }, { id: 'race-2', name: 'Race Two', date: '2025-01-02T20:00:00Z' }, ], } as any; mockApiClient.getSchedule.mockResolvedValue(mockDto); const result = await service.getLeagueSchedule(leagueId); expect(mockApiClient.getSchedule).toHaveBeenCalledWith(leagueId); expect(result).toEqual(mockDto); }); it('should handle empty races array', async () => { const leagueId = 'league-123'; const mockDto = { races: [] }; mockApiClient.getSchedule.mockResolvedValue(mockDto as any); const result = await service.getLeagueSchedule(leagueId); expect(result).toEqual(mockDto); }); it('should throw error when apiClient.getSchedule fails', async () => { const leagueId = 'league-123'; const error = new Error('API call failed'); mockApiClient.getSchedule.mockRejectedValue(error); await expect(service.getLeagueSchedule(leagueId)).rejects.toThrow('API call failed'); }); }); describe('getLeagueMemberships', () => { it('should call apiClient.getMemberships and return DTO', async () => { const leagueId = 'league-123'; const mockDto = { members: [{ driverId: 'driver-1' }, { driverId: 'driver-2' }], } as any; mockApiClient.getMemberships.mockResolvedValue(mockDto); const result = await service.getLeagueMemberships(leagueId); expect(mockApiClient.getMemberships).toHaveBeenCalledWith(leagueId); expect(result).toEqual(mockDto); }); it('should handle empty memberships array', async () => { const leagueId = 'league-123'; const mockDto = { members: [] } as any; mockApiClient.getMemberships.mockResolvedValue(mockDto); const result = await service.getLeagueMemberships(leagueId); expect(result).toEqual(mockDto); }); it('should throw error when apiClient.getMemberships fails', async () => { const leagueId = 'league-123'; const error = new Error('API call failed'); mockApiClient.getMemberships.mockRejectedValue(error); await expect(service.getLeagueMemberships(leagueId)).rejects.toThrow('API call failed'); }); }); describe('createLeague', () => { it('should call apiClient.create', async () => { const input: CreateLeagueInputDTO = { name: 'New League', description: 'A new league', visibility: 'public', ownerId: 'owner-1', }; const mockDto: CreateLeagueOutputDTO = { leagueId: 'new-league-id', success: true, }; mockApiClient.create.mockResolvedValue(mockDto); const result = await service.createLeague(input); expect(mockApiClient.create).toHaveBeenCalledWith(input); expect(result).toEqual(mockDto); }); it('should throw error when apiClient.create fails', async () => { const input: CreateLeagueInputDTO = { name: 'New League', description: 'A new league', visibility: 'public', ownerId: 'owner-1', }; const error = new Error('API call failed'); mockApiClient.create.mockRejectedValue(error); await expect(service.createLeague(input)).rejects.toThrow('API call failed'); }); }); describe('removeMember', () => { it('should call apiClient.removeRosterMember and return DTO', async () => { const leagueId = 'league-123'; const targetDriverId = 'target-789'; const mockDto: RemoveLeagueMemberOutputDTO = { success: true }; mockApiClient.removeRosterMember.mockResolvedValue(mockDto); const result = await service.removeMember(leagueId, targetDriverId); expect(mockApiClient.removeRosterMember).toHaveBeenCalledWith(leagueId, targetDriverId); expect(result).toEqual(mockDto); }); it('should handle unsuccessful removal', async () => { const leagueId = 'league-123'; const targetDriverId = 'target-789'; const mockDto: RemoveLeagueMemberOutputDTO = { success: false }; mockApiClient.removeRosterMember.mockResolvedValue(mockDto); const result = await service.removeMember(leagueId, targetDriverId); expect(result.success).toBe(false); }); it('should throw error when apiClient.removeRosterMember fails', async () => { const leagueId = 'league-123'; const targetDriverId = 'target-789'; const error = new Error('API call failed'); mockApiClient.removeRosterMember.mockRejectedValue(error); await expect(service.removeMember(leagueId, targetDriverId)).rejects.toThrow('API call failed'); }); }); });