Files
gridpilot.gg/core/racing/application/use-cases/CloseRaceEventStewardingUseCase.test.ts
2025-12-21 00:43:42 +01:00

124 lines
4.7 KiB
TypeScript

import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import { CloseRaceEventStewardingUseCase, type CloseRaceEventStewardingResult } from './CloseRaceEventStewardingUseCase';
import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository';
import type { IRaceRegistrationRepository } from '../../domain/repositories/IRaceRegistrationRepository';
import type { IPenaltyRepository } from '../../domain/repositories/IPenaltyRepository';
import type { DomainEventPublisher } from '@/shared/domain/DomainEvent';
import type { Logger } from '@core/shared/application';
import { RaceEvent } from '../../domain/entities/RaceEvent';
import { Session } from '../../domain/entities/Session';
import { SessionType } from '../../domain/value-objects/SessionType';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
describe('CloseRaceEventStewardingUseCase', () => {
let useCase: CloseRaceEventStewardingUseCase;
let raceEventRepository: {
findAwaitingStewardingClose: Mock;
update: Mock;
};
let raceRegistrationRepository: {
getRegisteredDrivers: Mock;
};
let penaltyRepository: {
findByRaceId: Mock;
};
let domainEventPublisher: {
publish: Mock;
};
let logger: {
error: Mock;
};
let output: UseCaseOutputPort<CloseRaceEventStewardingResult> & { present: Mock };
beforeEach(() => {
raceEventRepository = {
findAwaitingStewardingClose: vi.fn(),
update: vi.fn(),
};
raceRegistrationRepository = {
getRegisteredDrivers: vi.fn(),
};
penaltyRepository = {
findByRaceId: vi.fn(),
};
domainEventPublisher = {
publish: vi.fn(),
};
logger = {
error: vi.fn(),
};
output = { present: vi.fn() } as unknown as UseCaseOutputPort<CloseRaceEventStewardingResult> & { present: Mock };
useCase = new CloseRaceEventStewardingUseCase(
logger as unknown as Logger,
raceEventRepository as unknown as IRaceEventRepository,
raceRegistrationRepository as unknown as IRaceRegistrationRepository,
penaltyRepository as unknown as IPenaltyRepository,
domainEventPublisher as unknown as DomainEventPublisher,
output,
);
});
it('should close stewarding for expired events successfully', async () => {
const raceEvent = RaceEvent.create({
id: 'event-1',
seasonId: 'season-1',
leagueId: 'league-1',
name: 'Test Event',
sessions: [
Session.create({
id: 'session-1',
raceEventId: 'event-1',
sessionType: SessionType.main(),
scheduledAt: new Date(),
track: 'Test Track',
car: 'Test Car',
status: 'completed',
}),
],
status: 'awaiting_stewarding',
stewardingClosesAt: new Date(Date.now() - 1000), // expired
});
raceEventRepository.findAwaitingStewardingClose.mockResolvedValue([raceEvent]);
raceRegistrationRepository.getRegisteredDrivers.mockResolvedValue(['driver-1', 'driver-2']);
penaltyRepository.findByRaceId.mockResolvedValue([]);
domainEventPublisher.publish.mockResolvedValue(undefined);
const result = await useCase.execute({ raceId: 'event-1', closedById: 'admin-1' });
expect(result.isOk()).toBe(true);
expect(result.unwrap()).toBeUndefined();
expect(raceEventRepository.findAwaitingStewardingClose).toHaveBeenCalled();
expect(raceEventRepository.update).toHaveBeenCalledWith(
expect.objectContaining({ id: 'event-1', status: 'closed' })
);
expect(domainEventPublisher.publish).toHaveBeenCalled();
expect(output.present).toHaveBeenCalledTimes(1);
expect(output.present).toHaveBeenCalledWith({
race: expect.objectContaining({ id: 'event-1', status: 'closed' })
});
});
it('should handle no expired events', async () => {
raceEventRepository.findAwaitingStewardingClose.mockResolvedValue([]);
const result = await useCase.execute({ raceId: 'event-1', closedById: 'admin-1' });
expect(result.isOk()).toBe(true);
expect(result.unwrap()).toBeUndefined();
expect(raceEventRepository.update).not.toHaveBeenCalled();
expect(domainEventPublisher.publish).not.toHaveBeenCalled();
expect(output.present).not.toHaveBeenCalled();
});
it('should return error when repository throws', async () => {
raceEventRepository.findAwaitingStewardingClose.mockRejectedValue(new Error('DB error'));
const result = await useCase.execute({ raceId: 'event-1', closedById: 'admin-1' });
expect(result.isErr()).toBe(true);
expect(result.unwrapErr().code).toBe('REPOSITORY_ERROR');
expect(result.unwrapErr().details?.message).toContain('DB error');
expect(output.present).not.toHaveBeenCalled();
});
});