/** * Integration Test: Sponsor League Detail Use Case Orchestration * * Tests the orchestration logic of sponsor league detail-related Use Cases: * - GetLeagueDetailUseCase: Retrieves detailed league information * - GetLeagueStatisticsUseCase: Retrieves league statistics * - GetSponsorshipSlotsUseCase: Retrieves sponsorship slots information * - GetLeagueScheduleUseCase: Retrieves league schedule * - Validates that Use Cases correctly interact with their Ports (Repositories, Event Publishers) * - Uses In-Memory adapters for fast, deterministic testing * * Focus: Business logic orchestration, NOT UI rendering */ import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest'; import { InMemorySponsorRepository } from '../../../adapters/sponsors/persistence/inmemory/InMemorySponsorRepository'; import { InMemoryLeagueRepository } from '../../../adapters/leagues/persistence/inmemory/InMemoryLeagueRepository'; import { InMemoryEventPublisher } from '../../../adapters/events/InMemoryEventPublisher'; import { GetLeagueDetailUseCase } from '../../../core/sponsors/use-cases/GetLeagueDetailUseCase'; import { GetLeagueStatisticsUseCase } from '../../../core/sponsors/use-cases/GetLeagueStatisticsUseCase'; import { GetSponsorshipSlotsUseCase } from '../../../core/sponsors/use-cases/GetSponsorshipSlotsUseCase'; import { GetLeagueScheduleUseCase } from '../../../core/sponsors/use-cases/GetLeagueScheduleUseCase'; import { GetLeagueDetailQuery } from '../../../core/sponsors/ports/GetLeagueDetailQuery'; import { GetLeagueStatisticsQuery } from '../../../core/sponsors/ports/GetLeagueStatisticsQuery'; import { GetSponsorshipSlotsQuery } from '../../../core/sponsors/ports/GetSponsorshipSlotsQuery'; import { GetLeagueScheduleQuery } from '../../../core/sponsors/ports/GetLeagueScheduleQuery'; describe('Sponsor League Detail Use Case Orchestration', () => { let sponsorRepository: InMemorySponsorRepository; let leagueRepository: InMemoryLeagueRepository; let eventPublisher: InMemoryEventPublisher; let getLeagueDetailUseCase: GetLeagueDetailUseCase; let getLeagueStatisticsUseCase: GetLeagueStatisticsUseCase; let getSponsorshipSlotsUseCase: GetSponsorshipSlotsUseCase; let getLeagueScheduleUseCase: GetLeagueScheduleUseCase; beforeAll(() => { // TODO: Initialize In-Memory repositories and event publisher // sponsorRepository = new InMemorySponsorRepository(); // leagueRepository = new InMemoryLeagueRepository(); // eventPublisher = new InMemoryEventPublisher(); // getLeagueDetailUseCase = new GetLeagueDetailUseCase({ // sponsorRepository, // leagueRepository, // eventPublisher, // }); // getLeagueStatisticsUseCase = new GetLeagueStatisticsUseCase({ // sponsorRepository, // leagueRepository, // eventPublisher, // }); // getSponsorshipSlotsUseCase = new GetSponsorshipSlotsUseCase({ // sponsorRepository, // leagueRepository, // eventPublisher, // }); // getLeagueScheduleUseCase = new GetLeagueScheduleUseCase({ // sponsorRepository, // leagueRepository, // eventPublisher, // }); }); beforeEach(() => { // TODO: Clear all In-Memory repositories before each test // sponsorRepository.clear(); // leagueRepository.clear(); // eventPublisher.clear(); }); describe('GetLeagueDetailUseCase - Success Path', () => { it('should retrieve detailed league information', async () => { // TODO: Implement test // Scenario: Sponsor views league detail // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has name "Premier League" // And: The league has description "Top tier racing league" // And: The league has logo URL // And: The league has category "Professional" // When: GetLeagueDetailUseCase.execute() is called with sponsor ID and league ID // Then: The result should show league name // And: The result should show league description // And: The result should show league logo // And: The result should show league category // And: EventPublisher should emit LeagueDetailAccessedEvent }); it('should retrieve league detail with minimal data', async () => { // TODO: Implement test // Scenario: League with minimal data // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has name "Test League" // When: GetLeagueDetailUseCase.execute() is called with sponsor ID and league ID // Then: The result should show league name // And: EventPublisher should emit LeagueDetailAccessedEvent }); }); describe('GetLeagueDetailUseCase - Error Handling', () => { it('should throw error when sponsor does not exist', async () => { // TODO: Implement test // Scenario: Non-existent sponsor // Given: No sponsor exists with the given ID // And: A league exists with ID "league-456" // When: GetLeagueDetailUseCase.execute() is called with non-existent sponsor ID // Then: Should throw SponsorNotFoundError // And: EventPublisher should NOT emit any events }); it('should throw error when league does not exist', async () => { // TODO: Implement test // Scenario: Non-existent league // Given: A sponsor exists with ID "sponsor-123" // And: No league exists with the given ID // When: GetLeagueDetailUseCase.execute() is called with non-existent league ID // Then: Should throw LeagueNotFoundError // And: EventPublisher should NOT emit any events }); it('should throw error when league ID is invalid', async () => { // TODO: Implement test // Scenario: Invalid league ID // Given: A sponsor exists with ID "sponsor-123" // And: An invalid league ID (e.g., empty string, null, undefined) // When: GetLeagueDetailUseCase.execute() is called with invalid league ID // Then: Should throw ValidationError // And: EventPublisher should NOT emit any events }); }); describe('GetLeagueStatisticsUseCase - Success Path', () => { it('should retrieve league statistics', async () => { // TODO: Implement test // Scenario: League with statistics // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has 500 total drivers // And: The league has 300 active drivers // And: The league has 100 total races // And: The league has average race duration of 45 minutes // And: The league has popularity score of 85 // When: GetLeagueStatisticsUseCase.execute() is called with sponsor ID and league ID // Then: The result should show total drivers: 500 // And: The result should show active drivers: 300 // And: The result should show total races: 100 // And: The result should show average race duration: 45 minutes // And: The result should show popularity score: 85 // And: EventPublisher should emit LeagueStatisticsAccessedEvent }); it('should retrieve statistics with zero values', async () => { // TODO: Implement test // Scenario: League with no statistics // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has no drivers // And: The league has no races // When: GetLeagueStatisticsUseCase.execute() is called with sponsor ID and league ID // Then: The result should show total drivers: 0 // And: The result should show active drivers: 0 // And: The result should show total races: 0 // And: The result should show average race duration: 0 // And: The result should show popularity score: 0 // And: EventPublisher should emit LeagueStatisticsAccessedEvent }); }); describe('GetLeagueStatisticsUseCase - Error Handling', () => { it('should throw error when sponsor does not exist', async () => { // TODO: Implement test // Scenario: Non-existent sponsor // Given: No sponsor exists with the given ID // And: A league exists with ID "league-456" // When: GetLeagueStatisticsUseCase.execute() is called with non-existent sponsor ID // Then: Should throw SponsorNotFoundError // And: EventPublisher should NOT emit any events }); it('should throw error when league does not exist', async () => { // TODO: Implement test // Scenario: Non-existent league // Given: A sponsor exists with ID "sponsor-123" // And: No league exists with the given ID // When: GetLeagueStatisticsUseCase.execute() is called with non-existent league ID // Then: Should throw LeagueNotFoundError // And: EventPublisher should NOT emit any events }); }); describe('GetSponsorshipSlotsUseCase - Success Path', () => { it('should retrieve sponsorship slots information', async () => { // TODO: Implement test // Scenario: League with sponsorship slots // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has main sponsor slot available // And: The league has 5 secondary sponsor slots available // And: The main slot has pricing of $10000 // And: The secondary slots have pricing of $2000 each // When: GetSponsorshipSlotsUseCase.execute() is called with sponsor ID and league ID // Then: The result should show main sponsor slot details // And: The result should show secondary sponsor slots details // And: The result should show available slots count // And: EventPublisher should emit SponsorshipSlotsAccessedEvent }); it('should retrieve slots with no available slots', async () => { // TODO: Implement test // Scenario: League with no available slots // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has no available sponsorship slots // When: GetSponsorshipSlotsUseCase.execute() is called with sponsor ID and league ID // Then: The result should show no available slots // And: EventPublisher should emit SponsorshipSlotsAccessedEvent }); }); describe('GetSponsorshipSlotsUseCase - Error Handling', () => { it('should throw error when sponsor does not exist', async () => { // TODO: Implement test // Scenario: Non-existent sponsor // Given: No sponsor exists with the given ID // And: A league exists with ID "league-456" // When: GetSponsorshipSlotsUseCase.execute() is called with non-existent sponsor ID // Then: Should throw SponsorNotFoundError // And: EventPublisher should NOT emit any events }); it('should throw error when league does not exist', async () => { // TODO: Implement test // Scenario: Non-existent league // Given: A sponsor exists with ID "sponsor-123" // And: No league exists with the given ID // When: GetSponsorshipSlotsUseCase.execute() is called with non-existent league ID // Then: Should throw LeagueNotFoundError // And: EventPublisher should NOT emit any events }); }); describe('GetLeagueScheduleUseCase - Success Path', () => { it('should retrieve league schedule', async () => { // TODO: Implement test // Scenario: League with schedule // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has 5 upcoming races // When: GetLeagueScheduleUseCase.execute() is called with sponsor ID and league ID // Then: The result should show upcoming races // And: Each race should show race date // And: Each race should show race location // And: Each race should show race type // And: EventPublisher should emit LeagueScheduleAccessedEvent }); it('should retrieve schedule with no upcoming races', async () => { // TODO: Implement test // Scenario: League with no upcoming races // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has no upcoming races // When: GetLeagueScheduleUseCase.execute() is called with sponsor ID and league ID // Then: The result should be empty // And: EventPublisher should emit LeagueScheduleAccessedEvent }); }); describe('GetLeagueScheduleUseCase - Error Handling', () => { it('should throw error when sponsor does not exist', async () => { // TODO: Implement test // Scenario: Non-existent sponsor // Given: No sponsor exists with the given ID // And: A league exists with ID "league-456" // When: GetLeagueScheduleUseCase.execute() is called with non-existent sponsor ID // Then: Should throw SponsorNotFoundError // And: EventPublisher should NOT emit any events }); it('should throw error when league does not exist', async () => { // TODO: Implement test // Scenario: Non-existent league // Given: A sponsor exists with ID "sponsor-123" // And: No league exists with the given ID // When: GetLeagueScheduleUseCase.execute() is called with non-existent league ID // Then: Should throw LeagueNotFoundError // And: EventPublisher should NOT emit any events }); }); describe('League Detail Data Orchestration', () => { it('should correctly retrieve league detail with all information', async () => { // TODO: Implement test // Scenario: League detail orchestration // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has complete information // When: GetLeagueDetailUseCase.execute() is called // Then: The result should contain all league information // And: Each field should be populated correctly // And: EventPublisher should emit LeagueDetailAccessedEvent }); it('should correctly aggregate league statistics', async () => { // TODO: Implement test // Scenario: League statistics aggregation // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has 500 total drivers // And: The league has 300 active drivers // And: The league has 100 total races // When: GetLeagueStatisticsUseCase.execute() is called // Then: Total drivers should be 500 // And: Active drivers should be 300 // And: Total races should be 100 // And: EventPublisher should emit LeagueStatisticsAccessedEvent }); it('should correctly retrieve sponsorship slots', async () => { // TODO: Implement test // Scenario: Sponsorship slots retrieval // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has main sponsor slot available // And: The league has 5 secondary sponsor slots available // When: GetSponsorshipSlotsUseCase.execute() is called // Then: Main sponsor slot should be available // And: Secondary sponsor slots count should be 5 // And: EventPublisher should emit SponsorshipSlotsAccessedEvent }); it('should correctly retrieve league schedule', async () => { // TODO: Implement test // Scenario: League schedule retrieval // Given: A sponsor exists with ID "sponsor-123" // And: A league exists with ID "league-456" // And: The league has 5 upcoming races // When: GetLeagueScheduleUseCase.execute() is called // Then: All 5 races should be returned // And: Each race should have correct details // And: EventPublisher should emit LeagueScheduleAccessedEvent }); }); });