import { Race, type RaceStatusValue } from '@core/racing/domain/entities/Race'; import type { Logger } from '@core/shared/domain/Logger'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { InMemoryRaceRepository } from './InMemoryRaceRepository'; describe('InMemoryRaceRepository', () => { let repository: InMemoryRaceRepository; let mockLogger: Logger; beforeEach(() => { mockLogger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), }; repository = new InMemoryRaceRepository(mockLogger); }); const createTestRace = ( id: string, leagueId: string, track: string, car: string, scheduledAt: Date, status: RaceStatusValue = 'scheduled', ) => { return Race.create({ id, leagueId, scheduledAt, track, car, status, }); }; describe('constructor', () => { it('should initialize with a logger', () => { expect(repository).toBeDefined(); expect(mockLogger.info).toHaveBeenCalledWith('InMemoryRaceRepository initialized.'); }); }); describe('findById', () => { it('should return null if race not found', async () => { const result = await repository.findById('nonexistent'); expect(result).toBeNull(); expect(mockLogger.debug).toHaveBeenCalledWith('[InMemoryRaceRepository] Finding race by ID: nonexistent'); expect(mockLogger.warn).toHaveBeenCalledWith('Race with ID nonexistent not found.'); }); it('should return the race if found', async () => { const race = createTestRace('1', 'league1', 'Track1', 'Car1', new Date()); await repository.create(race); const result = await repository.findById('1'); expect(result).toEqual(race); expect(mockLogger.info).toHaveBeenCalledWith('Found race by ID: 1.'); }); }); describe('findAll', () => { it('should return all races', async () => { const race1 = createTestRace('1', 'league1', 'Track1', 'Car1', new Date()); const race2 = createTestRace('2', 'league2', 'Track2', 'Car2', new Date()); await repository.create(race1); await repository.create(race2); const result = await repository.findAll(); expect(result).toHaveLength(2); expect(result).toContain(race1); expect(result).toContain(race2); }); }); describe('findByLeagueId', () => { it('should return races filtered by league ID', async () => { const race1 = createTestRace('1', 'league1', 'Track1', 'Car1', new Date()); const race2 = createTestRace('2', 'league2', 'Track2', 'Car2', new Date()); const race3 = createTestRace('3', 'league1', 'Track3', 'Car3', new Date()); await repository.create(race1); await repository.create(race2); await repository.create(race3); const result = await repository.findByLeagueId('league1'); expect(result).toHaveLength(2); expect(result).toContain(race1); expect(result).toContain(race3); }); }); describe('findUpcomingByLeagueId', () => { it('should return upcoming races for league ID', async () => { const pastDate = new Date(Date.now() - 1000 * 60 * 60); // 1 hour ago const futureDate = new Date(Date.now() + 1000 * 60 * 60); // 1 hour from now const race1 = createTestRace('1', 'league1', 'Track1', 'Car1', pastDate, 'scheduled'); const race2 = createTestRace('2', 'league1', 'Track2', 'Car2', futureDate, 'scheduled'); const race3 = createTestRace('3', 'league1', 'Track3', 'Car3', futureDate, 'completed'); await repository.create(race1); await repository.create(race2); await repository.create(race3); const result = await repository.findUpcomingByLeagueId('league1'); expect(result).toHaveLength(1); expect(result).toContain(race2); }); }); describe('findCompletedByLeagueId', () => { it('should return completed races for league ID', async () => { const race1 = createTestRace('1', 'league1', 'Track1', 'Car1', new Date(), 'scheduled'); const race2 = createTestRace('2', 'league1', 'Track2', 'Car2', new Date(), 'completed'); const race3 = createTestRace('3', 'league1', 'Track3', 'Car3', new Date(), 'completed'); await repository.create(race1); await repository.create(race2); await repository.create(race3); const result = await repository.findCompletedByLeagueId('league1'); expect(result).toHaveLength(2); expect(result).toContain(race2); expect(result).toContain(race3); }); }); describe('findByStatus', () => { it('should return races filtered by status', async () => { const race1 = createTestRace('1', 'league1', 'Track1', 'Car1', new Date(), 'scheduled'); const race2 = createTestRace('2', 'league1', 'Track2', 'Car2', new Date(), 'completed'); const race3 = createTestRace('3', 'league1', 'Track3', 'Car3', new Date(), 'scheduled'); await repository.create(race1); await repository.create(race2); await repository.create(race3); const result = await repository.findByStatus('scheduled'); expect(result).toHaveLength(2); expect(result).toContain(race1); expect(result).toContain(race3); }); }); describe('findByDateRange', () => { it('should return races within date range', async () => { const date1 = new Date('2023-01-01'); const date2 = new Date('2023-01-02'); const date3 = new Date('2023-01-03'); const race1 = createTestRace('1', 'league1', 'Track1', 'Car1', date1); const race2 = createTestRace('2', 'league1', 'Track2', 'Car2', date2); const race3 = createTestRace('3', 'league1', 'Track3', 'Car3', date3); await repository.create(race1); await repository.create(race2); await repository.create(race3); const result = await repository.findByDateRange(date1, date2); expect(result).toHaveLength(2); expect(result).toContain(race1); expect(result).toContain(race2); }); }); describe('create', () => { it('should create a new race', async () => { const race = createTestRace('1', 'league1', 'Track1', 'Car1', new Date()); const result = await repository.create(race); expect(result).toEqual(race); expect(mockLogger.info).toHaveBeenCalledWith('Race 1 created successfully.'); }); it('should throw error if race already exists', async () => { const race = createTestRace('1', 'league1', 'Track1', 'Car1', new Date()); await repository.create(race); await expect(repository.create(race)).rejects.toThrow('Race already exists'); }); }); describe('update', () => { it('should update an existing race', async () => { const race = createTestRace('1', 'league1', 'Track1', 'Car1', new Date()); await repository.create(race); const updatedRace = race.start().complete(); const result = await repository.update(updatedRace); expect(result).toEqual(updatedRace); expect(mockLogger.info).toHaveBeenCalledWith('Race 1 updated successfully.'); }); it('should throw error if race does not exist', async () => { const race = createTestRace('1', 'league1', 'Track1', 'Car1', new Date()); await expect(repository.update(race)).rejects.toThrow('Race not found'); }); }); describe('delete', () => { it('should delete an existing race', async () => { const race = createTestRace('1', 'league1', 'Track1', 'Car1', new Date()); await repository.create(race); await repository.delete('1'); expect(mockLogger.info).toHaveBeenCalledWith('Race 1 deleted successfully.'); const found = await repository.findById('1'); expect(found).toBeNull(); }); it('should not throw if race does not exist', async () => { await repository.delete('nonexistent'); expect(mockLogger.warn).toHaveBeenCalledWith('Race with ID nonexistent not found for deletion.'); }); }); describe('exists', () => { it('should return true if race exists', async () => { const race = createTestRace('1', 'league1', 'Track1', 'Car1', new Date()); await repository.create(race); const result = await repository.exists('1'); expect(result).toBe(true); }); it('should return false if race does not exist', async () => { const result = await repository.exists('nonexistent'); expect(result).toBe(false); }); }); });