135 lines
4.2 KiB
TypeScript
135 lines
4.2 KiB
TypeScript
/**
|
|
* Unit tests for CalculateTeamContributionUseCase
|
|
*/
|
|
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { CalculateTeamContributionUseCase } from './CalculateTeamContributionUseCase';
|
|
import { Driver } from '../../../racing/domain/entities/Driver';
|
|
import { Race } from '../../../racing/domain/entities/Race';
|
|
import { Result } from '../../../racing/domain/entities/result/Result';
|
|
import { Rating } from '../../domain/Rating';
|
|
import { DriverId } from '../../../racing/domain/entities/DriverId';
|
|
import { RaceId } from '../../../racing/domain/entities/RaceId';
|
|
|
|
const mockRatingRepository = {
|
|
findByDriverAndRace: vi.fn(),
|
|
save: vi.fn(),
|
|
};
|
|
|
|
const mockDriverRepository = {
|
|
findById: vi.fn(),
|
|
};
|
|
|
|
const mockRaceRepository = {
|
|
findById: vi.fn(),
|
|
};
|
|
|
|
const mockResultRepository = {
|
|
findByRaceId: vi.fn(),
|
|
};
|
|
|
|
describe('CalculateTeamContributionUseCase', () => {
|
|
let useCase: CalculateTeamContributionUseCase;
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
useCase = new CalculateTeamContributionUseCase({
|
|
ratingRepository: mockRatingRepository as unknown as RatingRepository,
|
|
driverRepository: mockDriverRepository as unknown as DriverRepository,
|
|
raceRepository: mockRaceRepository as unknown as RaceRepository,
|
|
resultRepository: mockResultRepository as unknown as ResultRepository,
|
|
});
|
|
});
|
|
|
|
describe('Scenario 8: Creates rating when missing', () => {
|
|
it('should create and save a new rating when none exists', async () => {
|
|
// Given
|
|
const driverId = 'driver-1';
|
|
const raceId = 'race-1';
|
|
const points = 25;
|
|
|
|
mockDriverRepository.findById.mockResolvedValue(Driver.create({
|
|
id: driverId,
|
|
iracingId: 'ir-1',
|
|
name: 'Driver 1',
|
|
country: 'US'
|
|
}));
|
|
mockRaceRepository.findById.mockResolvedValue(Race.create({
|
|
id: raceId,
|
|
leagueId: 'l-1',
|
|
scheduledAt: new Date(),
|
|
track: 'Track',
|
|
car: 'Car'
|
|
}));
|
|
mockResultRepository.findByRaceId.mockResolvedValue([
|
|
Result.create({
|
|
id: 'res-1',
|
|
raceId,
|
|
driverId,
|
|
position: 1,
|
|
points,
|
|
incidents: 0,
|
|
startPosition: 1,
|
|
fastestLap: 0
|
|
})
|
|
]);
|
|
mockRatingRepository.findByDriverAndRace.mockResolvedValue(null);
|
|
|
|
// When
|
|
const result = await useCase.execute({ driverId, raceId });
|
|
|
|
// Then
|
|
expect(mockRatingRepository.save).toHaveBeenCalled();
|
|
const savedRating = mockRatingRepository.save.mock.calls[0][0] as Rating;
|
|
expect(savedRating.components.teamContribution).toBe(100); // 25/25 * 100
|
|
expect(result.teamContribution).toBe(100);
|
|
});
|
|
});
|
|
|
|
describe('Scenario 9: Updates existing rating', () => {
|
|
it('should preserve other fields and only update teamContribution', async () => {
|
|
// Given
|
|
const driverId = 'driver-1';
|
|
const raceId = 'race-1';
|
|
const points = 12.5; // 50% contribution
|
|
|
|
const existingRating = Rating.create({
|
|
driverId: DriverId.create('driver-1'),
|
|
raceId: RaceId.create('race-1'),
|
|
rating: 1500,
|
|
components: {
|
|
resultsStrength: 80,
|
|
consistency: 70,
|
|
cleanDriving: 90,
|
|
racecraft: 75,
|
|
reliability: 85,
|
|
teamContribution: 10, // Old value
|
|
},
|
|
timestamp: new Date('2023-01-01')
|
|
});
|
|
|
|
mockDriverRepository.findById.mockResolvedValue({ id: driverId });
|
|
mockRaceRepository.findById.mockResolvedValue({ id: raceId });
|
|
mockResultRepository.findByRaceId.mockResolvedValue([
|
|
{ driverId: { toString: () => driverId }, points }
|
|
]);
|
|
mockRatingRepository.findByDriverAndRace.mockResolvedValue(existingRating);
|
|
|
|
// When
|
|
const result = await useCase.execute({ driverId, raceId });
|
|
|
|
// Then
|
|
expect(mockRatingRepository.save).toHaveBeenCalled();
|
|
const savedRating = mockRatingRepository.save.mock.calls[0][0] as Rating;
|
|
|
|
// Check preserved fields
|
|
expect(savedRating.rating).toBe(1500);
|
|
expect(savedRating.components.resultsStrength).toBe(80);
|
|
|
|
// Check updated field
|
|
expect(savedRating.components.teamContribution).toBe(50); // 12.5/25 * 100
|
|
expect(result.teamContribution).toBe(50);
|
|
});
|
|
});
|
|
});
|