import { describe, it, expect, beforeEach, vi, type Mock } from 'vitest'; import { GetLeagueRosterMembersUseCase, type GetLeagueRosterMembersInput, type GetLeagueRosterMembersResult, type GetLeagueRosterMembersErrorCode, } from './GetLeagueRosterMembersUseCase'; import type { UseCaseOutputPort } from '@core/shared/application'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import { LeagueMembership } from '../../domain/entities/LeagueMembership'; import { Driver } from '../../domain/entities/Driver'; import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository'; import type { IDriverRepository } from '../../domain/repositories/IDriverRepository'; import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository'; describe('GetLeagueRosterMembersUseCase', () => { let useCase: GetLeagueRosterMembersUseCase; let leagueMembershipRepository: { getLeagueMembers: Mock; }; let driverRepository: { findById: Mock; }; let leagueRepository: { exists: Mock; }; let output: UseCaseOutputPort & { present: Mock }; beforeEach(() => { leagueMembershipRepository = { getLeagueMembers: vi.fn(), }; driverRepository = { findById: vi.fn(), }; leagueRepository = { exists: vi.fn(), }; output = { present: vi.fn(), }; useCase = new GetLeagueRosterMembersUseCase( leagueMembershipRepository as unknown as ILeagueMembershipRepository, driverRepository as unknown as IDriverRepository, leagueRepository as unknown as ILeagueRepository, output, ); }); it('presents only members with resolvable drivers', async () => { const leagueId = 'league-1'; const memberships = [ LeagueMembership.create({ id: 'membership-1', leagueId, driverId: 'driver-1', role: 'member', joinedAt: new Date(), }), LeagueMembership.create({ id: 'membership-2', leagueId, driverId: 'driver-missing', role: 'admin', joinedAt: new Date(), }), ]; const driver1 = Driver.create({ id: 'driver-1', iracingId: '123', name: 'Driver 1', country: 'US', }); leagueRepository.exists.mockResolvedValue(true); leagueMembershipRepository.getLeagueMembers.mockResolvedValue(memberships); driverRepository.findById.mockImplementation((id: string) => { if (id === 'driver-1') return Promise.resolve(driver1); return Promise.resolve(null); }); const result = await useCase.execute({ leagueId } as GetLeagueRosterMembersInput); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBeUndefined(); expect(output.present).toHaveBeenCalledTimes(1); const presented = output.present.mock.calls[0]?.[0] as GetLeagueRosterMembersResult; expect(presented.members).toHaveLength(1); expect(presented.members[0]?.membership).toEqual(memberships[0]); expect(presented.members[0]?.driver).toEqual(driver1); }); it('returns LEAGUE_NOT_FOUND when league does not exist', async () => { leagueRepository.exists.mockResolvedValue(false); const result = await useCase.execute({ leagueId: 'missing' } as GetLeagueRosterMembersInput); expect(result.isErr()).toBe(true); const err = result.unwrapErr() as ApplicationErrorCode< GetLeagueRosterMembersErrorCode, { message: string } >; expect(err.code).toBe('LEAGUE_NOT_FOUND'); expect(err.details.message).toBe('League not found'); expect(output.present).not.toHaveBeenCalled(); }); it('returns REPOSITORY_ERROR when repository throws', async () => { leagueRepository.exists.mockRejectedValue(new Error('Repository failure')); const result = await useCase.execute({ leagueId: 'league-1' } as GetLeagueRosterMembersInput); expect(result.isErr()).toBe(true); const err = result.unwrapErr() as ApplicationErrorCode< GetLeagueRosterMembersErrorCode, { message: string } >; expect(err.code).toBe('REPOSITORY_ERROR'); expect(err.details.message).toBe('Repository failure'); expect(output.present).not.toHaveBeenCalled(); }); });