integration tests
Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m50s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m50s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
This commit is contained in:
70
tests/integration/leagues/LeaguesTestContext.ts
Normal file
70
tests/integration/leagues/LeaguesTestContext.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { InMemoryLeagueRepository } from '../../../adapters/leagues/persistence/inmemory/InMemoryLeagueRepository';
|
||||
import { InMemoryDriverRepository } from '../../../adapters/drivers/persistence/inmemory/InMemoryDriverRepository';
|
||||
import { InMemoryEventPublisher } from '../../../adapters/events/InMemoryEventPublisher';
|
||||
import { CreateLeagueUseCase } from '../../../core/leagues/application/use-cases/CreateLeagueUseCase';
|
||||
import { GetLeagueUseCase } from '../../../core/leagues/application/use-cases/GetLeagueUseCase';
|
||||
import { GetLeagueRosterUseCase } from '../../../core/leagues/application/use-cases/GetLeagueRosterUseCase';
|
||||
import { JoinLeagueUseCase } from '../../../core/leagues/application/use-cases/JoinLeagueUseCase';
|
||||
import { LeaveLeagueUseCase } from '../../../core/leagues/application/use-cases/LeaveLeagueUseCase';
|
||||
import { ApproveMembershipRequestUseCase } from '../../../core/leagues/application/use-cases/ApproveMembershipRequestUseCase';
|
||||
import { RejectMembershipRequestUseCase } from '../../../core/leagues/application/use-cases/RejectMembershipRequestUseCase';
|
||||
import { PromoteMemberUseCase } from '../../../core/leagues/application/use-cases/PromoteMemberUseCase';
|
||||
import { DemoteAdminUseCase } from '../../../core/leagues/application/use-cases/DemoteAdminUseCase';
|
||||
import { RemoveMemberUseCase } from '../../../core/leagues/application/use-cases/RemoveMemberUseCase';
|
||||
import { LeagueCreateCommand } from '../../../core/leagues/application/ports/LeagueCreateCommand';
|
||||
|
||||
export class LeaguesTestContext {
|
||||
public readonly leagueRepository: InMemoryLeagueRepository;
|
||||
public readonly driverRepository: InMemoryDriverRepository;
|
||||
public readonly eventPublisher: InMemoryEventPublisher;
|
||||
|
||||
public readonly createLeagueUseCase: CreateLeagueUseCase;
|
||||
public readonly getLeagueUseCase: GetLeagueUseCase;
|
||||
public readonly getLeagueRosterUseCase: GetLeagueRosterUseCase;
|
||||
public readonly joinLeagueUseCase: JoinLeagueUseCase;
|
||||
public readonly leaveLeagueUseCase: LeaveLeagueUseCase;
|
||||
public readonly approveMembershipRequestUseCase: ApproveMembershipRequestUseCase;
|
||||
public readonly rejectMembershipRequestUseCase: RejectMembershipRequestUseCase;
|
||||
public readonly promoteMemberUseCase: PromoteMemberUseCase;
|
||||
public readonly demoteAdminUseCase: DemoteAdminUseCase;
|
||||
public readonly removeMemberUseCase: RemoveMemberUseCase;
|
||||
|
||||
constructor() {
|
||||
this.leagueRepository = new InMemoryLeagueRepository();
|
||||
this.driverRepository = new InMemoryDriverRepository();
|
||||
this.eventPublisher = new InMemoryEventPublisher();
|
||||
|
||||
this.createLeagueUseCase = new CreateLeagueUseCase(this.leagueRepository, this.eventPublisher);
|
||||
this.getLeagueUseCase = new GetLeagueUseCase(this.leagueRepository, this.eventPublisher);
|
||||
this.getLeagueRosterUseCase = new GetLeagueRosterUseCase(this.leagueRepository, this.eventPublisher);
|
||||
this.joinLeagueUseCase = new JoinLeagueUseCase(this.leagueRepository, this.driverRepository, this.eventPublisher);
|
||||
this.leaveLeagueUseCase = new LeaveLeagueUseCase(this.leagueRepository, this.driverRepository, this.eventPublisher);
|
||||
this.approveMembershipRequestUseCase = new ApproveMembershipRequestUseCase(this.leagueRepository, this.driverRepository, this.eventPublisher);
|
||||
this.rejectMembershipRequestUseCase = new RejectMembershipRequestUseCase(this.leagueRepository, this.driverRepository, this.eventPublisher);
|
||||
this.promoteMemberUseCase = new PromoteMemberUseCase(this.leagueRepository, this.driverRepository, this.eventPublisher);
|
||||
this.demoteAdminUseCase = new DemoteAdminUseCase(this.leagueRepository, this.driverRepository, this.eventPublisher);
|
||||
this.removeMemberUseCase = new RemoveMemberUseCase(this.leagueRepository, this.driverRepository, this.eventPublisher);
|
||||
}
|
||||
|
||||
public clear(): void {
|
||||
this.leagueRepository.clear();
|
||||
this.driverRepository.clear();
|
||||
this.eventPublisher.clear();
|
||||
}
|
||||
|
||||
public async createLeague(command: Partial<LeagueCreateCommand> = {}) {
|
||||
const defaultCommand: LeagueCreateCommand = {
|
||||
name: 'Test League',
|
||||
visibility: 'public',
|
||||
ownerId: 'driver-123',
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
...command,
|
||||
};
|
||||
return await this.createLeagueUseCase.execute(defaultCommand);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
import { LeagueCreateCommand } from '../../../../core/leagues/application/ports/LeagueCreateCommand';
|
||||
|
||||
describe('League Creation - Edge Cases', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should handle league with empty description', async () => {
|
||||
const result = await context.createLeague({ description: '' });
|
||||
expect(result.description).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle league with very long description', async () => {
|
||||
const longDescription = 'a'.repeat(2000);
|
||||
const result = await context.createLeague({ description: longDescription });
|
||||
expect(result.description).toBe(longDescription);
|
||||
});
|
||||
|
||||
it('should handle league with special characters in name', async () => {
|
||||
const specialName = 'League! @#$%^&*()_+';
|
||||
const result = await context.createLeague({ name: specialName });
|
||||
expect(result.name).toBe(specialName);
|
||||
});
|
||||
|
||||
it('should handle league with max drivers set to 1', async () => {
|
||||
const result = await context.createLeague({ maxDrivers: 1 });
|
||||
expect(result.maxDrivers).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle league with empty track list', async () => {
|
||||
const result = await context.createLeague({ tracks: [] });
|
||||
expect(result.tracks).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
import { LeagueCreateCommand } from '../../../../core/leagues/application/ports/LeagueCreateCommand';
|
||||
import { InMemoryLeagueRepository } from '../../../../adapters/leagues/persistence/inmemory/InMemoryLeagueRepository';
|
||||
import { CreateLeagueUseCase } from '../../../../core/leagues/application/use-cases/CreateLeagueUseCase';
|
||||
|
||||
describe('League Creation - Error Handling', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should throw error when driver ID is invalid', async () => {
|
||||
const command: LeagueCreateCommand = {
|
||||
name: 'Test League',
|
||||
visibility: 'public',
|
||||
ownerId: '',
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
};
|
||||
|
||||
await expect(context.createLeagueUseCase.execute(command)).rejects.toThrow('Owner ID is required');
|
||||
expect(context.eventPublisher.getLeagueCreatedEventCount()).toBe(0);
|
||||
});
|
||||
|
||||
it('should throw error when league name is empty', async () => {
|
||||
const command: LeagueCreateCommand = {
|
||||
name: '',
|
||||
visibility: 'public',
|
||||
ownerId: 'driver-123',
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
};
|
||||
|
||||
await expect(context.createLeagueUseCase.execute(command)).rejects.toThrow();
|
||||
expect(context.eventPublisher.getLeagueCreatedEventCount()).toBe(0);
|
||||
});
|
||||
|
||||
it('should throw error when repository throws error', async () => {
|
||||
const errorRepo = new InMemoryLeagueRepository();
|
||||
errorRepo.create = async () => { throw new Error('Database error'); };
|
||||
const errorUseCase = new CreateLeagueUseCase(errorRepo, context.eventPublisher);
|
||||
|
||||
const command: LeagueCreateCommand = {
|
||||
name: 'Test League',
|
||||
visibility: 'public',
|
||||
ownerId: 'driver-123',
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
};
|
||||
|
||||
await expect(errorUseCase.execute(command)).rejects.toThrow('Database error');
|
||||
expect(context.eventPublisher.getLeagueCreatedEventCount()).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
import { LeagueCreateCommand } from '../../../../core/leagues/application/ports/LeagueCreateCommand';
|
||||
|
||||
describe('League Creation - Success Path', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should create a league with complete configuration', async () => {
|
||||
const driverId = 'driver-123';
|
||||
const command: LeagueCreateCommand = {
|
||||
name: 'Test League',
|
||||
description: 'A test league for integration testing',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
maxDrivers: 20,
|
||||
approvalRequired: true,
|
||||
lateJoinAllowed: true,
|
||||
raceFrequency: 'weekly',
|
||||
raceDay: 'Saturday',
|
||||
raceTime: '18:00',
|
||||
tracks: ['Monza', 'Spa', 'Nürburgring'],
|
||||
scoringSystem: { points: [25, 18, 15, 12, 10, 8, 6, 4, 2, 1] },
|
||||
bonusPointsEnabled: true,
|
||||
penaltiesEnabled: true,
|
||||
protestsEnabled: true,
|
||||
appealsEnabled: true,
|
||||
stewardTeam: ['steward-1', 'steward-2'],
|
||||
gameType: 'iRacing',
|
||||
skillLevel: 'Intermediate',
|
||||
category: 'GT3',
|
||||
tags: ['competitive', 'weekly-races'],
|
||||
};
|
||||
|
||||
const result = await context.createLeagueUseCase.execute(command);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBeDefined();
|
||||
expect(result.name).toBe('Test League');
|
||||
expect(result.ownerId).toBe(driverId);
|
||||
expect(result.status).toBe('active');
|
||||
expect(result.maxDrivers).toBe(20);
|
||||
expect(result.tracks).toEqual(['Monza', 'Spa', 'Nürburgring']);
|
||||
|
||||
const savedLeague = await context.leagueRepository.findById(result.id);
|
||||
expect(savedLeague).toBeDefined();
|
||||
expect(savedLeague?.ownerId).toBe(driverId);
|
||||
|
||||
expect(context.eventPublisher.getLeagueCreatedEventCount()).toBe(1);
|
||||
const events = context.eventPublisher.getLeagueCreatedEvents();
|
||||
expect(events[0].leagueId).toBe(result.id);
|
||||
});
|
||||
|
||||
it('should create a league with minimal configuration', async () => {
|
||||
const driverId = 'driver-123';
|
||||
const command: LeagueCreateCommand = {
|
||||
name: 'Minimal League',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
};
|
||||
|
||||
const result = await context.createLeagueUseCase.execute(command);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.name).toBe('Minimal League');
|
||||
expect(result.status).toBe('active');
|
||||
expect(result.description).toBeNull();
|
||||
expect(context.eventPublisher.getLeagueCreatedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should create a league with public visibility', async () => {
|
||||
const result = await context.createLeague({ name: 'Public League', visibility: 'public' });
|
||||
expect(result.visibility).toBe('public');
|
||||
});
|
||||
|
||||
it('should create a league with private visibility', async () => {
|
||||
const result = await context.createLeague({ name: 'Private League', visibility: 'private' });
|
||||
expect(result.visibility).toBe('private');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
|
||||
describe('League Detail - Success Path', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should retrieve complete league detail with all data', async () => {
|
||||
const driverId = 'driver-123';
|
||||
const league = await context.createLeague({
|
||||
name: 'Complete League',
|
||||
description: 'A league with all data',
|
||||
ownerId: driverId,
|
||||
});
|
||||
|
||||
const result = await context.getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
expect(result.name).toBe('Complete League');
|
||||
expect(context.eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should retrieve league detail with minimal data', async () => {
|
||||
const driverId = 'driver-123';
|
||||
const league = await context.createLeague({ name: 'Minimal League', ownerId: driverId });
|
||||
|
||||
const result = await context.getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.name).toBe('Minimal League');
|
||||
expect(context.eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
|
||||
describe('League Discovery - Search', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should find leagues by name', async () => {
|
||||
await context.createLeague({ name: 'Formula 1' });
|
||||
await context.createLeague({ name: 'GT3 Masters' });
|
||||
|
||||
const results = await context.leagueRepository.search('Formula');
|
||||
expect(results).toHaveLength(1);
|
||||
expect(results[0].name).toBe('Formula 1');
|
||||
});
|
||||
|
||||
it('should find leagues by description', async () => {
|
||||
await context.createLeague({ name: 'League A', description: 'Competitive racing' });
|
||||
await context.createLeague({ name: 'League B', description: 'Casual fun' });
|
||||
|
||||
const results = await context.leagueRepository.search('Competitive');
|
||||
expect(results).toHaveLength(1);
|
||||
expect(results[0].name).toBe('League A');
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,586 +0,0 @@
|
||||
/**
|
||||
* Integration Test: League Detail Use Case Orchestration
|
||||
*
|
||||
* Tests the orchestration logic of league detail-related Use Cases:
|
||||
* - GetLeagueUseCase: Retrieves league details
|
||||
* - 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, beforeEach } from 'vitest';
|
||||
import { InMemoryLeagueRepository } from '../../../adapters/leagues/persistence/inmemory/InMemoryLeagueRepository';
|
||||
import { InMemoryLeagueEventPublisher } from '../../../adapters/leagues/events/InMemoryLeagueEventPublisher';
|
||||
import { GetLeagueUseCase } from '../../../core/leagues/application/use-cases/GetLeagueUseCase';
|
||||
import { CreateLeagueUseCase } from '../../../core/leagues/application/use-cases/CreateLeagueUseCase';
|
||||
import { LeagueCreateCommand } from '../../../core/leagues/application/ports/LeagueCreateCommand';
|
||||
|
||||
describe('League Detail Use Case Orchestration', () => {
|
||||
let leagueRepository: InMemoryLeagueRepository;
|
||||
let eventPublisher: InMemoryLeagueEventPublisher;
|
||||
let getLeagueUseCase: GetLeagueUseCase;
|
||||
let createLeagueUseCase: CreateLeagueUseCase;
|
||||
|
||||
beforeAll(() => {
|
||||
leagueRepository = new InMemoryLeagueRepository();
|
||||
eventPublisher = new InMemoryLeagueEventPublisher();
|
||||
getLeagueUseCase = new GetLeagueUseCase(leagueRepository, eventPublisher);
|
||||
createLeagueUseCase = new CreateLeagueUseCase(leagueRepository, eventPublisher);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
leagueRepository.clear();
|
||||
eventPublisher.clear();
|
||||
});
|
||||
|
||||
describe('GetLeagueDetailUseCase - Success Path', () => {
|
||||
it('should retrieve complete league detail with all data', async () => {
|
||||
// Scenario: League with complete data
|
||||
// Given: A league exists with complete data
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Complete League',
|
||||
description: 'A league with all data',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
maxDrivers: 20,
|
||||
approvalRequired: true,
|
||||
lateJoinAllowed: true,
|
||||
raceFrequency: 'weekly',
|
||||
raceDay: 'Saturday',
|
||||
raceTime: '18:00',
|
||||
tracks: ['Monza', 'Spa'],
|
||||
scoringSystem: { points: [25, 18, 15] },
|
||||
bonusPointsEnabled: true,
|
||||
penaltiesEnabled: true,
|
||||
protestsEnabled: true,
|
||||
appealsEnabled: true,
|
||||
stewardTeam: ['steward-1'],
|
||||
gameType: 'iRacing',
|
||||
skillLevel: 'Intermediate',
|
||||
category: 'GT3',
|
||||
tags: ['competitive'],
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain all league sections
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
expect(result.name).toBe('Complete League');
|
||||
expect(result.description).toBe('A league with all data');
|
||||
expect(result.ownerId).toBe(driverId);
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
const events = eventPublisher.getLeagueAccessedEvents();
|
||||
expect(events[0].leagueId).toBe(league.id);
|
||||
expect(events[0].driverId).toBe(driverId);
|
||||
});
|
||||
|
||||
it('should retrieve league detail with minimal data', async () => {
|
||||
// Scenario: League with minimal data
|
||||
// Given: A league exists with only basic information (name, description, owner)
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Minimal League',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain basic league info
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
expect(result.name).toBe('Minimal League');
|
||||
expect(result.ownerId).toBe(driverId);
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should retrieve league detail with career history but no recent results', async () => {
|
||||
// Scenario: League with career history but no recent results
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Career History League',
|
||||
description: 'A league with career history',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain career history
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should retrieve league detail with recent results but no career history', async () => {
|
||||
// Scenario: League with recent results but no career history
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Recent Results League',
|
||||
description: 'A league with recent results',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain recent race results
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should retrieve league detail with championship standings but no other data', async () => {
|
||||
// Scenario: League with championship standings but no other data
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Championship League',
|
||||
description: 'A league with championship standings',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain championship standings
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should retrieve league detail with social links but no team affiliation', async () => {
|
||||
// Scenario: League with social links but no team affiliation
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Social Links League',
|
||||
description: 'A league with social links',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain social links
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should retrieve league detail with team affiliation but no social links', async () => {
|
||||
// Scenario: League with team affiliation but no social links
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Team Affiliation League',
|
||||
description: 'A league with team affiliation',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain team affiliation
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetLeagueDetailUseCase - Edge Cases', () => {
|
||||
it('should handle league with no career history', async () => {
|
||||
// Scenario: League with no career history
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'No Career History League',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain league profile
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle league with no recent race results', async () => {
|
||||
// Scenario: League with no recent race results
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'No Recent Results League',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain league profile
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle league with no championship standings', async () => {
|
||||
// Scenario: League with no championship standings
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'No Championship League',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain league profile
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle league with no data at all', async () => {
|
||||
// Scenario: League with absolutely no data
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'No Data League',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with league ID
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: The result should contain basic league info
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
expect(result.name).toBe('No Data League');
|
||||
|
||||
// And: EventPublisher should emit LeagueAccessedEvent
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetLeagueDetailUseCase - Error Handling', () => {
|
||||
it('should throw error when league does not exist', async () => {
|
||||
// Scenario: Non-existent league
|
||||
// Given: No league exists with the given ID
|
||||
const nonExistentLeagueId = 'non-existent-league-id';
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with non-existent league ID
|
||||
// Then: Should throw error
|
||||
await expect(getLeagueUseCase.execute({ leagueId: nonExistentLeagueId, driverId: 'driver-123' }))
|
||||
.rejects.toThrow();
|
||||
|
||||
// And: EventPublisher should NOT emit any events
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(0);
|
||||
});
|
||||
|
||||
it('should throw error when league ID is invalid', async () => {
|
||||
// Scenario: Invalid league ID
|
||||
// Given: An invalid league ID (e.g., empty string)
|
||||
const invalidLeagueId = '';
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called with invalid league ID
|
||||
// Then: Should throw error
|
||||
await expect(getLeagueUseCase.execute({ leagueId: invalidLeagueId, driverId: 'driver-123' }))
|
||||
.rejects.toThrow();
|
||||
|
||||
// And: EventPublisher should NOT emit any events
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle repository errors gracefully', async () => {
|
||||
// Scenario: Repository throws error
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Test League',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// And: LeagueRepository throws an error during query
|
||||
const originalFindById = leagueRepository.findById;
|
||||
leagueRepository.findById = async () => {
|
||||
throw new Error('Repository error');
|
||||
};
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called
|
||||
// Then: Should propagate the error appropriately
|
||||
await expect(getLeagueUseCase.execute({ leagueId: league.id, driverId }))
|
||||
.rejects.toThrow('Repository error');
|
||||
|
||||
// And: EventPublisher should NOT emit any events
|
||||
expect(eventPublisher.getLeagueAccessedEventCount()).toBe(0);
|
||||
|
||||
// Restore original method
|
||||
leagueRepository.findById = originalFindById;
|
||||
});
|
||||
});
|
||||
|
||||
describe('League Detail Data Orchestration', () => {
|
||||
it('should correctly calculate league statistics from race results', async () => {
|
||||
// Scenario: League statistics calculation
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Statistics League',
|
||||
description: 'A league for statistics calculation',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: League statistics should show:
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
expect(result.name).toBe('Statistics League');
|
||||
});
|
||||
|
||||
it('should correctly format career history with league and team information', async () => {
|
||||
// Scenario: Career history formatting
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Career History League',
|
||||
description: 'A league for career history formatting',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: Career history should show:
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
expect(result.name).toBe('Career History League');
|
||||
});
|
||||
|
||||
it('should correctly format recent race results with proper details', async () => {
|
||||
// Scenario: Recent race results formatting
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Recent Results League',
|
||||
description: 'A league for recent results formatting',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: Recent race results should show:
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
expect(result.name).toBe('Recent Results League');
|
||||
});
|
||||
|
||||
it('should correctly aggregate championship standings across leagues', async () => {
|
||||
// Scenario: Championship standings aggregation
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Championship League',
|
||||
description: 'A league for championship standings',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: Championship standings should show:
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
expect(result.name).toBe('Championship League');
|
||||
});
|
||||
|
||||
it('should correctly format social links with proper URLs', async () => {
|
||||
// Scenario: Social links formatting
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Social Links League',
|
||||
description: 'A league for social links formatting',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: Social links should show:
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
expect(result.name).toBe('Social Links League');
|
||||
});
|
||||
|
||||
it('should correctly format team affiliation with role', async () => {
|
||||
// Scenario: Team affiliation formatting
|
||||
// Given: A league exists
|
||||
const driverId = 'driver-123';
|
||||
const league = await createLeagueUseCase.execute({
|
||||
name: 'Team Affiliation League',
|
||||
description: 'A league for team affiliation formatting',
|
||||
visibility: 'public',
|
||||
ownerId: driverId,
|
||||
approvalRequired: false,
|
||||
lateJoinAllowed: false,
|
||||
bonusPointsEnabled: false,
|
||||
penaltiesEnabled: false,
|
||||
protestsEnabled: false,
|
||||
appealsEnabled: false,
|
||||
});
|
||||
|
||||
// When: GetLeagueUseCase.execute() is called
|
||||
const result = await getLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
// Then: Team affiliation should show:
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe(league.id);
|
||||
expect(result.name).toBe('Team Affiliation League');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,901 +0,0 @@
|
||||
/**
|
||||
* Integration Test: League Settings Use Case Orchestration
|
||||
*
|
||||
* Tests the orchestration logic of league settings-related Use Cases:
|
||||
* - GetLeagueSettingsUseCase: Retrieves league settings
|
||||
* - UpdateLeagueBasicInfoUseCase: Updates league basic information
|
||||
* - UpdateLeagueStructureUseCase: Updates league structure settings
|
||||
* - UpdateLeagueScoringUseCase: Updates league scoring configuration
|
||||
* - UpdateLeagueStewardingUseCase: Updates league stewarding configuration
|
||||
* - ArchiveLeagueUseCase: Archives a league
|
||||
* - UnarchiveLeagueUseCase: Unarchives a league
|
||||
* - DeleteLeagueUseCase: Deletes a league
|
||||
* - ExportLeagueDataUseCase: Exports league data
|
||||
* - ImportLeagueDataUseCase: Imports league data
|
||||
* - ResetLeagueStatisticsUseCase: Resets league statistics
|
||||
* - ResetLeagueStandingsUseCase: Resets league standings
|
||||
* - ResetLeagueScheduleUseCase: Resets league schedule
|
||||
* - ResetLeagueRosterUseCase: Resets league roster
|
||||
* - ResetLeagueWalletUseCase: Resets league wallet
|
||||
* - ResetLeagueSponsorshipsUseCase: Resets league sponsorships
|
||||
* - ResetLeagueStewardingUseCase: Resets league stewarding
|
||||
* - ResetLeagueProtestsUseCase: Resets league protests
|
||||
* - ResetLeaguePenaltiesUseCase: Resets league penalties
|
||||
* - ResetLeagueAppealsUseCase: Resets league appeals
|
||||
* - ResetLeagueIncidentsUseCase: Resets league incidents
|
||||
* - ResetLeagueEverythingUseCase: Resets everything in the league
|
||||
* - 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 { InMemoryLeagueRepository } from '../../../adapters/leagues/persistence/inmemory/InMemoryLeagueRepository';
|
||||
import { InMemoryDriverRepository } from '../../../adapters/drivers/persistence/inmemory/InMemoryDriverRepository';
|
||||
import { InMemoryEventPublisher } from '../../../adapters/events/InMemoryEventPublisher';
|
||||
import { GetLeagueSettingsUseCase } from '../../../core/leagues/use-cases/GetLeagueSettingsUseCase';
|
||||
import { UpdateLeagueBasicInfoUseCase } from '../../../core/leagues/use-cases/UpdateLeagueBasicInfoUseCase';
|
||||
import { UpdateLeagueStructureUseCase } from '../../../core/leagues/use-cases/UpdateLeagueStructureUseCase';
|
||||
import { UpdateLeagueScoringUseCase } from '../../../core/leagues/use-cases/UpdateLeagueScoringUseCase';
|
||||
import { UpdateLeagueStewardingUseCase } from '../../../core/leagues/use-cases/UpdateLeagueStewardingUseCase';
|
||||
import { ArchiveLeagueUseCase } from '../../../core/leagues/use-cases/ArchiveLeagueUseCase';
|
||||
import { UnarchiveLeagueUseCase } from '../../../core/leagues/use-cases/UnarchiveLeagueUseCase';
|
||||
import { DeleteLeagueUseCase } from '../../../core/leagues/use-cases/DeleteLeagueUseCase';
|
||||
import { ExportLeagueDataUseCase } from '../../../core/leagues/use-cases/ExportLeagueDataUseCase';
|
||||
import { ImportLeagueDataUseCase } from '../../../core/leagues/use-cases/ImportLeagueDataUseCase';
|
||||
import { ResetLeagueStatisticsUseCase } from '../../../core/leagues/use-cases/ResetLeagueStatisticsUseCase';
|
||||
import { ResetLeagueStandingsUseCase } from '../../../core/leagues/use-cases/ResetLeagueStandingsUseCase';
|
||||
import { ResetLeagueScheduleUseCase } from '../../../core/leagues/use-cases/ResetLeagueScheduleUseCase';
|
||||
import { ResetLeagueRosterUseCase } from '../../../core/leagues/use-cases/ResetLeagueRosterUseCase';
|
||||
import { ResetLeagueWalletUseCase } from '../../../core/leagues/use-cases/ResetLeagueWalletUseCase';
|
||||
import { ResetLeagueSponsorshipsUseCase } from '../../../core/leagues/use-cases/ResetLeagueSponsorshipsUseCase';
|
||||
import { ResetLeagueStewardingUseCase } from '../../../core/leagues/use-cases/ResetLeagueStewardingUseCase';
|
||||
import { ResetLeagueProtestsUseCase } from '../../../core/leagues/use-cases/ResetLeagueProtestsUseCase';
|
||||
import { ResetLeaguePenaltiesUseCase } from '../../../core/leagues/use-cases/ResetLeaguePenaltiesUseCase';
|
||||
import { ResetLeagueAppealsUseCase } from '../../../core/leagues/use-cases/ResetLeagueAppealsUseCase';
|
||||
import { ResetLeagueIncidentsUseCase } from '../../../core/leagues/use-cases/ResetLeagueIncidentsUseCase';
|
||||
import { ResetLeagueEverythingUseCase } from '../../../core/leagues/use-cases/ResetLeagueEverythingUseCase';
|
||||
import { LeagueSettingsQuery } from '../../../core/leagues/ports/LeagueSettingsQuery';
|
||||
import { UpdateLeagueBasicInfoCommand } from '../../../core/leagues/ports/UpdateLeagueBasicInfoCommand';
|
||||
import { UpdateLeagueStructureCommand } from '../../../core/leagues/ports/UpdateLeagueStructureCommand';
|
||||
import { UpdateLeagueScoringCommand } from '../../../core/leagues/ports/UpdateLeagueScoringCommand';
|
||||
import { UpdateLeagueStewardingCommand } from '../../../core/leagues/ports/UpdateLeagueStewardingCommand';
|
||||
import { ArchiveLeagueCommand } from '../../../core/leagues/ports/ArchiveLeagueCommand';
|
||||
import { UnarchiveLeagueCommand } from '../../../core/leagues/ports/UnarchiveLeagueCommand';
|
||||
import { DeleteLeagueCommand } from '../../../core/leagues/ports/DeleteLeagueCommand';
|
||||
import { ExportLeagueDataCommand } from '../../../core/leagues/ports/ExportLeagueDataCommand';
|
||||
import { ImportLeagueDataCommand } from '../../../core/leagues/ports/ImportLeagueDataCommand';
|
||||
import { ResetLeagueStatisticsCommand } from '../../../core/leagues/ports/ResetLeagueStatisticsCommand';
|
||||
import { ResetLeagueStandingsCommand } from '../../../core/leagues/ports/ResetLeagueStandingsCommand';
|
||||
import { ResetLeagueScheduleCommand } from '../../../core/leagues/ports/ResetLeagueScheduleCommand';
|
||||
import { ResetLeagueRosterCommand } from '../../../core/leagues/ports/ResetLeagueRosterCommand';
|
||||
import { ResetLeagueWalletCommand } from '../../../core/leagues/ports/ResetLeagueWalletCommand';
|
||||
import { ResetLeagueSponsorshipsCommand } from '../../../core/leagues/ports/ResetLeagueSponsorshipsCommand';
|
||||
import { ResetLeagueStewardingCommand } from '../../../core/leagues/ports/ResetLeagueStewardingCommand';
|
||||
import { ResetLeagueProtestsCommand } from '../../../core/leagues/ports/ResetLeagueProtestsCommand';
|
||||
import { ResetLeaguePenaltiesCommand } from '../../../core/leagues/ports/ResetLeaguePenaltiesCommand';
|
||||
import { ResetLeagueAppealsCommand } from '../../../core/leagues/ports/ResetLeagueAppealsCommand';
|
||||
import { ResetLeagueIncidentsCommand } from '../../../core/leagues/ports/ResetLeagueIncidentsCommand';
|
||||
import { ResetLeagueEverythingCommand } from '../../../core/leagues/ports/ResetLeagueEverythingCommand';
|
||||
|
||||
describe('League Settings Use Case Orchestration', () => {
|
||||
let leagueRepository: InMemoryLeagueRepository;
|
||||
let driverRepository: InMemoryDriverRepository;
|
||||
let eventPublisher: InMemoryEventPublisher;
|
||||
let getLeagueSettingsUseCase: GetLeagueSettingsUseCase;
|
||||
let updateLeagueBasicInfoUseCase: UpdateLeagueBasicInfoUseCase;
|
||||
let updateLeagueStructureUseCase: UpdateLeagueStructureUseCase;
|
||||
let updateLeagueScoringUseCase: UpdateLeagueScoringUseCase;
|
||||
let updateLeagueStewardingUseCase: UpdateLeagueStewardingUseCase;
|
||||
let archiveLeagueUseCase: ArchiveLeagueUseCase;
|
||||
let unarchiveLeagueUseCase: UnarchiveLeagueUseCase;
|
||||
let deleteLeagueUseCase: DeleteLeagueUseCase;
|
||||
let exportLeagueDataUseCase: ExportLeagueDataUseCase;
|
||||
let importLeagueDataUseCase: ImportLeagueDataUseCase;
|
||||
let resetLeagueStatisticsUseCase: ResetLeagueStatisticsUseCase;
|
||||
let resetLeagueStandingsUseCase: ResetLeagueStandingsUseCase;
|
||||
let resetLeagueScheduleUseCase: ResetLeagueScheduleUseCase;
|
||||
let resetLeagueRosterUseCase: ResetLeagueRosterUseCase;
|
||||
let resetLeagueWalletUseCase: ResetLeagueWalletUseCase;
|
||||
let resetLeagueSponsorshipsUseCase: ResetLeagueSponsorshipsUseCase;
|
||||
let resetLeagueStewardingUseCase: ResetLeagueStewardingUseCase;
|
||||
let resetLeagueProtestsUseCase: ResetLeagueProtestsUseCase;
|
||||
let resetLeaguePenaltiesUseCase: ResetLeaguePenaltiesUseCase;
|
||||
let resetLeagueAppealsUseCase: ResetLeagueAppealsUseCase;
|
||||
let resetLeagueIncidentsUseCase: ResetLeagueIncidentsUseCase;
|
||||
let resetLeagueEverythingUseCase: ResetLeagueEverythingUseCase;
|
||||
|
||||
beforeAll(() => {
|
||||
// TODO: Initialize In-Memory repositories and event publisher
|
||||
// leagueRepository = new InMemoryLeagueRepository();
|
||||
// driverRepository = new InMemoryDriverRepository();
|
||||
// eventPublisher = new InMemoryEventPublisher();
|
||||
// getLeagueSettingsUseCase = new GetLeagueSettingsUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// updateLeagueBasicInfoUseCase = new UpdateLeagueBasicInfoUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// updateLeagueStructureUseCase = new UpdateLeagueStructureUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// updateLeagueScoringUseCase = new UpdateLeagueScoringUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// updateLeagueStewardingUseCase = new UpdateLeagueStewardingUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// archiveLeagueUseCase = new ArchiveLeagueUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// unarchiveLeagueUseCase = new UnarchiveLeagueUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// deleteLeagueUseCase = new DeleteLeagueUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// exportLeagueDataUseCase = new ExportLeagueDataUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// importLeagueDataUseCase = new ImportLeagueDataUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueStatisticsUseCase = new ResetLeagueStatisticsUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueStandingsUseCase = new ResetLeagueStandingsUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueScheduleUseCase = new ResetLeagueScheduleUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueRosterUseCase = new ResetLeagueRosterUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueWalletUseCase = new ResetLeagueWalletUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueSponsorshipsUseCase = new ResetLeagueSponsorshipsUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueStewardingUseCase = new ResetLeagueStewardingUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueProtestsUseCase = new ResetLeagueProtestsUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeaguePenaltiesUseCase = new ResetLeaguePenaltiesUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueAppealsUseCase = new ResetLeagueAppealsUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueIncidentsUseCase = new ResetLeagueIncidentsUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// resetLeagueEverythingUseCase = new ResetLeagueEverythingUseCase({
|
||||
// leagueRepository,
|
||||
// driverRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// TODO: Clear all In-Memory repositories before each test
|
||||
// leagueRepository.clear();
|
||||
// driverRepository.clear();
|
||||
// eventPublisher.clear();
|
||||
});
|
||||
|
||||
describe('GetLeagueSettingsUseCase - Success Path', () => {
|
||||
it('should retrieve league basic information', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league basic information
|
||||
// Given: A league exists with basic information
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league name
|
||||
// And: The result should contain the league description
|
||||
// And: The result should contain the league visibility
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league structure settings', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league structure settings
|
||||
// Given: A league exists with structure settings
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain max drivers
|
||||
// And: The result should contain approval requirement
|
||||
// And: The result should contain late join option
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league scoring configuration', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league scoring configuration
|
||||
// Given: A league exists with scoring configuration
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain scoring preset
|
||||
// And: The result should contain custom points
|
||||
// And: The result should contain bonus points configuration
|
||||
// And: The result should contain penalty configuration
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding configuration', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding configuration
|
||||
// Given: A league exists with stewarding configuration
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain protest configuration
|
||||
// And: The result should contain appeal configuration
|
||||
// And: The result should contain steward team
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league creation date', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league creation date
|
||||
// Given: A league exists with creation date
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league creation date
|
||||
// And: The date should be formatted correctly
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league last updated date', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league last updated date
|
||||
// Given: A league exists with last updated date
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league last updated date
|
||||
// And: The date should be formatted correctly
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league owner information', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league owner information
|
||||
// Given: A league exists with owner information
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league owner information
|
||||
// And: The owner should be clickable to view their profile
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league member count', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league member count
|
||||
// Given: A league exists with members
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league member count
|
||||
// And: The count should be accurate
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league race count', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league race count
|
||||
// Given: A league exists with races
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league race count
|
||||
// And: The count should be accurate
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league sponsor count', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league sponsor count
|
||||
// Given: A league exists with sponsors
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league sponsor count
|
||||
// And: The count should be accurate
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league wallet balance', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league wallet balance
|
||||
// Given: A league exists with wallet balance
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league wallet balance
|
||||
// And: The balance should be displayed as currency amount
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league total revenue', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league total revenue
|
||||
// Given: A league exists with total revenue
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league total revenue
|
||||
// And: The revenue should be displayed as currency amount
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league total fees', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league total fees
|
||||
// Given: A league exists with total fees
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league total fees
|
||||
// And: The fees should be displayed as currency amount
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league pending payouts', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league pending payouts
|
||||
// Given: A league exists with pending payouts
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league pending payouts
|
||||
// And: The payouts should be displayed as currency amount
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league net balance', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league net balance
|
||||
// Given: A league exists with net balance
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league net balance
|
||||
// And: The net balance should be displayed as currency amount
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league transaction count', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league transaction count
|
||||
// Given: A league exists with transaction count
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league transaction count
|
||||
// And: The count should be accurate
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league average transaction amount', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league average transaction amount
|
||||
// Given: A league exists with average transaction amount
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league average transaction amount
|
||||
// And: The amount should be displayed as currency amount
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league total race time', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league total race time
|
||||
// Given: A league exists with total race time
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league total race time
|
||||
// And: The time should be formatted correctly
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league average race time', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league average race time
|
||||
// Given: A league exists with average race time
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league average race time
|
||||
// And: The time should be formatted correctly
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league best lap time', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league best lap time
|
||||
// Given: A league exists with best lap time
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league best lap time
|
||||
// And: The time should be formatted correctly
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league average lap time', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league average lap time
|
||||
// Given: A league exists with average lap time
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league average lap time
|
||||
// And: The time should be formatted correctly
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league consistency score', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league consistency score
|
||||
// Given: A league exists with consistency score
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league consistency score
|
||||
// And: The score should be displayed as percentage or numeric value
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league aggression score', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league aggression score
|
||||
// Given: A league exists with aggression score
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league aggression score
|
||||
// And: The score should be displayed as percentage or numeric value
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league safety score', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league safety score
|
||||
// Given: A league exists with safety score
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league safety score
|
||||
// And: The score should be displayed as percentage or numeric value
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league racecraft score', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league racecraft score
|
||||
// Given: A league exists with racecraft score
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league racecraft score
|
||||
// And: The score should be displayed as percentage or numeric value
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league overall rating', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league overall rating
|
||||
// Given: A league exists with overall rating
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league overall rating
|
||||
// And: The rating should be displayed as stars or numeric value
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league rating trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league rating trend
|
||||
// Given: A league exists with rating trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league rating trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league rank trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league rank trend
|
||||
// Given: A league exists with rank trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league rank trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league points trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league points trend
|
||||
// Given: A league exists with points trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league points trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league win rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league win rate trend
|
||||
// Given: A league exists with win rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league win rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league podium rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league podium rate trend
|
||||
// Given: A league exists with podium rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league podium rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league DNF rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league DNF rate trend
|
||||
// Given: A league exists with DNF rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league DNF rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league incident rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league incident rate trend
|
||||
// Given: A league exists with incident rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league incident rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league penalty rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league penalty rate trend
|
||||
// Given: A league exists with penalty rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league penalty rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league protest rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league protest rate trend
|
||||
// Given: A league exists with protest rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league protest rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action rate trend
|
||||
// Given: A league exists with stewarding action rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding time trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding time trend
|
||||
// Given: A league exists with stewarding time trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding time trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league protest resolution time trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league protest resolution time trend
|
||||
// Given: A league exists with protest resolution time trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league protest resolution time trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league penalty appeal success rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league penalty appeal success rate trend
|
||||
// Given: A league exists with penalty appeal success rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league penalty appeal success rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league protest success rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league protest success rate trend
|
||||
// Given: A league exists with protest success rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league protest success rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action success rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action success rate trend
|
||||
// Given: A league exists with stewarding action success rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action success rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action appeal success rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action appeal success rate trend
|
||||
// Given: A league exists with stewarding action appeal success rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action appeal success rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action penalty success rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action penalty success rate trend
|
||||
// Given: A league exists with stewarding action penalty success rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action penalty success rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action protest success rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action protest success rate trend
|
||||
// Given: A league exists with stewarding action protest success rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action protest success rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action appeal penalty success rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action appeal penalty success rate trend
|
||||
// Given: A league exists with stewarding action appeal penalty success rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action appeal penalty success rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action appeal protest success rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action appeal protest success rate trend
|
||||
// Given: A league exists with stewarding action appeal protest success rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action appeal protest success rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action penalty protest success rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action penalty protest success rate trend
|
||||
// Given: A league exists with stewarding action penalty protest success rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action penalty protest success rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action appeal penalty protest success rate trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action appeal penalty protest success rate trend
|
||||
// Given: A league exists with stewarding action appeal penalty protest success rate trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action appeal penalty protest success rate trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action appeal penalty protest resolution time trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action appeal penalty protest resolution time trend
|
||||
// Given: A league exists with stewarding action appeal penalty protest resolution time trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action appeal penalty protest resolution time trend
|
||||
// And: The trend should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding action appeal penalty protest success rate and resolution time trend', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Admin views league stewarding action appeal penalty protest success rate and resolution time trend
|
||||
// Given: A league exists with stewarding action appeal penalty protest success rate and resolution time trend
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain the league stewarding action appeal penalty protest success rate trend
|
||||
// And: The result should contain the league stewarding action appeal penalty protest resolution time trend
|
||||
// And: Trends should show improvement or decline
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetLeagueSettingsUseCase - Edge Cases', () => {
|
||||
it('should handle league with no statistics', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: League with no statistics
|
||||
// Given: A league exists
|
||||
// And: The league has no statistics
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain league settings
|
||||
// And: Statistics sections should be empty or show default values
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should handle league with no financial data', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: League with no financial data
|
||||
// Given: A league exists
|
||||
// And: The league has no financial data
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain league settings
|
||||
// And: Financial sections should be empty or show default values
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should handle league with no trend data', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: League with no trend data
|
||||
// Given: A league exists
|
||||
// And: The league has no trend data
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain league settings
|
||||
// And: Trend sections should be empty or show default values
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
|
||||
it('should handle league with no data at all', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: League with absolutely no data
|
||||
// Given: A league exists
|
||||
// And: The league has no statistics
|
||||
// And: The league has no financial data
|
||||
// And: The league has no trend data
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with league ID
|
||||
// Then: The result should contain basic league settings
|
||||
// And: All sections should be empty or show default values
|
||||
// And: EventPublisher should emit LeagueSettingsAccessedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetLeagueSettingsUseCase - Error Handling', () => {
|
||||
it('should throw error when league does not exist', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Non-existent league
|
||||
// Given: No league exists with the given ID
|
||||
// When: GetLeagueSettingsUseCase.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: An invalid league ID (e.g., empty string, null, undefined)
|
||||
// When: GetLeagueSettingsUseCase.execute() is called with invalid league ID
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should handle repository errors gracefully', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Repository throws error
|
||||
// Given: A league exists
|
||||
// And: LeagueRepository throws an error during query
|
||||
// When: GetLeagueSettingsUseCase.execute() is called
|
||||
// Then: Should propagate the error appropriately
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
});
|
||||
|
||||
describe('League Settings Data Orchestration', () => {
|
||||
it('should correctly calculate league statistics from race results', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: League statistics calculation
|
||||
// Given: A league exists
|
||||
// And: The league has 10 completed races
|
||||
// And: The league has 3 wins
|
||||
// And: The league has 5 podiums
|
||||
// When: GetLeagueSettingsUseCase.execute() is called
|
||||
// Then: League statistics should show:
|
||||
// - Starts: 10
|
||||
// - Wins: 3
|
||||
// - Podiums: 5
|
||||
// - Rating: Calculated based on performance
|
||||
// - Rank: Calculated based on rating
|
||||
});
|
||||
|
||||
it('should correctly format career history with league and team information', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Career history formatting
|
||||
// Given: A league exists
|
||||
// And: The league has participated in 2 leagues
|
||||
// And: The league has been on 3 teams across seasons
|
||||
// When: GetLeagueSettingsUseCase.execute() is called
|
||||
// Then: Career history should show:
|
||||
// - League A: Season 2024, Team X
|
||||
// - League B: Season 2024, Team Y
|
||||
// - League A: Season 2023, Team Z
|
||||
});
|
||||
|
||||
it('should correctly format recent race results with proper details', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Recent race results formatting
|
||||
// Given: A league exists
|
||||
// And: The league has 5 recent race results
|
||||
// When: GetLeagueSettingsUseCase.execute() is called
|
||||
// Then: Recent race results should show:
|
||||
// - Race name
|
||||
// - Track name
|
||||
// - Finishing position
|
||||
// - Points earned
|
||||
// - Race date (sorted newest first)
|
||||
});
|
||||
|
||||
it('should correctly aggregate championship standings across leagues', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Championship standings aggregation
|
||||
// Given: A league exists
|
||||
// And: The league is in 2 championships
|
||||
// And: In Championship A: Position 5, 150 points, 20 drivers
|
||||
// And: In Championship B: Position 12, 85 points, 15 drivers
|
||||
// When: GetLeagueSettingsUseCase.execute() is called
|
||||
// Then: Championship standings should show:
|
||||
// - League A: Position 5, 150 points, 20 drivers
|
||||
// - League B: Position 12, 85 points, 15 drivers
|
||||
});
|
||||
|
||||
it('should correctly format social links with proper URLs', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Social links formatting
|
||||
// Given: A league exists
|
||||
// And: The league has social links (Discord, Twitter, iRacing)
|
||||
// When: GetLeagueSettingsUseCase.execute() is called
|
||||
// Then: Social links should show:
|
||||
// - Discord: https://discord.gg/username
|
||||
// - Twitter: https://twitter.com/username
|
||||
// - iRacing: https://members.iracing.com/membersite/member/profile?username=username
|
||||
});
|
||||
|
||||
it('should correctly format team affiliation with role', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team affiliation formatting
|
||||
// Given: A league exists
|
||||
// And: The league is affiliated with Team XYZ
|
||||
// And: The league's role is "Driver"
|
||||
// When: GetLeagueSettingsUseCase.execute() is called
|
||||
// Then: Team affiliation should show:
|
||||
// - Team name: Team XYZ
|
||||
// - Team logo: (if available)
|
||||
// - Driver role: Driver
|
||||
});
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
129
tests/integration/leagues/roster/league-roster-actions.test.ts
Normal file
129
tests/integration/leagues/roster/league-roster-actions.test.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
|
||||
describe('League Roster - Actions', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should allow a driver to join a public league without approval', async () => {
|
||||
const league = await context.createLeague({ approvalRequired: false });
|
||||
const driverId = 'driver-joiner';
|
||||
|
||||
context.driverRepository.addDriver({
|
||||
id: driverId,
|
||||
name: 'Joiner Driver',
|
||||
rating: 1500,
|
||||
rank: 100,
|
||||
avatar: undefined,
|
||||
starts: 0,
|
||||
wins: 0,
|
||||
podiums: 0,
|
||||
leagues: 0
|
||||
});
|
||||
|
||||
await context.joinLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
const members = await context.leagueRepository.getLeagueMembers(league.id);
|
||||
expect(members.some(m => m.driverId === driverId)).toBe(true);
|
||||
});
|
||||
|
||||
it('should create a pending request when joining a league requiring approval', async () => {
|
||||
const league = await context.createLeague({ approvalRequired: true });
|
||||
const driverId = 'driver-requester';
|
||||
|
||||
context.driverRepository.addDriver({
|
||||
id: driverId,
|
||||
name: 'Requester Driver',
|
||||
rating: 1500,
|
||||
rank: 100,
|
||||
avatar: undefined,
|
||||
starts: 0,
|
||||
wins: 0,
|
||||
podiums: 0,
|
||||
leagues: 0
|
||||
});
|
||||
|
||||
await context.joinLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
const requests = await context.leagueRepository.getPendingRequests(league.id);
|
||||
expect(requests.some(r => r.driverId === driverId)).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow an admin to approve a membership request', async () => {
|
||||
const ownerId = 'driver-owner';
|
||||
const league = await context.createLeague({ ownerId, approvalRequired: true });
|
||||
const driverId = 'driver-requester';
|
||||
|
||||
context.driverRepository.addDriver({
|
||||
id: driverId,
|
||||
name: 'Requester Driver',
|
||||
rating: 1500,
|
||||
rank: 100,
|
||||
avatar: undefined,
|
||||
starts: 0,
|
||||
wins: 0,
|
||||
podiums: 0,
|
||||
leagues: 0
|
||||
});
|
||||
await context.joinLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
const requests = await context.leagueRepository.getPendingRequests(league.id);
|
||||
const requestId = requests[0].id;
|
||||
|
||||
await context.approveMembershipRequestUseCase.execute({ leagueId: league.id, requestId });
|
||||
|
||||
const members = await context.leagueRepository.getLeagueMembers(league.id);
|
||||
expect(members.some(m => m.driverId === driverId)).toBe(true);
|
||||
|
||||
const updatedRequests = await context.leagueRepository.getPendingRequests(league.id);
|
||||
expect(updatedRequests).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should allow an admin to reject a membership request', async () => {
|
||||
const ownerId = 'driver-owner';
|
||||
const league = await context.createLeague({ ownerId, approvalRequired: true });
|
||||
const driverId = 'driver-requester';
|
||||
|
||||
context.driverRepository.addDriver({
|
||||
id: driverId,
|
||||
name: 'Requester Driver',
|
||||
rating: 1500,
|
||||
rank: 100,
|
||||
avatar: undefined,
|
||||
starts: 0,
|
||||
wins: 0,
|
||||
podiums: 0,
|
||||
leagues: 0
|
||||
});
|
||||
await context.joinLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
const requests = await context.leagueRepository.getPendingRequests(league.id);
|
||||
const requestId = requests[0].id;
|
||||
|
||||
await context.rejectMembershipRequestUseCase.execute({ leagueId: league.id, requestId });
|
||||
|
||||
const members = await context.leagueRepository.getLeagueMembers(league.id);
|
||||
expect(members.some(m => m.driverId === driverId)).toBe(false);
|
||||
|
||||
const updatedRequests = await context.leagueRepository.getPendingRequests(league.id);
|
||||
expect(updatedRequests).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should allow a driver to leave a league', async () => {
|
||||
const league = await context.createLeague();
|
||||
const driverId = 'driver-leaver';
|
||||
|
||||
context.leagueRepository.addLeagueMembers(league.id, [
|
||||
{ driverId, name: 'Leaver', role: 'member', joinDate: new Date() }
|
||||
]);
|
||||
|
||||
await context.leaveLeagueUseCase.execute({ leagueId: league.id, driverId });
|
||||
|
||||
const members = await context.leagueRepository.getLeagueMembers(league.id);
|
||||
expect(members.some(m => m.driverId === driverId)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
|
||||
describe('League Roster - Member Management', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should allow an admin to promote a member to admin', async () => {
|
||||
const ownerId = 'driver-owner';
|
||||
const league = await context.createLeague({ ownerId });
|
||||
const driverId = 'driver-member';
|
||||
|
||||
context.leagueRepository.addLeagueMembers(league.id, [
|
||||
{ driverId: ownerId, name: 'Owner', role: 'owner', joinDate: new Date() },
|
||||
{ driverId: driverId, name: 'Member', role: 'member', joinDate: new Date() },
|
||||
]);
|
||||
|
||||
await context.promoteMemberUseCase.execute({ leagueId: league.id, targetDriverId: driverId });
|
||||
|
||||
const members = await context.leagueRepository.getLeagueMembers(league.id);
|
||||
const promotedMember = members.find(m => m.driverId === driverId);
|
||||
expect(promotedMember?.role).toBe('admin');
|
||||
});
|
||||
|
||||
it('should allow an admin to demote an admin to member', async () => {
|
||||
const ownerId = 'driver-owner';
|
||||
const league = await context.createLeague({ ownerId });
|
||||
const adminId = 'driver-admin';
|
||||
|
||||
context.leagueRepository.addLeagueMembers(league.id, [
|
||||
{ driverId: ownerId, name: 'Owner', role: 'owner', joinDate: new Date() },
|
||||
{ driverId: adminId, name: 'Admin', role: 'admin', joinDate: new Date() },
|
||||
]);
|
||||
|
||||
await context.demoteAdminUseCase.execute({ leagueId: league.id, targetDriverId: adminId });
|
||||
|
||||
const members = await context.leagueRepository.getLeagueMembers(league.id);
|
||||
const demotedAdmin = members.find(m => m.driverId === adminId);
|
||||
expect(demotedAdmin?.role).toBe('member');
|
||||
});
|
||||
|
||||
it('should allow an admin to remove a member', async () => {
|
||||
const ownerId = 'driver-owner';
|
||||
const league = await context.createLeague({ ownerId });
|
||||
const driverId = 'driver-member';
|
||||
|
||||
context.leagueRepository.addLeagueMembers(league.id, [
|
||||
{ driverId: ownerId, name: 'Owner', role: 'owner', joinDate: new Date() },
|
||||
{ driverId: driverId, name: 'Member', role: 'member', joinDate: new Date() },
|
||||
]);
|
||||
|
||||
await context.removeMemberUseCase.execute({ leagueId: league.id, targetDriverId: driverId });
|
||||
|
||||
const members = await context.leagueRepository.getLeagueMembers(league.id);
|
||||
expect(members.some(m => m.driverId === driverId)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
|
||||
describe('League Roster - Success Path', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should retrieve complete league roster with all members', async () => {
|
||||
const leagueId = 'league-123';
|
||||
const ownerId = 'driver-1';
|
||||
const adminId = 'driver-2';
|
||||
const driverId = 'driver-3';
|
||||
|
||||
await context.leagueRepository.create({
|
||||
id: leagueId,
|
||||
name: 'Test League',
|
||||
description: null,
|
||||
visibility: 'public',
|
||||
ownerId,
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
maxDrivers: null,
|
||||
approvalRequired: true,
|
||||
lateJoinAllowed: true,
|
||||
raceFrequency: null,
|
||||
raceDay: null,
|
||||
raceTime: null,
|
||||
tracks: null,
|
||||
scoringSystem: null,
|
||||
bonusPointsEnabled: true,
|
||||
penaltiesEnabled: true,
|
||||
protestsEnabled: true,
|
||||
appealsEnabled: true,
|
||||
stewardTeam: null,
|
||||
gameType: null,
|
||||
skillLevel: null,
|
||||
category: null,
|
||||
tags: null,
|
||||
});
|
||||
|
||||
context.leagueRepository.addLeagueMembers(leagueId, [
|
||||
{ driverId: ownerId, name: 'Owner Driver', role: 'owner', joinDate: new Date('2024-01-01') },
|
||||
{ driverId: adminId, name: 'Admin Driver', role: 'admin', joinDate: new Date('2024-01-15') },
|
||||
{ driverId: driverId, name: 'Regular Driver', role: 'member', joinDate: new Date('2024-02-01') },
|
||||
]);
|
||||
|
||||
context.leagueRepository.addPendingRequests(leagueId, [
|
||||
{ id: 'request-1', driverId: 'driver-4', name: 'Pending Driver', requestDate: new Date('2024-02-15') },
|
||||
]);
|
||||
|
||||
const result = await context.getLeagueRosterUseCase.execute({ leagueId });
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.members).toHaveLength(3);
|
||||
expect(result.pendingRequests).toHaveLength(1);
|
||||
expect(result.stats.adminCount).toBe(2);
|
||||
expect(result.stats.driverCount).toBe(1);
|
||||
expect(context.eventPublisher.getLeagueRosterAccessedEventCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('should retrieve league roster with minimal members', async () => {
|
||||
const ownerId = 'driver-owner';
|
||||
const league = await context.createLeague({ ownerId });
|
||||
|
||||
context.leagueRepository.addLeagueMembers(league.id, [
|
||||
{ driverId: ownerId, name: 'Owner Driver', role: 'owner', joinDate: new Date('2024-01-01') },
|
||||
]);
|
||||
|
||||
const result = await context.getLeagueRosterUseCase.execute({ leagueId: league.id });
|
||||
|
||||
expect(result.members).toHaveLength(1);
|
||||
expect(result.members[0].role).toBe('owner');
|
||||
expect(result.stats.adminCount).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
|
||||
describe('League Settings - Basic Info', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should retrieve league basic information', async () => {
|
||||
const league = await context.createLeague({
|
||||
name: 'Test League',
|
||||
description: 'Test Description',
|
||||
visibility: 'public',
|
||||
});
|
||||
|
||||
const result = await context.leagueRepository.findById(league.id);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result?.name).toBe('Test League');
|
||||
expect(result?.description).toBe('Test Description');
|
||||
expect(result?.visibility).toBe('public');
|
||||
});
|
||||
|
||||
it('should update league basic information', async () => {
|
||||
const league = await context.createLeague({ name: 'Old Name' });
|
||||
|
||||
await context.leagueRepository.update(league.id, { name: 'New Name', description: 'New Description' });
|
||||
|
||||
const updated = await context.leagueRepository.findById(league.id);
|
||||
expect(updated?.name).toBe('New Name');
|
||||
expect(updated?.description).toBe('New Description');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
|
||||
describe('League Settings - Scoring', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should retrieve league scoring configuration', async () => {
|
||||
const league = await context.createLeague({
|
||||
scoringSystem: { points: [10, 8, 6] },
|
||||
bonusPointsEnabled: true,
|
||||
penaltiesEnabled: true,
|
||||
});
|
||||
|
||||
const result = await context.leagueRepository.findById(league.id);
|
||||
|
||||
expect(result?.scoringSystem).toEqual({ points: [10, 8, 6] });
|
||||
expect(result?.bonusPointsEnabled).toBe(true);
|
||||
expect(result?.penaltiesEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should update league scoring configuration', async () => {
|
||||
const league = await context.createLeague({ bonusPointsEnabled: false });
|
||||
|
||||
await context.leagueRepository.update(league.id, { bonusPointsEnabled: true, scoringSystem: { points: [25, 18] } });
|
||||
|
||||
const updated = await context.leagueRepository.findById(league.id);
|
||||
expect(updated?.bonusPointsEnabled).toBe(true);
|
||||
expect(updated?.scoringSystem).toEqual({ points: [25, 18] });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
|
||||
describe('League Settings - Stewarding', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should retrieve league stewarding configuration', async () => {
|
||||
const league = await context.createLeague({
|
||||
protestsEnabled: true,
|
||||
appealsEnabled: false,
|
||||
stewardTeam: ['steward-1'],
|
||||
});
|
||||
|
||||
const result = await context.leagueRepository.findById(league.id);
|
||||
|
||||
expect(result?.protestsEnabled).toBe(true);
|
||||
expect(result?.appealsEnabled).toBe(false);
|
||||
expect(result?.stewardTeam).toEqual(['steward-1']);
|
||||
});
|
||||
|
||||
it('should update league stewarding configuration', async () => {
|
||||
const league = await context.createLeague({ protestsEnabled: false });
|
||||
|
||||
await context.leagueRepository.update(league.id, { protestsEnabled: true, stewardTeam: ['steward-2'] });
|
||||
|
||||
const updated = await context.leagueRepository.findById(league.id);
|
||||
expect(updated?.protestsEnabled).toBe(true);
|
||||
expect(updated?.stewardTeam).toEqual(['steward-2']);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeaguesTestContext } from '../LeaguesTestContext';
|
||||
|
||||
describe('League Settings - Structure', () => {
|
||||
let context: LeaguesTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new LeaguesTestContext();
|
||||
context.clear();
|
||||
});
|
||||
|
||||
it('should retrieve league structure settings', async () => {
|
||||
const league = await context.createLeague({
|
||||
maxDrivers: 30,
|
||||
approvalRequired: true,
|
||||
lateJoinAllowed: false,
|
||||
});
|
||||
|
||||
const result = await context.leagueRepository.findById(league.id);
|
||||
|
||||
expect(result?.maxDrivers).toBe(30);
|
||||
expect(result?.approvalRequired).toBe(true);
|
||||
expect(result?.lateJoinAllowed).toBe(false);
|
||||
});
|
||||
|
||||
it('should update league structure settings', async () => {
|
||||
const league = await context.createLeague({ maxDrivers: 20 });
|
||||
|
||||
await context.leagueRepository.update(league.id, { maxDrivers: 40, approvalRequired: true });
|
||||
|
||||
const updated = await context.leagueRepository.findById(league.id);
|
||||
expect(updated?.maxDrivers).toBe(40);
|
||||
expect(updated?.approvalRequired).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user