Files
gridpilot.gg/tests/integration/sponsor/sponsor-campaigns-use-cases.integration.test.ts

347 lines
16 KiB
TypeScript

/**
* 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
});
});
});