import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest'; import { GetSeasonSponsorshipsUseCase, type GetSeasonSponsorshipsInput, type GetSeasonSponsorshipsResult, type GetSeasonSponsorshipsErrorCode, } from './GetSeasonSponsorshipsUseCase'; import type { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository'; import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository'; import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository'; import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository'; import type { IRaceRepository } from '../../domain/repositories/IRaceRepository'; import { Season } from '../../domain/entities/season/Season'; import { League } from '../../domain/entities/League'; import { SeasonSponsorship } from '../../domain/entities/season/SeasonSponsorship'; import { Money } from '../../domain/value-objects/Money'; import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; describe('GetSeasonSponsorshipsUseCase', () => { let seasonSponsorshipRepository: { findBySeasonId: Mock; }; let seasonRepository: { findById: Mock; }; let leagueRepository: { findById: Mock; }; let leagueMembershipRepository: { getLeagueMembers: Mock; }; let raceRepository: { findByLeagueId: Mock; }; let output: UseCaseOutputPort & { present: Mock }; let useCase: GetSeasonSponsorshipsUseCase; beforeEach(() => { seasonSponsorshipRepository = { findBySeasonId: vi.fn(), }; seasonRepository = { findById: vi.fn(), }; leagueRepository = { findById: vi.fn(), }; leagueMembershipRepository = { getLeagueMembers: vi.fn(), }; raceRepository = { findByLeagueId: vi.fn(), }; output = { present: vi.fn(), } as unknown as UseCaseOutputPort & { present: Mock }; useCase = new GetSeasonSponsorshipsUseCase( seasonSponsorshipRepository as unknown as ISeasonSponsorshipRepository, seasonRepository as unknown as ISeasonRepository, leagueRepository as unknown as ILeagueRepository, leagueMembershipRepository as unknown as ILeagueMembershipRepository, raceRepository as unknown as IRaceRepository, output, ); }); it('returns SEASON_NOT_FOUND when season does not exist', async () => { const input: GetSeasonSponsorshipsInput = { seasonId: 'season-1' }; seasonRepository.findById.mockResolvedValue(null); const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const err = result.unwrapErr() as ApplicationErrorCode< GetSeasonSponsorshipsErrorCode, { message: string } >; expect(err.code).toBe('SEASON_NOT_FOUND'); expect(err.details.message).toBe('Season not found'); expect(output.present).not.toHaveBeenCalled(); }); it('returns LEAGUE_NOT_FOUND when league for season does not exist', async () => { const input: GetSeasonSponsorshipsInput = { seasonId: 'season-1' }; const season = Season.create({ id: 'season-1', leagueId: 'league-1', gameId: 'game-1', name: 'Season 1', status: 'active', }); seasonRepository.findById.mockResolvedValue(season); leagueRepository.findById.mockResolvedValue(null); const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const err = result.unwrapErr() as ApplicationErrorCode< GetSeasonSponsorshipsErrorCode, { message: string } >; expect(err.code).toBe('LEAGUE_NOT_FOUND'); expect(err.details.message).toBe('League not found for season'); expect(output.present).not.toHaveBeenCalled(); }); it('presents sponsorship details with computed metrics', async () => { const input: GetSeasonSponsorshipsInput = { seasonId: 'season-1' }; const season = Season.create({ id: 'season-1', leagueId: 'league-1', gameId: 'game-1', name: 'Season 1', status: 'active', startDate: new Date('2025-01-01T00:00:00.000Z'), endDate: new Date('2025-02-01T00:00:00.000Z'), }); const league = League.create({ id: 'league-1', name: 'Test League', description: 'Test', ownerId: 'owner-1', }); const sponsorship = SeasonSponsorship.create({ id: 'sponsorship-1', sponsorId: 'sponsor-1', seasonId: 'season-1', tier: 'main', pricing: Money.create(1000, 'USD'), activatedAt: new Date('2025-01-02T00:00:00.000Z'), createdAt: new Date('2025-01-01T00:00:00.000Z'), }); seasonRepository.findById.mockResolvedValue(season); leagueRepository.findById.mockResolvedValue(league); seasonSponsorshipRepository.findBySeasonId.mockResolvedValue([sponsorship]); leagueMembershipRepository.getLeagueMembers.mockResolvedValue([ { driverId: 'driver-1' }, { driverId: 'driver-2' }, { driverId: 'driver-3' }, ]); raceRepository.findByLeagueId.mockResolvedValue([ { id: 'race-1', status: { isCompleted: () => true } }, { id: 'race-2', status: { isCompleted: () => true } }, { id: 'race-3', status: { isCompleted: () => false } }, ]); const result = await useCase.execute(input); expect(result.isOk()).toBe(true); expect(output.present).toHaveBeenCalledTimes(1); const presented = (output.present as Mock).mock.calls[0]?.[0] as GetSeasonSponsorshipsResult; expect(presented.seasonId).toBe('season-1'); expect(presented.sponsorships).toHaveLength(1); const detail = presented.sponsorships[0]!; expect(detail.id).toBe('sponsorship-1'); expect(detail.leagueId).toBe('league-1'); expect(detail.leagueName).toBe('Test League'); expect(detail.seasonId).toBe('season-1'); expect(detail.seasonName).toBe('Season 1'); expect(detail.seasonStartDate).toEqual(new Date('2025-01-01T00:00:00.000Z')); expect(detail.seasonEndDate).toEqual(new Date('2025-02-01T00:00:00.000Z')); expect(detail.activatedAt).toEqual(new Date('2025-01-02T00:00:00.000Z')); expect(detail.metrics.drivers).toBe(3); expect(detail.metrics.races).toBe(3); expect(detail.metrics.completedRaces).toBe(2); expect(detail.metrics.impressions).toBe(2 * 3 * 100); expect(detail.pricing).toEqual({ amount: 1000, currency: 'USD' }); expect(detail.platformFee).toEqual({ amount: 100, currency: 'USD' }); expect(detail.netAmount).toEqual({ amount: 900, currency: 'USD' }); }); it('returns REPOSITORY_ERROR when repository throws', async () => { const input: GetSeasonSponsorshipsInput = { seasonId: 'season-1' }; seasonRepository.findById.mockRejectedValue(new Error('DB error')); const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const err = result.unwrapErr() as ApplicationErrorCode< GetSeasonSponsorshipsErrorCode, { message: string } >; expect(err.code).toBe('REPOSITORY_ERROR'); expect(err.details.message).toBe('DB error'); expect(output.present).not.toHaveBeenCalled(); }); });