/** * Integration Test: Sponsor Leagues Use Case Orchestration * * Tests the orchestration logic of sponsor leagues-related Use Cases: * - GetAvailableLeaguesUseCase: Retrieves available leagues for sponsorship * - GetLeagueStatisticsUseCase: Retrieves league statistics * - FilterLeaguesUseCase: Filters leagues by availability * - SearchLeaguesUseCase: Searches leagues by query * - 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 { GetAvailableLeaguesUseCase } from '../../../core/sponsors/use-cases/GetAvailableLeaguesUseCase'; import { GetLeagueStatisticsUseCase } from '../../../core/sponsors/use-cases/GetLeagueStatisticsUseCase'; import { FilterLeaguesUseCase } from '../../../core/sponsors/use-cases/FilterLeaguesUseCase'; import { SearchLeaguesUseCase } from '../../../core/sponsors/use-cases/SearchLeaguesUseCase'; import { GetAvailableLeaguesQuery } from '../../../core/sponsors/ports/GetAvailableLeaguesQuery'; import { GetLeagueStatisticsQuery } from '../../../core/sponsors/ports/GetLeagueStatisticsQuery'; import { FilterLeaguesCommand } from '../../../core/sponsors/ports/FilterLeaguesCommand'; import { SearchLeaguesCommand } from '../../../core/sponsors/ports/SearchLeaguesCommand'; describe('Sponsor Leagues Use Case Orchestration', () => { let sponsorRepository: InMemorySponsorRepository; let leagueRepository: InMemoryLeagueRepository; let eventPublisher: InMemoryEventPublisher; let getAvailableLeaguesUseCase: GetAvailableLeaguesUseCase; let getLeagueStatisticsUseCase: GetLeagueStatisticsUseCase; let filterLeaguesUseCase: FilterLeaguesUseCase; let searchLeaguesUseCase: SearchLeaguesUseCase; beforeAll(() => { // TODO: Initialize In-Memory repositories and event publisher // sponsorRepository = new InMemorySponsorRepository(); // leagueRepository = new InMemoryLeagueRepository(); // eventPublisher = new InMemoryEventPublisher(); // getAvailableLeaguesUseCase = new GetAvailableLeaguesUseCase({ // sponsorRepository, // leagueRepository, // eventPublisher, // }); // getLeagueStatisticsUseCase = new GetLeagueStatisticsUseCase({ // sponsorRepository, // leagueRepository, // eventPublisher, // }); // filterLeaguesUseCase = new FilterLeaguesUseCase({ // sponsorRepository, // leagueRepository, // eventPublisher, // }); // searchLeaguesUseCase = new SearchLeaguesUseCase({ // sponsorRepository, // leagueRepository, // eventPublisher, // }); }); beforeEach(() => { // TODO: Clear all In-Memory repositories before each test // sponsorRepository.clear(); // leagueRepository.clear(); // eventPublisher.clear(); }); describe('GetAvailableLeaguesUseCase - Success Path', () => { it('should retrieve available leagues for sponsorship', async () => { // TODO: Implement test // Scenario: Sponsor with available leagues // Given: A sponsor exists with ID "sponsor-123" // And: There are 5 leagues available for sponsorship // When: GetAvailableLeaguesUseCase.execute() is called with sponsor ID // Then: The result should contain all 5 leagues // And: Each league should display its details // And: EventPublisher should emit AvailableLeaguesAccessedEvent }); it('should retrieve leagues with minimal data', async () => { // TODO: Implement test // Scenario: Sponsor with minimal leagues // Given: A sponsor exists with ID "sponsor-123" // And: There is 1 league available for sponsorship // When: GetAvailableLeaguesUseCase.execute() is called with sponsor ID // Then: The result should contain the single league // And: EventPublisher should emit AvailableLeaguesAccessedEvent }); it('should retrieve leagues with empty result', async () => { // TODO: Implement test // Scenario: Sponsor with no available leagues // Given: A sponsor exists with ID "sponsor-123" // And: There are no leagues available for sponsorship // When: GetAvailableLeaguesUseCase.execute() is called with sponsor ID // Then: The result should be empty // And: EventPublisher should emit AvailableLeaguesAccessedEvent }); }); describe('GetAvailableLeaguesUseCase - 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 // When: GetAvailableLeaguesUseCase.execute() is called with non-existent sponsor ID // Then: Should throw SponsorNotFoundError // And: EventPublisher should NOT emit any events }); it('should throw error when sponsor ID is invalid', async () => { // TODO: Implement test // Scenario: Invalid sponsor ID // Given: An invalid sponsor ID (e.g., empty string, null, undefined) // When: GetAvailableLeaguesUseCase.execute() is called with invalid sponsor 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: Sponsor with league statistics // Given: A sponsor exists with ID "sponsor-123" // And: There are 10 leagues available // And: There are 3 main sponsor slots available // And: There are 15 secondary sponsor slots available // And: There are 500 total drivers // And: Average CPM is $50 // When: GetLeagueStatisticsUseCase.execute() is called with sponsor ID // Then: The result should show total leagues count: 10 // And: The result should show main sponsor slots available: 3 // And: The result should show secondary sponsor slots available: 15 // And: The result should show total drivers count: 500 // And: The result should show average CPM: $50 // And: EventPublisher should emit LeagueStatisticsAccessedEvent }); it('should retrieve statistics with zero values', async () => { // TODO: Implement test // Scenario: Sponsor with no leagues // Given: A sponsor exists with ID "sponsor-123" // And: There are no leagues available // When: GetLeagueStatisticsUseCase.execute() is called with sponsor ID // Then: The result should show all counts as 0 // And: The result should show average CPM as 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 // When: GetLeagueStatisticsUseCase.execute() is called with non-existent sponsor ID // Then: Should throw SponsorNotFoundError // And: EventPublisher should NOT emit any events }); }); describe('FilterLeaguesUseCase - Success Path', () => { it('should filter leagues by "All" availability', async () => { // TODO: Implement test // Scenario: Filter by All // Given: A sponsor exists with ID "sponsor-123" // And: There are 5 leagues (3 with main slot available, 2 with secondary slots available) // When: FilterLeaguesUseCase.execute() is called with availability "All" // Then: The result should contain all 5 leagues // And: EventPublisher should emit LeaguesFilteredEvent }); it('should filter leagues by "Main Slot Available" availability', async () => { // TODO: Implement test // Scenario: Filter by Main Slot Available // Given: A sponsor exists with ID "sponsor-123" // And: There are 5 leagues (3 with main slot available, 2 with secondary slots available) // When: FilterLeaguesUseCase.execute() is called with availability "Main Slot Available" // Then: The result should contain only 3 leagues with main slot available // And: EventPublisher should emit LeaguesFilteredEvent }); it('should filter leagues by "Secondary Slot Available" availability', async () => { // TODO: Implement test // Scenario: Filter by Secondary Slot Available // Given: A sponsor exists with ID "sponsor-123" // And: There are 5 leagues (3 with main slot available, 2 with secondary slots available) // When: FilterLeaguesUseCase.execute() is called with availability "Secondary Slot Available" // Then: The result should contain only 2 leagues with secondary slots available // And: EventPublisher should emit LeaguesFilteredEvent }); it('should return empty result when no leagues match filter', async () => { // TODO: Implement test // Scenario: Filter with no matches // Given: A sponsor exists with ID "sponsor-123" // And: There are 2 leagues with main slot available // When: FilterLeaguesUseCase.execute() is called with availability "Secondary Slot Available" // Then: The result should be empty // And: EventPublisher should emit LeaguesFilteredEvent }); }); describe('FilterLeaguesUseCase - 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 // When: FilterLeaguesUseCase.execute() is called with non-existent sponsor ID // Then: Should throw SponsorNotFoundError // And: EventPublisher should NOT emit any events }); it('should throw error with invalid availability', async () => { // TODO: Implement test // Scenario: Invalid availability // Given: A sponsor exists with ID "sponsor-123" // When: FilterLeaguesUseCase.execute() is called with invalid availability // Then: Should throw ValidationError // And: EventPublisher should NOT emit any events }); }); describe('SearchLeaguesUseCase - Success Path', () => { it('should search leagues by league name', async () => { // TODO: Implement test // Scenario: Search by league name // Given: A sponsor exists with ID "sponsor-123" // And: There are leagues named: "Premier League", "League A", "League B" // When: SearchLeaguesUseCase.execute() is called with query "Premier League" // Then: The result should contain only "Premier League" // And: EventPublisher should emit LeaguesSearchedEvent }); it('should search leagues by partial match', async () => { // TODO: Implement test // Scenario: Search by partial match // Given: A sponsor exists with ID "sponsor-123" // And: There are leagues named: "Premier League", "League A", "League B" // When: SearchLeaguesUseCase.execute() is called with query "League" // Then: The result should contain all three leagues // And: EventPublisher should emit LeaguesSearchedEvent }); it('should return empty result when no leagues match search', async () => { // TODO: Implement test // Scenario: Search with no matches // Given: A sponsor exists with ID "sponsor-123" // And: There are leagues named: "League A", "League B" // When: SearchLeaguesUseCase.execute() is called with query "NonExistent" // Then: The result should be empty // And: EventPublisher should emit LeaguesSearchedEvent }); it('should return all leagues when search query is empty', async () => { // TODO: Implement test // Scenario: Search with empty query // Given: A sponsor exists with ID "sponsor-123" // And: There are 3 leagues available // When: SearchLeaguesUseCase.execute() is called with empty query // Then: The result should contain all 3 leagues // And: EventPublisher should emit LeaguesSearchedEvent }); }); describe('SearchLeaguesUseCase - 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 // When: SearchLeaguesUseCase.execute() is called with non-existent sponsor ID // Then: Should throw SponsorNotFoundError // And: EventPublisher should NOT emit any events }); it('should throw error with invalid query', async () => { // TODO: Implement test // Scenario: Invalid query // Given: A sponsor exists with ID "sponsor-123" // When: SearchLeaguesUseCase.execute() is called with invalid query (e.g., null, undefined) // Then: Should throw ValidationError // And: EventPublisher should NOT emit any events }); }); describe('League Data Orchestration', () => { it('should correctly aggregate league statistics', async () => { // TODO: Implement test // Scenario: League statistics aggregation // Given: A sponsor exists with ID "sponsor-123" // And: There are 5 leagues with different slot availability // And: There are 3 main sponsor slots available // And: There are 15 secondary sponsor slots available // And: There are 500 total drivers // And: Average CPM is $50 // When: GetLeagueStatisticsUseCase.execute() is called // Then: Total leagues should be 5 // And: Main sponsor slots available should be 3 // And: Secondary sponsor slots available should be 15 // And: Total drivers count should be 500 // And: Average CPM should be $50 // And: EventPublisher should emit LeagueStatisticsAccessedEvent }); it('should correctly filter leagues by availability', async () => { // TODO: Implement test // Scenario: League availability filtering // Given: A sponsor exists with ID "sponsor-123" // And: There are leagues with different slot availability // When: FilterLeaguesUseCase.execute() is called with "Main Slot Available" // Then: Only leagues with main slot available should be returned // And: Each league should have correct availability // And: EventPublisher should emit LeaguesFilteredEvent }); it('should correctly search leagues by name', async () => { // TODO: Implement test // Scenario: League name search // Given: A sponsor exists with ID "sponsor-123" // And: There are leagues with different names // When: SearchLeaguesUseCase.execute() is called with league name // Then: Only leagues with matching names should be returned // And: Each league should have correct name // And: EventPublisher should emit LeaguesSearchedEvent }); }); });