refactor
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import { InMemoryStandingRepository } from './InMemoryStandingRepository';
|
||||
import { Standing } from '@core/racing/domain/entities/Standing';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
describe('InMemoryStandingRepository', () => {
|
||||
let repository: InMemoryStandingRepository;
|
||||
let mockLogger: Logger;
|
||||
let mockResultRepository: any;
|
||||
let mockRaceRepository: any;
|
||||
let mockLeagueRepository: any;
|
||||
const testPointsSystems: Record<string, Record<number, number>> = {
|
||||
'f1-2024': {
|
||||
1: 25, 2: 18, 3: 15, 4: 12, 5: 10,
|
||||
6: 8, 7: 6, 8: 4, 9: 2, 10: 1
|
||||
},
|
||||
'indycar': {
|
||||
1: 50, 2: 40, 3: 35, 4: 32, 5: 30,
|
||||
6: 28, 7: 26, 8: 24, 9: 22, 10: 20,
|
||||
11: 19, 12: 18, 13: 17, 14: 16, 15: 15
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockLogger = {
|
||||
debug: vi.fn(),
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
mockResultRepository = {
|
||||
findById: vi.fn(),
|
||||
findAll: vi.fn(),
|
||||
findByRaceId: vi.fn(),
|
||||
findByDriverId: vi.fn(),
|
||||
findByDriverIdAndLeagueId: vi.fn(),
|
||||
create: vi.fn(),
|
||||
createMany: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
deleteByRaceId: vi.fn(),
|
||||
exists: vi.fn(),
|
||||
existsByRaceId: vi.fn(),
|
||||
} as any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
mockRaceRepository = {
|
||||
findById: vi.fn(),
|
||||
findAll: vi.fn(),
|
||||
findByLeagueId: vi.fn(),
|
||||
findUpcomingByLeagueId: vi.fn(),
|
||||
findCompletedByLeagueId: vi.fn(),
|
||||
findByStatus: vi.fn(),
|
||||
findByDateRange: vi.fn(),
|
||||
create: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
exists: vi.fn(),
|
||||
} as any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
mockLeagueRepository = {
|
||||
findById: vi.fn(),
|
||||
findByOwnerId: vi.fn(),
|
||||
searchByName: vi.fn(),
|
||||
findAll: vi.fn(),
|
||||
create: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
exists: vi.fn(),
|
||||
} as any;
|
||||
repository = new InMemoryStandingRepository(
|
||||
mockLogger,
|
||||
testPointsSystems,
|
||||
mockResultRepository,
|
||||
mockRaceRepository,
|
||||
mockLeagueRepository
|
||||
);
|
||||
});
|
||||
|
||||
const createTestStanding = (leagueId: string, driverId: string, position: number = 1, points: number = 0) => {
|
||||
return Standing.create({
|
||||
leagueId,
|
||||
driverId,
|
||||
position,
|
||||
points,
|
||||
});
|
||||
};
|
||||
|
||||
describe('constructor', () => {
|
||||
it('should initialize with required parameters', () => {
|
||||
expect(repository).toBeDefined();
|
||||
expect(mockLogger.info).toHaveBeenCalledWith('InMemoryStandingRepository initialized.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('findByLeagueId', () => {
|
||||
it('should return standings for the specified league', async () => {
|
||||
const standing1 = createTestStanding('league1', 'driver1', 1, 25);
|
||||
const standing2 = createTestStanding('league1', 'driver2', 2, 18);
|
||||
const standing3 = createTestStanding('league2', 'driver3', 1, 50);
|
||||
await repository.save(standing1);
|
||||
await repository.save(standing2);
|
||||
await repository.save(standing3);
|
||||
|
||||
const result = await repository.findByLeagueId('league1');
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0]).toEqual(standing1);
|
||||
expect(result[1]).toEqual(standing2);
|
||||
});
|
||||
|
||||
it('should return empty array if no standings for league', async () => {
|
||||
const result = await repository.findByLeagueId('nonexistent');
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should sort standings by position then points', async () => {
|
||||
const standing1 = createTestStanding('league1', 'driver1', 2, 18);
|
||||
const standing2 = createTestStanding('league1', 'driver2', 1, 25);
|
||||
await repository.save(standing1);
|
||||
await repository.save(standing2);
|
||||
|
||||
const result = await repository.findByLeagueId('league1');
|
||||
expect(result[0]).toEqual(standing2); // position 1
|
||||
expect(result[1]).toEqual(standing1); // position 2
|
||||
});
|
||||
});
|
||||
|
||||
describe('findByDriverIdAndLeagueId', () => {
|
||||
it('should return the standing if found', async () => {
|
||||
const standing = createTestStanding('league1', 'driver1');
|
||||
await repository.save(standing);
|
||||
|
||||
const result = await repository.findByDriverIdAndLeagueId('driver1', 'league1');
|
||||
expect(result).toEqual(standing);
|
||||
});
|
||||
|
||||
it('should return null if not found', async () => {
|
||||
const result = await repository.findByDriverIdAndLeagueId('driver1', 'league1');
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('findAll', () => {
|
||||
it('should return all standings', async () => {
|
||||
const standing1 = createTestStanding('league1', 'driver1');
|
||||
const standing2 = createTestStanding('league2', 'driver2');
|
||||
await repository.save(standing1);
|
||||
await repository.save(standing2);
|
||||
|
||||
const result = await repository.findAll();
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result).toContain(standing1);
|
||||
expect(result).toContain(standing2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('save', () => {
|
||||
it('should save a new standing', async () => {
|
||||
const standing = createTestStanding('league1', 'driver1');
|
||||
const result = await repository.save(standing);
|
||||
expect(result).toEqual(standing);
|
||||
expect(mockLogger.info).toHaveBeenCalledWith('Standing for league league1, driver driver1 saved successfully.');
|
||||
});
|
||||
|
||||
it('should update existing standing', async () => {
|
||||
const standing = createTestStanding('league1', 'driver1', 1, 25);
|
||||
await repository.save(standing);
|
||||
const updatedStanding = createTestStanding('league1', 'driver1', 1, 35);
|
||||
const result = await repository.save(updatedStanding);
|
||||
expect(result).toEqual(updatedStanding);
|
||||
});
|
||||
});
|
||||
|
||||
describe('saveMany', () => {
|
||||
it('should save multiple standings', async () => {
|
||||
const standings = [
|
||||
createTestStanding('league1', 'driver1'),
|
||||
createTestStanding('league1', 'driver2'),
|
||||
];
|
||||
const result = await repository.saveMany(standings);
|
||||
expect(result).toEqual(standings);
|
||||
expect(mockLogger.info).toHaveBeenCalledWith('2 standings saved successfully.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete', () => {
|
||||
it('should delete existing standing', async () => {
|
||||
const standing = createTestStanding('league1', 'driver1');
|
||||
await repository.save(standing);
|
||||
await repository.delete('league1', 'driver1');
|
||||
const found = await repository.findByDriverIdAndLeagueId('driver1', 'league1');
|
||||
expect(found).toBeNull();
|
||||
expect(mockLogger.info).toHaveBeenCalledWith('Standing for league league1, driver driver1 deleted successfully.');
|
||||
});
|
||||
|
||||
it('should log warning if standing not found', async () => {
|
||||
await repository.delete('league1', 'driver1');
|
||||
expect(mockLogger.warn).toHaveBeenCalledWith('Standing for league league1, driver driver1 not found for deletion.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteByLeagueId', () => {
|
||||
it('should delete all standings for a league', async () => {
|
||||
const standing1 = createTestStanding('league1', 'driver1');
|
||||
const standing2 = createTestStanding('league1', 'driver2');
|
||||
const standing3 = createTestStanding('league2', 'driver3');
|
||||
await repository.save(standing1);
|
||||
await repository.save(standing2);
|
||||
await repository.save(standing3);
|
||||
|
||||
await repository.deleteByLeagueId('league1');
|
||||
const league1Standings = await repository.findByLeagueId('league1');
|
||||
const league2Standings = await repository.findByLeagueId('league2');
|
||||
expect(league1Standings).toHaveLength(0);
|
||||
expect(league2Standings).toHaveLength(1);
|
||||
expect(mockLogger.info).toHaveBeenCalledWith('Deleted 2 standings for league id: league1.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('exists', () => {
|
||||
it('should return true if standing exists', async () => {
|
||||
const standing = createTestStanding('league1', 'driver1');
|
||||
await repository.save(standing);
|
||||
const result = await repository.exists('league1', 'driver1');
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if standing does not exist', async () => {
|
||||
const result = await repository.exists('league1', 'driver1');
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('recalculate', () => {
|
||||
it('should throw error if repositories are missing', async () => {
|
||||
const repoWithoutDeps = new InMemoryStandingRepository(mockLogger, testPointsSystems);
|
||||
await expect(repoWithoutDeps.recalculate('league1')).rejects.toThrow('Cannot recalculate standings: missing required repositories');
|
||||
});
|
||||
|
||||
it('should throw error if league not found', async () => {
|
||||
mockLeagueRepository.findById.mockResolvedValue(null);
|
||||
await expect(repository.recalculate('nonexistent')).rejects.toThrow('League with ID nonexistent not found');
|
||||
});
|
||||
|
||||
it('should return empty array if no completed races', async () => {
|
||||
const mockLeague = {
|
||||
id: 'league1',
|
||||
settings: { pointsSystem: 'f1-2024', customPoints: null },
|
||||
};
|
||||
mockLeagueRepository.findById.mockResolvedValue(mockLeague);
|
||||
mockRaceRepository.findCompletedByLeagueId.mockResolvedValue([]);
|
||||
const result = await repository.recalculate('league1');
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should recalculate standings based on race results', async () => {
|
||||
const mockLeague = {
|
||||
id: 'league1',
|
||||
settings: { pointsSystem: 'f1-2024', customPoints: null },
|
||||
};
|
||||
const mockRace = { id: 'race1' };
|
||||
const mockResult1 = { driverId: 'driver1', position: 1 };
|
||||
const mockResult2 = { driverId: 'driver2', position: 2 };
|
||||
|
||||
mockLeagueRepository.findById.mockResolvedValue(mockLeague);
|
||||
mockRaceRepository.findCompletedByLeagueId.mockResolvedValue([mockRace]);
|
||||
mockResultRepository.findByRaceId.mockResolvedValue([mockResult1, mockResult2]);
|
||||
|
||||
const result = await repository.recalculate('league1');
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0]?.driverId.toString()).toBe('driver1');
|
||||
expect(result[0]?.points.toNumber()).toBe(25); // 1st place in f1-2024
|
||||
expect(result[1]?.driverId.toString()).toBe('driver2');
|
||||
expect(result[1]?.points.toNumber()).toBe(18); // 2nd place
|
||||
});
|
||||
|
||||
it('should use custom points if available', async () => {
|
||||
const customPoints = { 1: 100, 2: 80 };
|
||||
const mockLeague = {
|
||||
id: 'league1',
|
||||
settings: { pointsSystem: 'f1-2024', customPoints },
|
||||
};
|
||||
const mockRace = { id: 'race1' };
|
||||
const mockResult = { driverId: 'driver1', position: 1 };
|
||||
|
||||
mockLeagueRepository.findById.mockResolvedValue(mockLeague);
|
||||
mockRaceRepository.findCompletedByLeagueId.mockResolvedValue([mockRace]);
|
||||
mockResultRepository.findByRaceId.mockResolvedValue([mockResult]);
|
||||
|
||||
const result = await repository.recalculate('league1');
|
||||
expect(result[0]?.points.toNumber()).toBe(100);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user