import { describe, expect, it, vi, beforeEach } from 'vitest'; import { AppendRatingEventsUseCase, AppendRatingEventsInput } from './AppendRatingEventsUseCase'; import { IRatingEventRepository } from '../../domain/repositories/IRatingEventRepository'; import { IUserRatingRepository } from '../../domain/repositories/IUserRatingRepository'; import { RatingEvent } from '../../domain/entities/RatingEvent'; import { UserRating } from '../../domain/value-objects/UserRating'; import { RatingEventId } from '../../domain/value-objects/RatingEventId'; describe('AppendRatingEventsUseCase', () => { let mockEventRepo: Partial; let mockRatingRepo: Partial; beforeEach(() => { mockEventRepo = { save: vi.fn(), getAllByUserId: vi.fn().mockResolvedValue([]), }; mockRatingRepo = { save: vi.fn(), }; }); it('should be constructed with repositories', () => { const useCase = new AppendRatingEventsUseCase( mockEventRepo as IRatingEventRepository, mockRatingRepo as IUserRatingRepository, ); expect(useCase).toBeInstanceOf(AppendRatingEventsUseCase); }); it('should handle empty input (no events)', async () => { const useCase = new AppendRatingEventsUseCase( mockEventRepo as IRatingEventRepository, mockRatingRepo as IUserRatingRepository, ); const input: AppendRatingEventsInput = { userId: 'user-1', }; const result = await useCase.execute(input); expect(result.events).toEqual([]); expect(result.snapshotUpdated).toBe(false); expect(mockEventRepo.save).not.toHaveBeenCalled(); expect(mockRatingRepo.save).not.toHaveBeenCalled(); }); it('should create and save events from direct input', async () => { const useCase = new AppendRatingEventsUseCase( mockEventRepo as IRatingEventRepository, mockRatingRepo as IUserRatingRepository, ); const input: AppendRatingEventsInput = { userId: 'user-1', events: [ { userId: 'user-1', dimension: 'driving', delta: 5, sourceType: 'race', sourceId: 'race-1', reasonCode: 'TEST', reasonSummary: 'Test event', }, ], }; const result = await useCase.execute(input); expect(result.events).toHaveLength(1); expect(result.snapshotUpdated).toBe(true); expect(mockEventRepo.save).toHaveBeenCalledTimes(1); expect(mockRatingRepo.save).toHaveBeenCalledTimes(1); }); it('should create events from race results using factory', async () => { const useCase = new AppendRatingEventsUseCase( mockEventRepo as IRatingEventRepository, mockRatingRepo as IUserRatingRepository, ); const input: AppendRatingEventsInput = { userId: 'user-1', raceId: 'race-123', raceResults: [ { position: 3, totalDrivers: 10, startPosition: 5, incidents: 1, fieldStrength: 1500, status: 'finished', }, ], }; const result = await useCase.execute(input); expect(result.events.length).toBeGreaterThan(0); expect(result.snapshotUpdated).toBe(true); expect(mockEventRepo.save).toHaveBeenCalled(); expect(mockRatingRepo.save).toHaveBeenCalled(); }); it('should handle multiple race results', async () => { const useCase = new AppendRatingEventsUseCase( mockEventRepo as IRatingEventRepository, mockRatingRepo as IUserRatingRepository, ); const input: AppendRatingEventsInput = { userId: 'user-1', raceId: 'race-123', raceResults: [ { position: 3, totalDrivers: 10, startPosition: 5, incidents: 1, fieldStrength: 1500, status: 'finished' }, { position: 1, totalDrivers: 10, startPosition: 2, incidents: 0, fieldStrength: 1500, status: 'finished' }, ], }; const result = await useCase.execute(input); expect(result.events.length).toBeGreaterThan(2); // Multiple events per race expect(result.snapshotUpdated).toBe(true); }); it('should handle DNF status', async () => { const useCase = new AppendRatingEventsUseCase( mockEventRepo as IRatingEventRepository, mockRatingRepo as IUserRatingRepository, ); const input: AppendRatingEventsInput = { userId: 'user-1', raceId: 'race-123', raceResults: [ { position: 5, totalDrivers: 10, startPosition: 3, incidents: 2, fieldStrength: 1500, status: 'dnf' }, ], }; const result = await useCase.execute(input); expect(result.events.length).toBeGreaterThan(0); expect(result.snapshotUpdated).toBe(true); expect(mockEventRepo.save).toHaveBeenCalled(); }); it('should not update snapshot if no events were saved', async () => { // Mock save to throw or do nothing const saveMock = vi.fn().mockResolvedValue({}); const getAllMock = vi.fn().mockResolvedValue([]); mockEventRepo = { save: saveMock, getAllByUserId: getAllMock, }; const useCase = new AppendRatingEventsUseCase( mockEventRepo as IRatingEventRepository, mockRatingRepo as IUserRatingRepository, ); const input: AppendRatingEventsInput = { userId: 'user-1', events: [], // Empty }; const result = await useCase.execute(input); expect(result.events).toEqual([]); expect(result.snapshotUpdated).toBe(false); expect(mockRatingRepo.save).not.toHaveBeenCalled(); }); });