/** * Integration Test: Sponsor Campaigns Use Case Orchestration * * Tests the orchestration logic of sponsor campaigns-related Use Cases: * - GetSponsorCampaignsUseCase: Retrieves sponsor's campaigns * - GetCampaignStatisticsUseCase: Retrieves campaign statistics * - FilterCampaignsUseCase: Filters campaigns by status * - SearchCampaignsUseCase: Searches campaigns 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 { InMemoryCampaignRepository } from '../../../adapters/sponsors/persistence/inmemory/InMemoryCampaignRepository'; import { InMemoryEventPublisher } from '../../../adapters/events/InMemoryEventPublisher'; import { GetSponsorCampaignsUseCase } from '../../../core/sponsors/use-cases/GetSponsorCampaignsUseCase'; import { GetCampaignStatisticsUseCase } from '../../../core/sponsors/use-cases/GetCampaignStatisticsUseCase'; import { FilterCampaignsUseCase } from '../../../core/sponsors/use-cases/FilterCampaignsUseCase'; import { SearchCampaignsUseCase } from '../../../core/sponsors/use-cases/SearchCampaignsUseCase'; import { GetSponsorCampaignsQuery } from '../../../core/sponsors/ports/GetSponsorCampaignsQuery'; import { GetCampaignStatisticsQuery } from '../../../core/sponsors/ports/GetCampaignStatisticsQuery'; import { FilterCampaignsCommand } from '../../../core/sponsors/ports/FilterCampaignsCommand'; import { SearchCampaignsCommand } from '../../../core/sponsors/ports/SearchCampaignsCommand'; describe('Sponsor Campaigns Use Case Orchestration', () => { let sponsorRepository: InMemorySponsorRepository; let campaignRepository: InMemoryCampaignRepository; let eventPublisher: InMemoryEventPublisher; let getSponsorCampaignsUseCase: GetSponsorCampaignsUseCase; let getCampaignStatisticsUseCase: GetCampaignStatisticsUseCase; let filterCampaignsUseCase: FilterCampaignsUseCase; let searchCampaignsUseCase: SearchCampaignsUseCase; beforeAll(() => { // TODO: Initialize In-Memory repositories and event publisher // sponsorRepository = new InMemorySponsorRepository(); // campaignRepository = new InMemoryCampaignRepository(); // eventPublisher = new InMemoryEventPublisher(); // getSponsorCampaignsUseCase = new GetSponsorCampaignsUseCase({ // sponsorRepository, // campaignRepository, // eventPublisher, // }); // getCampaignStatisticsUseCase = new GetCampaignStatisticsUseCase({ // sponsorRepository, // campaignRepository, // eventPublisher, // }); // filterCampaignsUseCase = new FilterCampaignsUseCase({ // sponsorRepository, // campaignRepository, // eventPublisher, // }); // searchCampaignsUseCase = new SearchCampaignsUseCase({ // sponsorRepository, // campaignRepository, // eventPublisher, // }); }); beforeEach(() => { // TODO: Clear all In-Memory repositories before each test // sponsorRepository.clear(); // campaignRepository.clear(); // eventPublisher.clear(); }); describe('GetSponsorCampaignsUseCase - Success Path', () => { it('should retrieve all campaigns for a sponsor', async () => { // TODO: Implement test // Scenario: Sponsor with multiple campaigns // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 5 campaigns (2 active, 2 pending, 1 rejected) // When: GetSponsorCampaignsUseCase.execute() is called with sponsor ID // Then: The result should contain all 5 campaigns // And: Each campaign should display its details // And: EventPublisher should emit SponsorCampaignsAccessedEvent }); it('should retrieve campaigns with minimal data', async () => { // TODO: Implement test // Scenario: Sponsor with minimal campaigns // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 1 campaign // When: GetSponsorCampaignsUseCase.execute() is called with sponsor ID // Then: The result should contain the single campaign // And: EventPublisher should emit SponsorCampaignsAccessedEvent }); it('should retrieve campaigns with empty result', async () => { // TODO: Implement test // Scenario: Sponsor with no campaigns // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has no campaigns // When: GetSponsorCampaignsUseCase.execute() is called with sponsor ID // Then: The result should be empty // And: EventPublisher should emit SponsorCampaignsAccessedEvent }); }); describe('GetSponsorCampaignsUseCase - 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: GetSponsorCampaignsUseCase.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: GetSponsorCampaignsUseCase.execute() is called with invalid sponsor ID // Then: Should throw ValidationError // And: EventPublisher should NOT emit any events }); }); describe('GetCampaignStatisticsUseCase - Success Path', () => { it('should retrieve campaign statistics for a sponsor', async () => { // TODO: Implement test // Scenario: Sponsor with multiple campaigns // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 5 campaigns (2 active, 2 pending, 1 rejected) // And: The sponsor has total investment of $5000 // And: The sponsor has total impressions of 100000 // When: GetCampaignStatisticsUseCase.execute() is called with sponsor ID // Then: The result should show total sponsorships count: 5 // And: The result should show active sponsorships count: 2 // And: The result should show pending sponsorships count: 2 // And: The result should show approved sponsorships count: 2 // And: The result should show rejected sponsorships count: 1 // And: The result should show total investment: $5000 // And: The result should show total impressions: 100000 // And: EventPublisher should emit CampaignStatisticsAccessedEvent }); it('should retrieve statistics with zero values', async () => { // TODO: Implement test // Scenario: Sponsor with no campaigns // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has no campaigns // When: GetCampaignStatisticsUseCase.execute() is called with sponsor ID // Then: The result should show all counts as 0 // And: The result should show total investment as 0 // And: The result should show total impressions as 0 // And: EventPublisher should emit CampaignStatisticsAccessedEvent }); }); describe('GetCampaignStatisticsUseCase - 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: GetCampaignStatisticsUseCase.execute() is called with non-existent sponsor ID // Then: Should throw SponsorNotFoundError // And: EventPublisher should NOT emit any events }); }); describe('FilterCampaignsUseCase - Success Path', () => { it('should filter campaigns by "All" status', async () => { // TODO: Implement test // Scenario: Filter by All // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 5 campaigns (2 active, 2 pending, 1 rejected) // When: FilterCampaignsUseCase.execute() is called with status "All" // Then: The result should contain all 5 campaigns // And: EventPublisher should emit CampaignsFilteredEvent }); it('should filter campaigns by "Active" status', async () => { // TODO: Implement test // Scenario: Filter by Active // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 5 campaigns (2 active, 2 pending, 1 rejected) // When: FilterCampaignsUseCase.execute() is called with status "Active" // Then: The result should contain only 2 active campaigns // And: EventPublisher should emit CampaignsFilteredEvent }); it('should filter campaigns by "Pending" status', async () => { // TODO: Implement test // Scenario: Filter by Pending // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 5 campaigns (2 active, 2 pending, 1 rejected) // When: FilterCampaignsUseCase.execute() is called with status "Pending" // Then: The result should contain only 2 pending campaigns // And: EventPublisher should emit CampaignsFilteredEvent }); it('should filter campaigns by "Approved" status', async () => { // TODO: Implement test // Scenario: Filter by Approved // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 5 campaigns (2 active, 2 pending, 1 rejected) // When: FilterCampaignsUseCase.execute() is called with status "Approved" // Then: The result should contain only 2 approved campaigns // And: EventPublisher should emit CampaignsFilteredEvent }); it('should filter campaigns by "Rejected" status', async () => { // TODO: Implement test // Scenario: Filter by Rejected // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 5 campaigns (2 active, 2 pending, 1 rejected) // When: FilterCampaignsUseCase.execute() is called with status "Rejected" // Then: The result should contain only 1 rejected campaign // And: EventPublisher should emit CampaignsFilteredEvent }); it('should return empty result when no campaigns match filter', async () => { // TODO: Implement test // Scenario: Filter with no matches // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 2 active campaigns // When: FilterCampaignsUseCase.execute() is called with status "Pending" // Then: The result should be empty // And: EventPublisher should emit CampaignsFilteredEvent }); }); describe('FilterCampaignsUseCase - 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: FilterCampaignsUseCase.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 status', async () => { // TODO: Implement test // Scenario: Invalid status // Given: A sponsor exists with ID "sponsor-123" // When: FilterCampaignsUseCase.execute() is called with invalid status // Then: Should throw ValidationError // And: EventPublisher should NOT emit any events }); }); describe('SearchCampaignsUseCase - Success Path', () => { it('should search campaigns by league name', async () => { // TODO: Implement test // Scenario: Search by league name // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has campaigns for leagues: "League A", "League B", "League C" // When: SearchCampaignsUseCase.execute() is called with query "League A" // Then: The result should contain only campaigns for "League A" // And: EventPublisher should emit CampaignsSearchedEvent }); it('should search campaigns by partial match', async () => { // TODO: Implement test // Scenario: Search by partial match // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has campaigns for leagues: "Premier League", "League A", "League B" // When: SearchCampaignsUseCase.execute() is called with query "League" // Then: The result should contain campaigns for "Premier League", "League A", "League B" // And: EventPublisher should emit CampaignsSearchedEvent }); it('should return empty result when no campaigns match search', async () => { // TODO: Implement test // Scenario: Search with no matches // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has campaigns for leagues: "League A", "League B" // When: SearchCampaignsUseCase.execute() is called with query "NonExistent" // Then: The result should be empty // And: EventPublisher should emit CampaignsSearchedEvent }); it('should return all campaigns when search query is empty', async () => { // TODO: Implement test // Scenario: Search with empty query // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 3 campaigns // When: SearchCampaignsUseCase.execute() is called with empty query // Then: The result should contain all 3 campaigns // And: EventPublisher should emit CampaignsSearchedEvent }); }); describe('SearchCampaignsUseCase - 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: SearchCampaignsUseCase.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: SearchCampaignsUseCase.execute() is called with invalid query (e.g., null, undefined) // Then: Should throw ValidationError // And: EventPublisher should NOT emit any events }); }); describe('Campaign Data Orchestration', () => { it('should correctly aggregate campaign statistics', async () => { // TODO: Implement test // Scenario: Campaign statistics aggregation // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has 3 campaigns with investments: $1000, $2000, $3000 // And: The sponsor has 3 campaigns with impressions: 50000, 30000, 20000 // When: GetCampaignStatisticsUseCase.execute() is called // Then: Total investment should be $6000 // And: Total impressions should be 100000 // And: EventPublisher should emit CampaignStatisticsAccessedEvent }); it('should correctly filter campaigns by status', async () => { // TODO: Implement test // Scenario: Campaign status filtering // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has campaigns with different statuses // When: FilterCampaignsUseCase.execute() is called with "Active" // Then: Only active campaigns should be returned // And: Each campaign should have correct status // And: EventPublisher should emit CampaignsFilteredEvent }); it('should correctly search campaigns by league name', async () => { // TODO: Implement test // Scenario: Campaign league name search // Given: A sponsor exists with ID "sponsor-123" // And: The sponsor has campaigns for different leagues // When: SearchCampaignsUseCase.execute() is called with league name // Then: Only campaigns for matching leagues should be returned // And: Each campaign should have correct league name // And: EventPublisher should emit CampaignsSearchedEvent }); }); });