integration test placeholders
This commit is contained in:
@@ -0,0 +1,359 @@
|
||||
/**
|
||||
* Integration Test: Sponsor Billing Use Case Orchestration
|
||||
*
|
||||
* Tests the orchestration logic of sponsor billing-related Use Cases:
|
||||
* - GetBillingStatisticsUseCase: Retrieves billing statistics
|
||||
* - GetPaymentMethodsUseCase: Retrieves payment methods
|
||||
* - SetDefaultPaymentMethodUseCase: Sets default payment method
|
||||
* - GetInvoicesUseCase: Retrieves invoices
|
||||
* - DownloadInvoiceUseCase: Downloads invoice
|
||||
* - 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 { InMemoryBillingRepository } from '../../../adapters/billing/persistence/inmemory/InMemoryBillingRepository';
|
||||
import { InMemoryEventPublisher } from '../../../adapters/events/InMemoryEventPublisher';
|
||||
import { GetBillingStatisticsUseCase } from '../../../core/sponsors/use-cases/GetBillingStatisticsUseCase';
|
||||
import { GetPaymentMethodsUseCase } from '../../../core/sponsors/use-cases/GetPaymentMethodsUseCase';
|
||||
import { SetDefaultPaymentMethodUseCase } from '../../../core/sponsors/use-cases/SetDefaultPaymentMethodUseCase';
|
||||
import { GetInvoicesUseCase } from '../../../core/sponsors/use-cases/GetInvoicesUseCase';
|
||||
import { DownloadInvoiceUseCase } from '../../../core/sponsors/use-cases/DownloadInvoiceUseCase';
|
||||
import { GetBillingStatisticsQuery } from '../../../core/sponsors/ports/GetBillingStatisticsQuery';
|
||||
import { GetPaymentMethodsQuery } from '../../../core/sponsors/ports/GetPaymentMethodsQuery';
|
||||
import { SetDefaultPaymentMethodCommand } from '../../../core/sponsors/ports/SetDefaultPaymentMethodCommand';
|
||||
import { GetInvoicesQuery } from '../../../core/sponsors/ports/GetInvoicesQuery';
|
||||
import { DownloadInvoiceCommand } from '../../../core/sponsors/ports/DownloadInvoiceCommand';
|
||||
|
||||
describe('Sponsor Billing Use Case Orchestration', () => {
|
||||
let sponsorRepository: InMemorySponsorRepository;
|
||||
let billingRepository: InMemoryBillingRepository;
|
||||
let eventPublisher: InMemoryEventPublisher;
|
||||
let getBillingStatisticsUseCase: GetBillingStatisticsUseCase;
|
||||
let getPaymentMethodsUseCase: GetPaymentMethodsUseCase;
|
||||
let setDefaultPaymentMethodUseCase: SetDefaultPaymentMethodUseCase;
|
||||
let getInvoicesUseCase: GetInvoicesUseCase;
|
||||
let downloadInvoiceUseCase: DownloadInvoiceUseCase;
|
||||
|
||||
beforeAll(() => {
|
||||
// TODO: Initialize In-Memory repositories and event publisher
|
||||
// sponsorRepository = new InMemorySponsorRepository();
|
||||
// billingRepository = new InMemoryBillingRepository();
|
||||
// eventPublisher = new InMemoryEventPublisher();
|
||||
// getBillingStatisticsUseCase = new GetBillingStatisticsUseCase({
|
||||
// sponsorRepository,
|
||||
// billingRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// getPaymentMethodsUseCase = new GetPaymentMethodsUseCase({
|
||||
// sponsorRepository,
|
||||
// billingRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// setDefaultPaymentMethodUseCase = new SetDefaultPaymentMethodUseCase({
|
||||
// sponsorRepository,
|
||||
// billingRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// getInvoicesUseCase = new GetInvoicesUseCase({
|
||||
// sponsorRepository,
|
||||
// billingRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// downloadInvoiceUseCase = new DownloadInvoiceUseCase({
|
||||
// sponsorRepository,
|
||||
// billingRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// TODO: Clear all In-Memory repositories before each test
|
||||
// sponsorRepository.clear();
|
||||
// billingRepository.clear();
|
||||
// eventPublisher.clear();
|
||||
});
|
||||
|
||||
describe('GetBillingStatisticsUseCase - Success Path', () => {
|
||||
it('should retrieve billing statistics for a sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with billing data
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has total spent: $5000
|
||||
// And: The sponsor has pending payments: $1000
|
||||
// And: The sponsor has next payment date: "2024-02-01"
|
||||
// And: The sponsor has monthly average spend: $1250
|
||||
// When: GetBillingStatisticsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show total spent: $5000
|
||||
// And: The result should show pending payments: $1000
|
||||
// And: The result should show next payment date: "2024-02-01"
|
||||
// And: The result should show monthly average spend: $1250
|
||||
// And: EventPublisher should emit BillingStatisticsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve statistics with zero values', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with no billing data
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has no billing history
|
||||
// When: GetBillingStatisticsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show total spent: $0
|
||||
// And: The result should show pending payments: $0
|
||||
// And: The result should show next payment date: null
|
||||
// And: The result should show monthly average spend: $0
|
||||
// And: EventPublisher should emit BillingStatisticsAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetBillingStatisticsUseCase - 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: GetBillingStatisticsUseCase.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: GetBillingStatisticsUseCase.execute() is called with invalid sponsor ID
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetPaymentMethodsUseCase - Success Path', () => {
|
||||
it('should retrieve payment methods for a sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with multiple payment methods
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has 3 payment methods (1 default, 2 non-default)
|
||||
// When: GetPaymentMethodsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should contain all 3 payment methods
|
||||
// And: Each payment method should display its details
|
||||
// And: The default payment method should be marked
|
||||
// And: EventPublisher should emit PaymentMethodsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve payment methods with minimal data', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with single payment method
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has 1 payment method (default)
|
||||
// When: GetPaymentMethodsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should contain the single payment method
|
||||
// And: EventPublisher should emit PaymentMethodsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve payment methods with empty result', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with no payment methods
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has no payment methods
|
||||
// When: GetPaymentMethodsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should be empty
|
||||
// And: EventPublisher should emit PaymentMethodsAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetPaymentMethodsUseCase - 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: GetPaymentMethodsUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('SetDefaultPaymentMethodUseCase - Success Path', () => {
|
||||
it('should set default payment method for a sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Set default payment method
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has 3 payment methods (1 default, 2 non-default)
|
||||
// When: SetDefaultPaymentMethodUseCase.execute() is called with payment method ID
|
||||
// Then: The payment method should become default
|
||||
// And: The previous default should no longer be default
|
||||
// And: EventPublisher should emit PaymentMethodUpdatedEvent
|
||||
});
|
||||
|
||||
it('should set default payment method when no default exists', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Set default when none exists
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has 2 payment methods (no default)
|
||||
// When: SetDefaultPaymentMethodUseCase.execute() is called with payment method ID
|
||||
// Then: The payment method should become default
|
||||
// And: EventPublisher should emit PaymentMethodUpdatedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('SetDefaultPaymentMethodUseCase - 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: SetDefaultPaymentMethodUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should throw error when payment method does not exist', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Non-existent payment method
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has 2 payment methods
|
||||
// When: SetDefaultPaymentMethodUseCase.execute() is called with non-existent payment method ID
|
||||
// Then: Should throw PaymentMethodNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should throw error when payment method does not belong to sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Payment method belongs to different sponsor
|
||||
// Given: Sponsor A exists with ID "sponsor-123"
|
||||
// And: Sponsor B exists with ID "sponsor-456"
|
||||
// And: Sponsor B has a payment method with ID "pm-789"
|
||||
// When: SetDefaultPaymentMethodUseCase.execute() is called with sponsor ID "sponsor-123" and payment method ID "pm-789"
|
||||
// Then: Should throw PaymentMethodNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetInvoicesUseCase - Success Path', () => {
|
||||
it('should retrieve invoices for a sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with multiple invoices
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has 5 invoices (2 pending, 2 paid, 1 overdue)
|
||||
// When: GetInvoicesUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should contain all 5 invoices
|
||||
// And: Each invoice should display its details
|
||||
// And: EventPublisher should emit InvoicesAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve invoices with minimal data', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with single invoice
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has 1 invoice
|
||||
// When: GetInvoicesUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should contain the single invoice
|
||||
// And: EventPublisher should emit InvoicesAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve invoices with empty result', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with no invoices
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has no invoices
|
||||
// When: GetInvoicesUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should be empty
|
||||
// And: EventPublisher should emit InvoicesAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetInvoicesUseCase - 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: GetInvoicesUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('DownloadInvoiceUseCase - Success Path', () => {
|
||||
it('should download invoice for a sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Download invoice
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has an invoice with ID "inv-456"
|
||||
// When: DownloadInvoiceUseCase.execute() is called with invoice ID
|
||||
// Then: The invoice should be downloaded
|
||||
// And: The invoice should be in PDF format
|
||||
// And: EventPublisher should emit InvoiceDownloadedEvent
|
||||
});
|
||||
|
||||
it('should download invoice with correct content', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Download invoice with correct content
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has an invoice with ID "inv-456"
|
||||
// When: DownloadInvoiceUseCase.execute() is called with invoice ID
|
||||
// Then: The downloaded invoice should contain correct invoice number
|
||||
// And: The downloaded invoice should contain correct date
|
||||
// And: The downloaded invoice should contain correct amount
|
||||
// And: EventPublisher should emit InvoiceDownloadedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('DownloadInvoiceUseCase - Error Handling', () => {
|
||||
it('should throw error when invoice does not exist', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Non-existent invoice
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has no invoice with ID "inv-999"
|
||||
// When: DownloadInvoiceUseCase.execute() is called with non-existent invoice ID
|
||||
// Then: Should throw InvoiceNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should throw error when invoice does not belong to sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invoice belongs to different sponsor
|
||||
// Given: Sponsor A exists with ID "sponsor-123"
|
||||
// And: Sponsor B exists with ID "sponsor-456"
|
||||
// And: Sponsor B has an invoice with ID "inv-789"
|
||||
// When: DownloadInvoiceUseCase.execute() is called with invoice ID "inv-789"
|
||||
// Then: Should throw InvoiceNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('Billing Data Orchestration', () => {
|
||||
it('should correctly aggregate billing statistics', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Billing statistics aggregation
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has 3 invoices with amounts: $1000, $2000, $3000
|
||||
// And: The sponsor has 1 pending invoice with amount: $500
|
||||
// When: GetBillingStatisticsUseCase.execute() is called
|
||||
// Then: Total spent should be $6000
|
||||
// And: Pending payments should be $500
|
||||
// And: EventPublisher should emit BillingStatisticsAccessedEvent
|
||||
});
|
||||
|
||||
it('should correctly set default payment method', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Set default payment method
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has 3 payment methods
|
||||
// When: SetDefaultPaymentMethodUseCase.execute() is called
|
||||
// Then: Only one payment method should be default
|
||||
// And: The default payment method should be marked correctly
|
||||
// And: EventPublisher should emit PaymentMethodUpdatedEvent
|
||||
});
|
||||
|
||||
it('should correctly retrieve invoices with status', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invoice status retrieval
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has invoices with different statuses
|
||||
// When: GetInvoicesUseCase.execute() is called
|
||||
// Then: Each invoice should have correct status
|
||||
// And: Pending invoices should be highlighted
|
||||
// And: Overdue invoices should show warning
|
||||
// And: EventPublisher should emit InvoicesAccessedEvent
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,346 @@
|
||||
/**
|
||||
* 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
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* Integration Test: Sponsor Dashboard Use Case Orchestration
|
||||
*
|
||||
* Tests the orchestration logic of sponsor dashboard-related Use Cases:
|
||||
* - GetDashboardOverviewUseCase: Retrieves dashboard overview
|
||||
* - GetDashboardMetricsUseCase: Retrieves dashboard metrics
|
||||
* - GetRecentActivityUseCase: Retrieves recent activity
|
||||
* - GetPendingActionsUseCase: Retrieves pending actions
|
||||
* - 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 { InMemoryBillingRepository } from '../../../adapters/billing/persistence/inmemory/InMemoryBillingRepository';
|
||||
import { InMemoryEventPublisher } from '../../../adapters/events/InMemoryEventPublisher';
|
||||
import { GetDashboardOverviewUseCase } from '../../../core/sponsors/use-cases/GetDashboardOverviewUseCase';
|
||||
import { GetDashboardMetricsUseCase } from '../../../core/sponsors/use-cases/GetDashboardMetricsUseCase';
|
||||
import { GetRecentActivityUseCase } from '../../../core/sponsors/use-cases/GetRecentActivityUseCase';
|
||||
import { GetPendingActionsUseCase } from '../../../core/sponsors/use-cases/GetPendingActionsUseCase';
|
||||
import { GetDashboardOverviewQuery } from '../../../core/sponsors/ports/GetDashboardOverviewQuery';
|
||||
import { GetDashboardMetricsQuery } from '../../../core/sponsors/ports/GetDashboardMetricsQuery';
|
||||
import { GetRecentActivityQuery } from '../../../core/sponsors/ports/GetRecentActivityQuery';
|
||||
import { GetPendingActionsQuery } from '../../../core/sponsors/ports/GetPendingActionsQuery';
|
||||
|
||||
describe('Sponsor Dashboard Use Case Orchestration', () => {
|
||||
let sponsorRepository: InMemorySponsorRepository;
|
||||
let campaignRepository: InMemoryCampaignRepository;
|
||||
let billingRepository: InMemoryBillingRepository;
|
||||
let eventPublisher: InMemoryEventPublisher;
|
||||
let getDashboardOverviewUseCase: GetDashboardOverviewUseCase;
|
||||
let getDashboardMetricsUseCase: GetDashboardMetricsUseCase;
|
||||
let getRecentActivityUseCase: GetRecentActivityUseCase;
|
||||
let getPendingActionsUseCase: GetPendingActionsUseCase;
|
||||
|
||||
beforeAll(() => {
|
||||
// TODO: Initialize In-Memory repositories and event publisher
|
||||
// sponsorRepository = new InMemorySponsorRepository();
|
||||
// campaignRepository = new InMemoryCampaignRepository();
|
||||
// billingRepository = new InMemoryBillingRepository();
|
||||
// eventPublisher = new InMemoryEventPublisher();
|
||||
// getDashboardOverviewUseCase = new GetDashboardOverviewUseCase({
|
||||
// sponsorRepository,
|
||||
// campaignRepository,
|
||||
// billingRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// getDashboardMetricsUseCase = new GetDashboardMetricsUseCase({
|
||||
// sponsorRepository,
|
||||
// campaignRepository,
|
||||
// billingRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// getRecentActivityUseCase = new GetRecentActivityUseCase({
|
||||
// sponsorRepository,
|
||||
// campaignRepository,
|
||||
// billingRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// getPendingActionsUseCase = new GetPendingActionsUseCase({
|
||||
// sponsorRepository,
|
||||
// campaignRepository,
|
||||
// billingRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// TODO: Clear all In-Memory repositories before each test
|
||||
// sponsorRepository.clear();
|
||||
// campaignRepository.clear();
|
||||
// billingRepository.clear();
|
||||
// eventPublisher.clear();
|
||||
});
|
||||
|
||||
describe('GetDashboardOverviewUseCase - Success Path', () => {
|
||||
it('should retrieve dashboard overview for a sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with complete dashboard data
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has company name "Test Company"
|
||||
// And: The sponsor has 5 campaigns
|
||||
// And: The sponsor has billing data
|
||||
// When: GetDashboardOverviewUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show company name
|
||||
// And: The result should show welcome message
|
||||
// And: The result should show quick action buttons
|
||||
// And: EventPublisher should emit DashboardOverviewAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve overview with minimal data', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with minimal data
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has company name "Test Company"
|
||||
// And: The sponsor has no campaigns
|
||||
// And: The sponsor has no billing data
|
||||
// When: GetDashboardOverviewUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show company name
|
||||
// And: The result should show welcome message
|
||||
// And: EventPublisher should emit DashboardOverviewAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetDashboardOverviewUseCase - 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: GetDashboardOverviewUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetDashboardMetricsUseCase - Success Path', () => {
|
||||
it('should retrieve dashboard metrics for a sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with complete metrics
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has 5 total sponsorships
|
||||
// And: The sponsor has 2 active sponsorships
|
||||
// And: The sponsor has total investment of $5000
|
||||
// And: The sponsor has total impressions of 100000
|
||||
// When: GetDashboardMetricsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show total sponsorships: 5
|
||||
// And: The result should show active sponsorships: 2
|
||||
// And: The result should show total investment: $5000
|
||||
// And: The result should show total impressions: 100000
|
||||
// And: EventPublisher should emit DashboardMetricsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve metrics with zero values', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with no metrics
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has no campaigns
|
||||
// When: GetDashboardMetricsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show total sponsorships: 0
|
||||
// And: The result should show active sponsorships: 0
|
||||
// And: The result should show total investment: $0
|
||||
// And: The result should show total impressions: 0
|
||||
// And: EventPublisher should emit DashboardMetricsAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetDashboardMetricsUseCase - 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: GetDashboardMetricsUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetRecentActivityUseCase - Success Path', () => {
|
||||
it('should retrieve recent activity for a sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with recent activity
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has recent sponsorship updates
|
||||
// And: The sponsor has recent billing activity
|
||||
// And: The sponsor has recent campaign changes
|
||||
// When: GetRecentActivityUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should contain recent sponsorship updates
|
||||
// And: The result should contain recent billing activity
|
||||
// And: The result should contain recent campaign changes
|
||||
// And: EventPublisher should emit RecentActivityAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve activity with empty result', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with no recent activity
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has no recent activity
|
||||
// When: GetRecentActivityUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should be empty
|
||||
// And: EventPublisher should emit RecentActivityAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetRecentActivityUseCase - 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: GetRecentActivityUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetPendingActionsUseCase - Success Path', () => {
|
||||
it('should retrieve pending actions for a sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with pending actions
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has sponsorships awaiting approval
|
||||
// And: The sponsor has pending payments
|
||||
// And: The sponsor has action items
|
||||
// When: GetPendingActionsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show sponsorships awaiting approval
|
||||
// And: The result should show pending payments
|
||||
// And: The result should show action items
|
||||
// And: EventPublisher should emit PendingActionsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve pending actions with empty result', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with no pending actions
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has no pending actions
|
||||
// When: GetPendingActionsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should be empty
|
||||
// And: EventPublisher should emit PendingActionsAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetPendingActionsUseCase - 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: GetPendingActionsUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dashboard Data Orchestration', () => {
|
||||
it('should correctly aggregate dashboard metrics', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Dashboard metrics 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: GetDashboardMetricsUseCase.execute() is called
|
||||
// Then: Total sponsorships should be 3
|
||||
// And: Active sponsorships should be calculated correctly
|
||||
// And: Total investment should be $6000
|
||||
// And: Total impressions should be 100000
|
||||
// And: EventPublisher should emit DashboardMetricsAccessedEvent
|
||||
});
|
||||
|
||||
it('should correctly format recent activity', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Recent activity formatting
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has recent activity from different sources
|
||||
// When: GetRecentActivityUseCase.execute() is called
|
||||
// Then: Activity should be sorted by date (newest first)
|
||||
// And: Each activity should have correct type and details
|
||||
// And: EventPublisher should emit RecentActivityAccessedEvent
|
||||
});
|
||||
|
||||
it('should correctly identify pending actions', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Pending actions identification
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has sponsorships awaiting approval
|
||||
// And: The sponsor has pending payments
|
||||
// When: GetPendingActionsUseCase.execute() is called
|
||||
// Then: All pending actions should be identified
|
||||
// And: Each action should have correct priority
|
||||
// And: EventPublisher should emit PendingActionsAccessedEvent
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,345 @@
|
||||
/**
|
||||
* 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
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,331 @@
|
||||
/**
|
||||
* 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
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,392 @@
|
||||
/**
|
||||
* Integration Test: Sponsor Settings Use Case Orchestration
|
||||
*
|
||||
* Tests the orchestration logic of sponsor settings-related Use Cases:
|
||||
* - GetSponsorProfileUseCase: Retrieves sponsor profile information
|
||||
* - UpdateSponsorProfileUseCase: Updates sponsor profile information
|
||||
* - GetNotificationPreferencesUseCase: Retrieves notification preferences
|
||||
* - UpdateNotificationPreferencesUseCase: Updates notification preferences
|
||||
* - GetPrivacySettingsUseCase: Retrieves privacy settings
|
||||
* - UpdatePrivacySettingsUseCase: Updates privacy settings
|
||||
* - DeleteSponsorAccountUseCase: Deletes sponsor account
|
||||
* - 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 { InMemoryEventPublisher } from '../../../adapters/events/InMemoryEventPublisher';
|
||||
import { GetSponsorProfileUseCase } from '../../../core/sponsors/use-cases/GetSponsorProfileUseCase';
|
||||
import { UpdateSponsorProfileUseCase } from '../../../core/sponsors/use-cases/UpdateSponsorProfileUseCase';
|
||||
import { GetNotificationPreferencesUseCase } from '../../../core/sponsors/use-cases/GetNotificationPreferencesUseCase';
|
||||
import { UpdateNotificationPreferencesUseCase } from '../../../core/sponsors/use-cases/UpdateNotificationPreferencesUseCase';
|
||||
import { GetPrivacySettingsUseCase } from '../../../core/sponsors/use-cases/GetPrivacySettingsUseCase';
|
||||
import { UpdatePrivacySettingsUseCase } from '../../../core/sponsors/use-cases/UpdatePrivacySettingsUseCase';
|
||||
import { DeleteSponsorAccountUseCase } from '../../../core/sponsors/use-cases/DeleteSponsorAccountUseCase';
|
||||
import { GetSponsorProfileQuery } from '../../../core/sponsors/ports/GetSponsorProfileQuery';
|
||||
import { UpdateSponsorProfileCommand } from '../../../core/sponsors/ports/UpdateSponsorProfileCommand';
|
||||
import { GetNotificationPreferencesQuery } from '../../../core/sponsors/ports/GetNotificationPreferencesQuery';
|
||||
import { UpdateNotificationPreferencesCommand } from '../../../core/sponsors/ports/UpdateNotificationPreferencesCommand';
|
||||
import { GetPrivacySettingsQuery } from '../../../core/sponsors/ports/GetPrivacySettingsQuery';
|
||||
import { UpdatePrivacySettingsCommand } from '../../../core/sponsors/ports/UpdatePrivacySettingsCommand';
|
||||
import { DeleteSponsorAccountCommand } from '../../../core/sponsors/ports/DeleteSponsorAccountCommand';
|
||||
|
||||
describe('Sponsor Settings Use Case Orchestration', () => {
|
||||
let sponsorRepository: InMemorySponsorRepository;
|
||||
let eventPublisher: InMemoryEventPublisher;
|
||||
let getSponsorProfileUseCase: GetSponsorProfileUseCase;
|
||||
let updateSponsorProfileUseCase: UpdateSponsorProfileUseCase;
|
||||
let getNotificationPreferencesUseCase: GetNotificationPreferencesUseCase;
|
||||
let updateNotificationPreferencesUseCase: UpdateNotificationPreferencesUseCase;
|
||||
let getPrivacySettingsUseCase: GetPrivacySettingsUseCase;
|
||||
let updatePrivacySettingsUseCase: UpdatePrivacySettingsUseCase;
|
||||
let deleteSponsorAccountUseCase: DeleteSponsorAccountUseCase;
|
||||
|
||||
beforeAll(() => {
|
||||
// TODO: Initialize In-Memory repositories and event publisher
|
||||
// sponsorRepository = new InMemorySponsorRepository();
|
||||
// eventPublisher = new InMemoryEventPublisher();
|
||||
// getSponsorProfileUseCase = new GetSponsorProfileUseCase({
|
||||
// sponsorRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// updateSponsorProfileUseCase = new UpdateSponsorProfileUseCase({
|
||||
// sponsorRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// getNotificationPreferencesUseCase = new GetNotificationPreferencesUseCase({
|
||||
// sponsorRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// updateNotificationPreferencesUseCase = new UpdateNotificationPreferencesUseCase({
|
||||
// sponsorRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// getPrivacySettingsUseCase = new GetPrivacySettingsUseCase({
|
||||
// sponsorRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// updatePrivacySettingsUseCase = new UpdatePrivacySettingsUseCase({
|
||||
// sponsorRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// deleteSponsorAccountUseCase = new DeleteSponsorAccountUseCase({
|
||||
// sponsorRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// TODO: Clear all In-Memory repositories before each test
|
||||
// sponsorRepository.clear();
|
||||
// eventPublisher.clear();
|
||||
});
|
||||
|
||||
describe('GetSponsorProfileUseCase - Success Path', () => {
|
||||
it('should retrieve sponsor profile information', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with complete profile
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has company name "Test Company"
|
||||
// And: The sponsor has contact name "John Doe"
|
||||
// And: The sponsor has contact email "john@example.com"
|
||||
// And: The sponsor has contact phone "+1234567890"
|
||||
// And: The sponsor has website URL "https://testcompany.com"
|
||||
// And: The sponsor has company description "Test description"
|
||||
// And: The sponsor has industry "Technology"
|
||||
// And: The sponsor has address "123 Test St"
|
||||
// And: The sponsor has tax ID "TAX123"
|
||||
// When: GetSponsorProfileUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show all profile information
|
||||
// And: EventPublisher should emit SponsorProfileAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve profile with minimal data', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with minimal profile
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has company name "Test Company"
|
||||
// And: The sponsor has contact email "john@example.com"
|
||||
// When: GetSponsorProfileUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show available profile information
|
||||
// And: EventPublisher should emit SponsorProfileAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetSponsorProfileUseCase - 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: GetSponsorProfileUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdateSponsorProfileUseCase - Success Path', () => {
|
||||
it('should update sponsor profile information', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Update sponsor profile
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: UpdateSponsorProfileUseCase.execute() is called with updated profile data
|
||||
// Then: The sponsor profile should be updated
|
||||
// And: The updated data should be retrievable
|
||||
// And: EventPublisher should emit SponsorProfileUpdatedEvent
|
||||
});
|
||||
|
||||
it('should update sponsor profile with partial data', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Update partial profile
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: UpdateSponsorProfileUseCase.execute() is called with partial profile data
|
||||
// Then: Only the provided fields should be updated
|
||||
// And: Other fields should remain unchanged
|
||||
// And: EventPublisher should emit SponsorProfileUpdatedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdateSponsorProfileUseCase - Validation', () => {
|
||||
it('should reject update with invalid email', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invalid email format
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: UpdateSponsorProfileUseCase.execute() is called with invalid email
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject update with invalid phone', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invalid phone format
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: UpdateSponsorProfileUseCase.execute() is called with invalid phone
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject update with invalid URL', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invalid URL format
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: UpdateSponsorProfileUseCase.execute() is called with invalid URL
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdateSponsorProfileUseCase - 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: UpdateSponsorProfileUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetNotificationPreferencesUseCase - Success Path', () => {
|
||||
it('should retrieve notification preferences', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with notification preferences
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has notification preferences configured
|
||||
// When: GetNotificationPreferencesUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show all notification options
|
||||
// And: Each option should show its enabled/disabled status
|
||||
// And: EventPublisher should emit NotificationPreferencesAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve default notification preferences', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with default preferences
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has default notification preferences
|
||||
// When: GetNotificationPreferencesUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show default preferences
|
||||
// And: EventPublisher should emit NotificationPreferencesAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetNotificationPreferencesUseCase - 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: GetNotificationPreferencesUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdateNotificationPreferencesUseCase - Success Path', () => {
|
||||
it('should update notification preferences', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Update notification preferences
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: UpdateNotificationPreferencesUseCase.execute() is called with updated preferences
|
||||
// Then: The notification preferences should be updated
|
||||
// And: The updated preferences should be retrievable
|
||||
// And: EventPublisher should emit NotificationPreferencesUpdatedEvent
|
||||
});
|
||||
|
||||
it('should toggle individual notification preferences', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Toggle notification preference
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: UpdateNotificationPreferencesUseCase.execute() is called to toggle a preference
|
||||
// Then: Only the toggled preference should change
|
||||
// And: Other preferences should remain unchanged
|
||||
// And: EventPublisher should emit NotificationPreferencesUpdatedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdateNotificationPreferencesUseCase - 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: UpdateNotificationPreferencesUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetPrivacySettingsUseCase - Success Path', () => {
|
||||
it('should retrieve privacy settings', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with privacy settings
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has privacy settings configured
|
||||
// When: GetPrivacySettingsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show all privacy options
|
||||
// And: Each option should show its enabled/disabled status
|
||||
// And: EventPublisher should emit PrivacySettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve default privacy settings', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with default privacy settings
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has default privacy settings
|
||||
// When: GetPrivacySettingsUseCase.execute() is called with sponsor ID
|
||||
// Then: The result should show default privacy settings
|
||||
// And: EventPublisher should emit PrivacySettingsAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetPrivacySettingsUseCase - 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: GetPrivacySettingsUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdatePrivacySettingsUseCase - Success Path', () => {
|
||||
it('should update privacy settings', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Update privacy settings
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: UpdatePrivacySettingsUseCase.execute() is called with updated settings
|
||||
// Then: The privacy settings should be updated
|
||||
// And: The updated settings should be retrievable
|
||||
// And: EventPublisher should emit PrivacySettingsUpdatedEvent
|
||||
});
|
||||
|
||||
it('should toggle individual privacy settings', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Toggle privacy setting
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: UpdatePrivacySettingsUseCase.execute() is called to toggle a setting
|
||||
// Then: Only the toggled setting should change
|
||||
// And: Other settings should remain unchanged
|
||||
// And: EventPublisher should emit PrivacySettingsUpdatedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdatePrivacySettingsUseCase - 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: UpdatePrivacySettingsUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('DeleteSponsorAccountUseCase - Success Path', () => {
|
||||
it('should delete sponsor account', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Delete sponsor account
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: DeleteSponsorAccountUseCase.execute() is called with sponsor ID
|
||||
// Then: The sponsor account should be deleted
|
||||
// And: The sponsor should no longer be retrievable
|
||||
// And: EventPublisher should emit SponsorAccountDeletedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('DeleteSponsorAccountUseCase - 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: DeleteSponsorAccountUseCase.execute() is called with non-existent sponsor ID
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('Sponsor Settings Data Orchestration', () => {
|
||||
it('should correctly update sponsor profile', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Profile update orchestration
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has initial profile data
|
||||
// When: UpdateSponsorProfileUseCase.execute() is called with new data
|
||||
// Then: The profile should be updated in the repository
|
||||
// And: The updated data should be retrievable
|
||||
// And: EventPublisher should emit SponsorProfileUpdatedEvent
|
||||
});
|
||||
|
||||
it('should correctly update notification preferences', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Notification preferences update orchestration
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has initial notification preferences
|
||||
// When: UpdateNotificationPreferencesUseCase.execute() is called with new preferences
|
||||
// Then: The preferences should be updated in the repository
|
||||
// And: The updated preferences should be retrievable
|
||||
// And: EventPublisher should emit NotificationPreferencesUpdatedEvent
|
||||
});
|
||||
|
||||
it('should correctly update privacy settings', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Privacy settings update orchestration
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// And: The sponsor has initial privacy settings
|
||||
// When: UpdatePrivacySettingsUseCase.execute() is called with new settings
|
||||
// Then: The settings should be updated in the repository
|
||||
// And: The updated settings should be retrievable
|
||||
// And: EventPublisher should emit PrivacySettingsUpdatedEvent
|
||||
});
|
||||
|
||||
it('should correctly delete sponsor account', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Account deletion orchestration
|
||||
// Given: A sponsor exists with ID "sponsor-123"
|
||||
// When: DeleteSponsorAccountUseCase.execute() is called
|
||||
// Then: The sponsor should be deleted from the repository
|
||||
// And: The sponsor should no longer be retrievable
|
||||
// And: EventPublisher should emit SponsorAccountDeletedEvent
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* Integration Test: Sponsor Signup Use Case Orchestration
|
||||
*
|
||||
* Tests the orchestration logic of sponsor signup-related Use Cases:
|
||||
* - CreateSponsorUseCase: Creates a new sponsor account
|
||||
* - SponsorLoginUseCase: Authenticates a sponsor
|
||||
* - SponsorLogoutUseCase: Logs out a sponsor
|
||||
* - 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 { InMemoryEventPublisher } from '../../../adapters/events/InMemoryEventPublisher';
|
||||
import { CreateSponsorUseCase } from '../../../core/sponsors/use-cases/CreateSponsorUseCase';
|
||||
import { SponsorLoginUseCase } from '../../../core/sponsors/use-cases/SponsorLoginUseCase';
|
||||
import { SponsorLogoutUseCase } from '../../../core/sponsors/use-cases/SponsorLogoutUseCase';
|
||||
import { CreateSponsorCommand } from '../../../core/sponsors/ports/CreateSponsorCommand';
|
||||
import { SponsorLoginCommand } from '../../../core/sponsors/ports/SponsorLoginCommand';
|
||||
import { SponsorLogoutCommand } from '../../../core/sponsors/ports/SponsorLogoutCommand';
|
||||
|
||||
describe('Sponsor Signup Use Case Orchestration', () => {
|
||||
let sponsorRepository: InMemorySponsorRepository;
|
||||
let eventPublisher: InMemoryEventPublisher;
|
||||
let createSponsorUseCase: CreateSponsorUseCase;
|
||||
let sponsorLoginUseCase: SponsorLoginUseCase;
|
||||
let sponsorLogoutUseCase: SponsorLogoutUseCase;
|
||||
|
||||
beforeAll(() => {
|
||||
// TODO: Initialize In-Memory repositories and event publisher
|
||||
// sponsorRepository = new InMemorySponsorRepository();
|
||||
// eventPublisher = new InMemoryEventPublisher();
|
||||
// createSponsorUseCase = new CreateSponsorUseCase({
|
||||
// sponsorRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// sponsorLoginUseCase = new SponsorLoginUseCase({
|
||||
// sponsorRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// sponsorLogoutUseCase = new SponsorLogoutUseCase({
|
||||
// sponsorRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// TODO: Clear all In-Memory repositories before each test
|
||||
// sponsorRepository.clear();
|
||||
// eventPublisher.clear();
|
||||
});
|
||||
|
||||
describe('CreateSponsorUseCase - Success Path', () => {
|
||||
it('should create a new sponsor account with valid information', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor creates account
|
||||
// Given: No sponsor exists with the given email
|
||||
// When: CreateSponsorUseCase.execute() is called with valid sponsor data
|
||||
// Then: The sponsor should be created in the repository
|
||||
// And: The sponsor should have a unique ID
|
||||
// And: The sponsor should have the provided company name
|
||||
// And: The sponsor should have the provided contact email
|
||||
// And: The sponsor should have the provided website URL
|
||||
// And: The sponsor should have the provided sponsorship interests
|
||||
// And: The sponsor should have a created timestamp
|
||||
// And: EventPublisher should emit SponsorCreatedEvent
|
||||
});
|
||||
|
||||
it('should create a sponsor with multiple sponsorship interests', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor creates account with multiple interests
|
||||
// Given: No sponsor exists with the given email
|
||||
// When: CreateSponsorUseCase.execute() is called with multiple sponsorship interests
|
||||
// Then: The sponsor should be created with all selected interests
|
||||
// And: Each interest should be stored correctly
|
||||
// And: EventPublisher should emit SponsorCreatedEvent
|
||||
});
|
||||
|
||||
it('should create a sponsor with optional company logo', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor creates account with logo
|
||||
// Given: No sponsor exists with the given email
|
||||
// When: CreateSponsorUseCase.execute() is called with a company logo
|
||||
// Then: The sponsor should be created with the logo reference
|
||||
// And: The logo should be stored in the media repository
|
||||
// And: EventPublisher should emit SponsorCreatedEvent
|
||||
});
|
||||
|
||||
it('should create a sponsor with default settings', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor creates account with default settings
|
||||
// Given: No sponsor exists with the given email
|
||||
// When: CreateSponsorUseCase.execute() is called
|
||||
// Then: The sponsor should be created with default notification preferences
|
||||
// And: The sponsor should be created with default privacy settings
|
||||
// And: EventPublisher should emit SponsorCreatedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('CreateSponsorUseCase - Validation', () => {
|
||||
it('should reject sponsor creation with duplicate email', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Duplicate email
|
||||
// Given: A sponsor exists with email "sponsor@example.com"
|
||||
// When: CreateSponsorUseCase.execute() is called with the same email
|
||||
// Then: Should throw DuplicateEmailError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject sponsor creation with invalid email format', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invalid email format
|
||||
// Given: No sponsor exists
|
||||
// When: CreateSponsorUseCase.execute() is called with invalid email
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject sponsor creation with missing required fields', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Missing required fields
|
||||
// Given: No sponsor exists
|
||||
// When: CreateSponsorUseCase.execute() is called without company name
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject sponsor creation with invalid website URL', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invalid website URL
|
||||
// Given: No sponsor exists
|
||||
// When: CreateSponsorUseCase.execute() is called with invalid URL
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject sponsor creation with invalid password', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invalid password
|
||||
// Given: No sponsor exists
|
||||
// When: CreateSponsorUseCase.execute() is called with weak password
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('SponsorLoginUseCase - Success Path', () => {
|
||||
it('should authenticate sponsor with valid credentials', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor logs in
|
||||
// Given: A sponsor exists with email "sponsor@example.com" and password "password123"
|
||||
// When: SponsorLoginUseCase.execute() is called with valid credentials
|
||||
// Then: The sponsor should be authenticated
|
||||
// And: The sponsor should receive an authentication token
|
||||
// And: EventPublisher should emit SponsorLoggedInEvent
|
||||
});
|
||||
|
||||
it('should authenticate sponsor with correct email and password', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor logs in with correct credentials
|
||||
// Given: A sponsor exists with specific credentials
|
||||
// When: SponsorLoginUseCase.execute() is called with matching credentials
|
||||
// Then: The sponsor should be authenticated
|
||||
// And: EventPublisher should emit SponsorLoggedInEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('SponsorLoginUseCase - Error Handling', () => {
|
||||
it('should reject login with non-existent email', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Non-existent sponsor
|
||||
// Given: No sponsor exists with the given email
|
||||
// When: SponsorLoginUseCase.execute() is called
|
||||
// Then: Should throw SponsorNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject login with incorrect password', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Incorrect password
|
||||
// Given: A sponsor exists with email "sponsor@example.com"
|
||||
// When: SponsorLoginUseCase.execute() is called with wrong password
|
||||
// Then: Should throw InvalidCredentialsError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject login with invalid email format', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invalid email format
|
||||
// Given: No sponsor exists
|
||||
// When: SponsorLoginUseCase.execute() is called with invalid email
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('SponsorLogoutUseCase - Success Path', () => {
|
||||
it('should log out authenticated sponsor', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor logs out
|
||||
// Given: A sponsor is authenticated
|
||||
// When: SponsorLogoutUseCase.execute() is called
|
||||
// Then: The sponsor should be logged out
|
||||
// And: EventPublisher should emit SponsorLoggedOutEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('Sponsor Data Orchestration', () => {
|
||||
it('should correctly create sponsor with sponsorship interests', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with multiple interests
|
||||
// Given: No sponsor exists
|
||||
// When: CreateSponsorUseCase.execute() is called with interests: ["League", "Team", "Driver"]
|
||||
// Then: The sponsor should have all three interests stored
|
||||
// And: Each interest should be retrievable
|
||||
// And: EventPublisher should emit SponsorCreatedEvent
|
||||
});
|
||||
|
||||
it('should correctly create sponsor with default notification preferences', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with default notifications
|
||||
// Given: No sponsor exists
|
||||
// When: CreateSponsorUseCase.execute() is called
|
||||
// Then: The sponsor should have default notification preferences
|
||||
// And: All notification types should be enabled by default
|
||||
// And: EventPublisher should emit SponsorCreatedEvent
|
||||
});
|
||||
|
||||
it('should correctly create sponsor with default privacy settings', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Sponsor with default privacy
|
||||
// Given: No sponsor exists
|
||||
// When: CreateSponsorUseCase.execute() is called
|
||||
// Then: The sponsor should have default privacy settings
|
||||
// And: Public profile should be enabled by default
|
||||
// And: EventPublisher should emit SponsorCreatedEvent
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user