import { beforeEach, describe, expect, it } from 'vitest'; import { LeaguesTestContext } from '../LeaguesTestContext'; import { League as RacingLeague } from '../../../../core/racing/domain/entities/League'; import { Season } from '../../../../core/racing/domain/entities/season/Season'; import { Race } from '../../../../core/racing/domain/entities/Race'; describe('League Schedule - GetLeagueScheduleUseCase', () => { let context: LeaguesTestContext; beforeEach(() => { context = new LeaguesTestContext(); context.clear(); }); const seedRacingLeague = async (params: { leagueId: string }) => { const league = RacingLeague.create({ id: params.leagueId, name: 'Racing League', description: 'League used for schedule integration tests', ownerId: 'driver-123', }); await context.racingLeagueRepository.create(league); return league; }; const seedSeason = async (params: { seasonId: string; leagueId: string; startDate: Date; endDate: Date; status?: 'planned' | 'active' | 'completed' | 'archived' | 'cancelled'; schedulePublished?: boolean; }) => { const season = Season.create({ id: params.seasonId, leagueId: params.leagueId, gameId: 'iracing', name: 'Season 1', status: params.status ?? 'active', startDate: params.startDate, endDate: params.endDate, ...(params.schedulePublished !== undefined ? { schedulePublished: params.schedulePublished } : {}), }); await context.seasonRepository.add(season); return season; }; it('returns schedule for active season and races within season window', async () => { const leagueId = 'league-1'; await seedRacingLeague({ leagueId }); const seasonId = 'season-jan'; await seedSeason({ seasonId, leagueId, startDate: new Date('2025-01-01T00:00:00Z'), endDate: new Date('2025-01-31T23:59:59Z'), status: 'active', }); const createRace1 = await context.createLeagueSeasonScheduleRaceUseCase.execute({ leagueId, seasonId, track: 'Track A', car: 'Car A', scheduledAt: new Date('2025-01-10T20:00:00Z'), }); expect(createRace1.isOk()).toBe(true); const createRace2 = await context.createLeagueSeasonScheduleRaceUseCase.execute({ leagueId, seasonId, track: 'Track B', car: 'Car B', scheduledAt: new Date('2025-01-20T20:00:00Z'), }); expect(createRace2.isOk()).toBe(true); const result = await context.getLeagueScheduleUseCase.execute({ leagueId }); expect(result.isOk()).toBe(true); const value = result.unwrap(); expect(value.league.id.toString()).toBe(leagueId); expect(value.seasonId).toBe(seasonId); expect(value.published).toBe(false); expect(value.races.map(r => r.race.track)).toEqual(['Track A', 'Track B']); }); it('scopes schedule by seasonId (no season date bleed)', async () => { const leagueId = 'league-1'; await seedRacingLeague({ leagueId }); const janSeasonId = 'season-jan'; const febSeasonId = 'season-feb'; await seedSeason({ seasonId: janSeasonId, leagueId, startDate: new Date('2025-01-01T00:00:00Z'), endDate: new Date('2025-01-31T23:59:59Z'), status: 'active', }); await seedSeason({ seasonId: febSeasonId, leagueId, startDate: new Date('2025-02-01T00:00:00Z'), endDate: new Date('2025-02-28T23:59:59Z'), status: 'planned', }); const janRace = await context.createLeagueSeasonScheduleRaceUseCase.execute({ leagueId, seasonId: janSeasonId, track: 'Track Jan', car: 'Car Jan', scheduledAt: new Date('2025-01-10T20:00:00Z'), }); expect(janRace.isOk()).toBe(true); const febRace = await context.createLeagueSeasonScheduleRaceUseCase.execute({ leagueId, seasonId: febSeasonId, track: 'Track Feb', car: 'Car Feb', scheduledAt: new Date('2025-02-10T20:00:00Z'), }); expect(febRace.isOk()).toBe(true); const janResult = await context.getLeagueScheduleUseCase.execute({ leagueId, seasonId: janSeasonId, }); expect(janResult.isOk()).toBe(true); const janValue = janResult.unwrap(); expect(janValue.seasonId).toBe(janSeasonId); expect(janValue.races.map(r => r.race.track)).toEqual(['Track Jan']); const febResult = await context.getLeagueScheduleUseCase.execute({ leagueId, seasonId: febSeasonId, }); expect(febResult.isOk()).toBe(true); const febValue = febResult.unwrap(); expect(febValue.seasonId).toBe(febSeasonId); expect(febValue.races.map(r => r.race.track)).toEqual(['Track Feb']); }); it('returns all races when no seasons exist for league', async () => { const leagueId = 'league-1'; await seedRacingLeague({ leagueId }); await context.raceRepository.create( Race.create({ id: 'race-1', leagueId, scheduledAt: new Date('2025-01-10T20:00:00Z'), track: 'Track 1', car: 'Car 1', }), ); await context.raceRepository.create( Race.create({ id: 'race-2', leagueId, scheduledAt: new Date('2025-01-15T20:00:00Z'), track: 'Track 2', car: 'Car 2', }), ); const result = await context.getLeagueScheduleUseCase.execute({ leagueId }); expect(result.isOk()).toBe(true); const value = result.unwrap(); expect(value.seasonId).toBe('no-season'); expect(value.published).toBe(false); expect(value.races.map(r => r.race.track)).toEqual(['Track 1', 'Track 2']); }); it('reflects schedule published state from the selected season', async () => { const leagueId = 'league-1'; await seedRacingLeague({ leagueId }); const seasonId = 'season-1'; await seedSeason({ seasonId, leagueId, startDate: new Date('2025-01-01T00:00:00Z'), endDate: new Date('2025-01-31T23:59:59Z'), status: 'active', schedulePublished: false, }); const pre = await context.getLeagueScheduleUseCase.execute({ leagueId }); expect(pre.isOk()).toBe(true); expect(pre.unwrap().published).toBe(false); const publish = await context.publishLeagueSeasonScheduleUseCase.execute({ leagueId, seasonId }); expect(publish.isOk()).toBe(true); const post = await context.getLeagueScheduleUseCase.execute({ leagueId }); expect(post.isOk()).toBe(true); expect(post.unwrap().published).toBe(true); }); it('returns LEAGUE_NOT_FOUND when league does not exist', async () => { const result = await context.getLeagueScheduleUseCase.execute({ leagueId: 'missing-league' }); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('LEAGUE_NOT_FOUND'); }); it('returns SEASON_NOT_FOUND when requested season does not belong to the league', async () => { const leagueId = 'league-1'; await seedRacingLeague({ leagueId }); await seedSeason({ seasonId: 'season-other', leagueId: 'league-other', startDate: new Date('2025-01-01T00:00:00Z'), endDate: new Date('2025-01-31T23:59:59Z'), status: 'active', }); const result = await context.getLeagueScheduleUseCase.execute({ leagueId, seasonId: 'season-other', }); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('SEASON_NOT_FOUND'); }); });