346 lines
16 KiB
TypeScript
346 lines
16 KiB
TypeScript
/**
|
|
* 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
|
|
});
|
|
});
|
|
});
|