core tests
This commit is contained in:
57
core/racing/application/use-cases/DriverStatsUseCase.test.ts
Normal file
57
core/racing/application/use-cases/DriverStatsUseCase.test.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { DriverStatsUseCase, type DriverStats } from './DriverStatsUseCase';
|
||||
import type { ResultRepository } from '../../domain/repositories/ResultRepository';
|
||||
import type { StandingRepository } from '../../domain/repositories/StandingRepository';
|
||||
import type { DriverStatsRepository } from '../../domain/repositories/DriverStatsRepository';
|
||||
import type { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
describe('DriverStatsUseCase', () => {
|
||||
const mockResultRepository = {} as ResultRepository;
|
||||
const mockStandingRepository = {} as StandingRepository;
|
||||
const mockDriverStatsRepository = {
|
||||
getDriverStats: vi.fn(),
|
||||
} as unknown as DriverStatsRepository;
|
||||
const mockLogger = {
|
||||
debug: vi.fn(),
|
||||
} as unknown as Logger;
|
||||
|
||||
const useCase = new DriverStatsUseCase(
|
||||
mockResultRepository,
|
||||
mockStandingRepository,
|
||||
mockDriverStatsRepository,
|
||||
mockLogger
|
||||
);
|
||||
|
||||
it('should return driver stats when found', async () => {
|
||||
const mockStats: DriverStats = {
|
||||
rating: 1500,
|
||||
safetyRating: 4.5,
|
||||
sportsmanshipRating: 4.8,
|
||||
totalRaces: 10,
|
||||
wins: 2,
|
||||
podiums: 5,
|
||||
dnfs: 0,
|
||||
avgFinish: 3.5,
|
||||
bestFinish: 1,
|
||||
worstFinish: 8,
|
||||
consistency: 0.9,
|
||||
experienceLevel: 'Intermediate',
|
||||
overallRank: 42,
|
||||
};
|
||||
vi.mocked(mockDriverStatsRepository.getDriverStats).mockResolvedValue(mockStats);
|
||||
|
||||
const result = await useCase.getDriverStats('driver-1');
|
||||
|
||||
expect(result).toEqual(mockStats);
|
||||
expect(mockLogger.debug).toHaveBeenCalledWith('Getting stats for driver driver-1');
|
||||
expect(mockDriverStatsRepository.getDriverStats).toHaveBeenCalledWith('driver-1');
|
||||
});
|
||||
|
||||
it('should return null when stats are not found', async () => {
|
||||
vi.mocked(mockDriverStatsRepository.getDriverStats).mockResolvedValue(null);
|
||||
|
||||
const result = await useCase.getDriverStats('non-existent');
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
43
core/racing/application/use-cases/GetDriverUseCase.test.ts
Normal file
43
core/racing/application/use-cases/GetDriverUseCase.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { GetDriverUseCase } from './GetDriverUseCase';
|
||||
import { Result } from '@core/shared/domain/Result';
|
||||
import type { DriverRepository } from '../../domain/repositories/DriverRepository';
|
||||
import type { Driver } from '../../domain/entities/Driver';
|
||||
|
||||
describe('GetDriverUseCase', () => {
|
||||
const mockDriverRepository = {
|
||||
findById: vi.fn(),
|
||||
} as unknown as DriverRepository;
|
||||
|
||||
const useCase = new GetDriverUseCase(mockDriverRepository);
|
||||
|
||||
it('should return a driver when found', async () => {
|
||||
const mockDriver = { id: 'driver-1', name: 'John Doe' } as unknown as Driver;
|
||||
vi.mocked(mockDriverRepository.findById).mockResolvedValue(mockDriver);
|
||||
|
||||
const result = await useCase.execute({ driverId: 'driver-1' });
|
||||
|
||||
expect(result.isOk()).toBe(true);
|
||||
expect(result.unwrap()).toBe(mockDriver);
|
||||
expect(mockDriverRepository.findById).toHaveBeenCalledWith('driver-1');
|
||||
});
|
||||
|
||||
it('should return null when driver is not found', async () => {
|
||||
vi.mocked(mockDriverRepository.findById).mockResolvedValue(null);
|
||||
|
||||
const result = await useCase.execute({ driverId: 'non-existent' });
|
||||
|
||||
expect(result.isOk()).toBe(true);
|
||||
expect(result.unwrap()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return an error when repository throws', async () => {
|
||||
const error = new Error('Repository error');
|
||||
vi.mocked(mockDriverRepository.findById).mockRejectedValue(error);
|
||||
|
||||
const result = await useCase.execute({ driverId: 'driver-1' });
|
||||
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.error).toBe(error);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { GetTeamsLeaderboardUseCase } from './GetTeamsLeaderboardUseCase';
|
||||
import { Result } from '@core/shared/domain/Result';
|
||||
import type { TeamRepository } from '../../domain/repositories/TeamRepository';
|
||||
import type { TeamMembershipRepository } from '../../domain/repositories/TeamMembershipRepository';
|
||||
import type { Logger } from '@core/shared/domain/Logger';
|
||||
import type { Team } from '../../domain/entities/Team';
|
||||
|
||||
describe('GetTeamsLeaderboardUseCase', () => {
|
||||
const mockTeamRepository = {
|
||||
findAll: vi.fn(),
|
||||
} as unknown as TeamRepository;
|
||||
|
||||
const mockTeamMembershipRepository = {
|
||||
getTeamMembers: vi.fn(),
|
||||
} as unknown as TeamMembershipRepository;
|
||||
|
||||
const mockGetDriverStats = vi.fn();
|
||||
|
||||
const mockLogger = {
|
||||
error: vi.fn(),
|
||||
} as unknown as Logger;
|
||||
|
||||
const useCase = new GetTeamsLeaderboardUseCase(
|
||||
mockTeamRepository,
|
||||
mockTeamMembershipRepository,
|
||||
mockGetDriverStats,
|
||||
mockLogger
|
||||
);
|
||||
|
||||
it('should return teams leaderboard with calculated stats', async () => {
|
||||
const mockTeam1 = { id: 'team-1', name: 'Team 1' } as unknown as Team;
|
||||
const mockTeam2 = { id: 'team-2', name: 'Team 2' } as unknown as Team;
|
||||
vi.mocked(mockTeamRepository.findAll).mockResolvedValue([mockTeam1, mockTeam2]);
|
||||
|
||||
vi.mocked(mockTeamMembershipRepository.getTeamMembers).mockImplementation(async (teamId) => {
|
||||
if (teamId === 'team-1') return [{ driverId: 'driver-1' }, { driverId: 'driver-2' }] as any;
|
||||
if (teamId === 'team-2') return [{ driverId: 'driver-3' }] as any;
|
||||
return [];
|
||||
});
|
||||
|
||||
mockGetDriverStats.mockImplementation((driverId) => {
|
||||
if (driverId === 'driver-1') return { rating: 1000, wins: 1, totalRaces: 5 };
|
||||
if (driverId === 'driver-2') return { rating: 2000, wins: 2, totalRaces: 10 };
|
||||
if (driverId === 'driver-3') return { rating: 1500, wins: 0, totalRaces: 2 };
|
||||
return null;
|
||||
});
|
||||
|
||||
const result = await useCase.execute({ leagueId: 'league-1' });
|
||||
|
||||
expect(result.isOk()).toBe(true);
|
||||
const data = result.unwrap();
|
||||
expect(data.items).toHaveLength(2);
|
||||
|
||||
const item1 = data.items.find(i => i.team.id === 'team-1');
|
||||
expect(item1?.rating).toBe(1500); // (1000 + 2000) / 2
|
||||
expect(item1?.totalWins).toBe(3);
|
||||
expect(item1?.totalRaces).toBe(15);
|
||||
|
||||
const item2 = data.items.find(i => i.team.id === 'team-2');
|
||||
expect(item2?.rating).toBe(1500);
|
||||
expect(item2?.totalWins).toBe(0);
|
||||
expect(item2?.totalRaces).toBe(2);
|
||||
|
||||
expect(data.topItems).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should handle teams with no members', async () => {
|
||||
const mockTeam = { id: 'team-empty', name: 'Empty Team' } as unknown as Team;
|
||||
vi.mocked(mockTeamRepository.findAll).mockResolvedValue([mockTeam]);
|
||||
vi.mocked(mockTeamMembershipRepository.getTeamMembers).mockResolvedValue([]);
|
||||
|
||||
const result = await useCase.execute({ leagueId: 'league-1' });
|
||||
|
||||
expect(result.isOk()).toBe(true);
|
||||
const data = result.unwrap();
|
||||
expect(data.items[0].rating).toBeNull();
|
||||
expect(data.items[0].performanceLevel).toBe('beginner');
|
||||
});
|
||||
|
||||
it('should return error when repository fails', async () => {
|
||||
vi.mocked(mockTeamRepository.findAll).mockRejectedValue(new Error('DB Error'));
|
||||
|
||||
const result = await useCase.execute({ leagueId: 'league-1' });
|
||||
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.error.code).toBe('REPOSITORY_ERROR');
|
||||
expect(mockLogger.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
59
core/racing/application/use-cases/RankingUseCase.test.ts
Normal file
59
core/racing/application/use-cases/RankingUseCase.test.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { RankingUseCase, type DriverRanking } from './RankingUseCase';
|
||||
import type { StandingRepository } from '../../domain/repositories/StandingRepository';
|
||||
import type { DriverRepository } from '../../domain/repositories/DriverRepository';
|
||||
import type { DriverStatsRepository } from '../../domain/repositories/DriverStatsRepository';
|
||||
import type { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
describe('RankingUseCase', () => {
|
||||
const mockStandingRepository = {} as StandingRepository;
|
||||
const mockDriverRepository = {} as DriverRepository;
|
||||
const mockDriverStatsRepository = {
|
||||
getAllStats: vi.fn(),
|
||||
} as unknown as DriverStatsRepository;
|
||||
const mockLogger = {
|
||||
debug: vi.fn(),
|
||||
} as unknown as Logger;
|
||||
|
||||
const useCase = new RankingUseCase(
|
||||
mockStandingRepository,
|
||||
mockDriverRepository,
|
||||
mockDriverStatsRepository,
|
||||
mockLogger
|
||||
);
|
||||
|
||||
it('should return all driver rankings', async () => {
|
||||
const mockStatsMap = new Map([
|
||||
['driver-1', { rating: 1500, wins: 2, totalRaces: 10, overallRank: 1 }],
|
||||
['driver-2', { rating: 1200, wins: 0, totalRaces: 5, overallRank: 2 }],
|
||||
]);
|
||||
vi.mocked(mockDriverStatsRepository.getAllStats).mockResolvedValue(mockStatsMap as any);
|
||||
|
||||
const result = await useCase.getAllDriverRankings();
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result).toContainEqual({
|
||||
driverId: 'driver-1',
|
||||
rating: 1500,
|
||||
wins: 2,
|
||||
totalRaces: 10,
|
||||
overallRank: 1,
|
||||
});
|
||||
expect(result).toContainEqual({
|
||||
driverId: 'driver-2',
|
||||
rating: 1200,
|
||||
wins: 0,
|
||||
totalRaces: 5,
|
||||
overallRank: 2,
|
||||
});
|
||||
expect(mockLogger.debug).toHaveBeenCalledWith('Getting all driver rankings');
|
||||
});
|
||||
|
||||
it('should return empty array when no stats exist', async () => {
|
||||
vi.mocked(mockDriverStatsRepository.getAllStats).mockResolvedValue(new Map());
|
||||
|
||||
const result = await useCase.getAllDriverRankings();
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
44
core/racing/application/utils/RaceResultGenerator.test.ts
Normal file
44
core/racing/application/utils/RaceResultGenerator.test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { RaceResultGenerator } from './RaceResultGenerator';
|
||||
|
||||
describe('RaceResultGenerator', () => {
|
||||
it('should generate results for all drivers', () => {
|
||||
const raceId = 'race-1';
|
||||
const driverIds = ['d1', 'd2', 'd3'];
|
||||
const driverRatings = new Map([
|
||||
['d1', 2000],
|
||||
['d2', 1500],
|
||||
['d3', 1000],
|
||||
]);
|
||||
|
||||
const results = RaceResultGenerator.generateRaceResults(raceId, driverIds, driverRatings);
|
||||
|
||||
expect(results).toHaveLength(3);
|
||||
const resultDriverIds = results.map(r => r.driverId.toString());
|
||||
expect(resultDriverIds).toContain('d1');
|
||||
expect(resultDriverIds).toContain('d2');
|
||||
expect(resultDriverIds).toContain('d3');
|
||||
|
||||
results.forEach(r => {
|
||||
expect(r.raceId.toString()).toBe(raceId);
|
||||
expect(r.position.toNumber()).toBeGreaterThan(0);
|
||||
expect(r.position.toNumber()).toBeLessThanOrEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('should provide incident descriptions', () => {
|
||||
expect(RaceResultGenerator.getIncidentDescription(0)).toBe('Clean race');
|
||||
expect(RaceResultGenerator.getIncidentDescription(1)).toBe('Track limits violation');
|
||||
expect(RaceResultGenerator.getIncidentDescription(2)).toBe('Contact with another car');
|
||||
expect(RaceResultGenerator.getIncidentDescription(3)).toBe('Off-track incident');
|
||||
expect(RaceResultGenerator.getIncidentDescription(4)).toBe('Collision requiring safety car');
|
||||
expect(RaceResultGenerator.getIncidentDescription(5)).toBe('5 incidents');
|
||||
});
|
||||
|
||||
it('should calculate incident penalty points', () => {
|
||||
expect(RaceResultGenerator.getIncidentPenaltyPoints(0)).toBe(0);
|
||||
expect(RaceResultGenerator.getIncidentPenaltyPoints(1)).toBe(0);
|
||||
expect(RaceResultGenerator.getIncidentPenaltyPoints(2)).toBe(2);
|
||||
expect(RaceResultGenerator.getIncidentPenaltyPoints(3)).toBe(4);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { RaceResultGeneratorWithIncidents } from './RaceResultGeneratorWithIncidents';
|
||||
import { RaceIncidents } from '../../domain/value-objects/RaceIncidents';
|
||||
|
||||
describe('RaceResultGeneratorWithIncidents', () => {
|
||||
it('should generate results for all drivers', () => {
|
||||
const raceId = 'race-1';
|
||||
const driverIds = ['d1', 'd2'];
|
||||
const driverRatings = new Map([
|
||||
['d1', 2000],
|
||||
['d2', 1500],
|
||||
]);
|
||||
|
||||
const results = RaceResultGeneratorWithIncidents.generateRaceResults(raceId, driverIds, driverRatings);
|
||||
|
||||
expect(results).toHaveLength(2);
|
||||
results.forEach(r => {
|
||||
expect(r.raceId.toString()).toBe(raceId);
|
||||
expect(r.incidents).toBeInstanceOf(RaceIncidents);
|
||||
});
|
||||
});
|
||||
|
||||
it('should calculate incident penalty points', () => {
|
||||
const incidents = new RaceIncidents([
|
||||
{ type: 'contact', lap: 1, description: 'desc', penaltyPoints: 2 },
|
||||
{ type: 'unsafe_rejoin', lap: 5, description: 'desc', penaltyPoints: 3 },
|
||||
]);
|
||||
|
||||
expect(RaceResultGeneratorWithIncidents.getIncidentPenaltyPoints(incidents)).toBe(5);
|
||||
});
|
||||
|
||||
it('should get incident description', () => {
|
||||
const incidents = new RaceIncidents([
|
||||
{ type: 'contact', lap: 1, description: 'desc', penaltyPoints: 2 },
|
||||
]);
|
||||
|
||||
const description = RaceResultGeneratorWithIncidents.getIncidentDescription(incidents);
|
||||
expect(description).toContain('1 incidents');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user