integration tests
This commit is contained in:
@@ -1,344 +1,403 @@
|
||||
/**
|
||||
* Integration Test: Team Creation Use Case Orchestration
|
||||
*
|
||||
*
|
||||
* Tests the orchestration logic of team creation-related Use Cases:
|
||||
* - CreateTeamUseCase: Creates a new team with name, description, logo, league, tier, and roster size
|
||||
* - Validates that Use Cases correctly interact with their Ports (Repositories, Event Publishers, File Storage)
|
||||
* - CreateTeamUseCase: Creates a new team with name, description, and leagues
|
||||
* - Validates that Use Cases correctly interact with their Ports (Repositories)
|
||||
* - 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 { InMemoryTeamRepository } from '../../../adapters/teams/persistence/inmemory/InMemoryTeamRepository';
|
||||
import { InMemoryDriverRepository } from '../../../adapters/drivers/persistence/inmemory/InMemoryDriverRepository';
|
||||
import { InMemoryLeagueRepository } from '../../../adapters/leagues/persistence/inmemory/InMemoryLeagueRepository';
|
||||
import { InMemoryEventPublisher } from '../../../adapters/events/InMemoryEventPublisher';
|
||||
import { InMemoryFileStorage } from '../../../adapters/files/InMemoryFileStorage';
|
||||
import { CreateTeamUseCase } from '../../../core/teams/use-cases/CreateTeamUseCase';
|
||||
import { CreateTeamCommand } from '../../../core/teams/ports/CreateTeamCommand';
|
||||
import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
|
||||
import { InMemoryTeamRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryTeamRepository';
|
||||
import { InMemoryTeamMembershipRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryTeamMembershipRepository';
|
||||
import { CreateTeamUseCase } from '../../../core/racing/application/use-cases/CreateTeamUseCase';
|
||||
import { Team } from '../../../core/racing/domain/entities/Team';
|
||||
import { Driver } from '../../../core/racing/domain/entities/Driver';
|
||||
import { League } from '../../../core/racing/domain/entities/League';
|
||||
import { Logger } from '../../../core/shared/domain/Logger';
|
||||
|
||||
describe('Team Creation Use Case Orchestration', () => {
|
||||
let teamRepository: InMemoryTeamRepository;
|
||||
let driverRepository: InMemoryDriverRepository;
|
||||
let leagueRepository: InMemoryLeagueRepository;
|
||||
let eventPublisher: InMemoryEventPublisher;
|
||||
let fileStorage: InMemoryFileStorage;
|
||||
let membershipRepository: InMemoryTeamMembershipRepository;
|
||||
let createTeamUseCase: CreateTeamUseCase;
|
||||
let mockLogger: Logger;
|
||||
|
||||
beforeAll(() => {
|
||||
// TODO: Initialize In-Memory repositories, event publisher, and file storage
|
||||
// teamRepository = new InMemoryTeamRepository();
|
||||
// driverRepository = new InMemoryDriverRepository();
|
||||
// leagueRepository = new InMemoryLeagueRepository();
|
||||
// eventPublisher = new InMemoryEventPublisher();
|
||||
// fileStorage = new InMemoryFileStorage();
|
||||
// createTeamUseCase = new CreateTeamUseCase({
|
||||
// teamRepository,
|
||||
// driverRepository,
|
||||
// leagueRepository,
|
||||
// eventPublisher,
|
||||
// fileStorage,
|
||||
// });
|
||||
mockLogger = {
|
||||
info: () => {},
|
||||
debug: () => {},
|
||||
warn: () => {},
|
||||
error: () => {},
|
||||
} as unknown as Logger;
|
||||
|
||||
teamRepository = new InMemoryTeamRepository(mockLogger);
|
||||
membershipRepository = new InMemoryTeamMembershipRepository(mockLogger);
|
||||
createTeamUseCase = new CreateTeamUseCase(teamRepository, membershipRepository, mockLogger);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// TODO: Clear all In-Memory repositories before each test
|
||||
// teamRepository.clear();
|
||||
// driverRepository.clear();
|
||||
// leagueRepository.clear();
|
||||
// eventPublisher.clear();
|
||||
// fileStorage.clear();
|
||||
teamRepository.clear();
|
||||
membershipRepository.clear();
|
||||
});
|
||||
|
||||
describe('CreateTeamUseCase - Success Path', () => {
|
||||
it('should create a team with all required fields', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with complete information
|
||||
// Given: A driver exists
|
||||
const driverId = 'd1';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '1', name: 'John Doe', country: 'US' });
|
||||
|
||||
// And: A league exists
|
||||
// And: A tier exists
|
||||
const leagueId = 'l1';
|
||||
const league = League.create({ id: leagueId, name: 'League 1', description: 'Test League', ownerId: 'owner' });
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called with valid command
|
||||
// Then: The team should be created in the repository
|
||||
// And: The team should have the correct name, description, and settings
|
||||
// And: The team should be associated with the correct driver as captain
|
||||
// And: The team should be associated with the correct league
|
||||
// And: EventPublisher should emit TeamCreatedEvent
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'Test Team',
|
||||
tag: 'TT',
|
||||
description: 'A test team',
|
||||
ownerId: driverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
|
||||
// Then: The team should be created successfully
|
||||
expect(result.isOk()).toBe(true);
|
||||
const { team } = result.unwrap();
|
||||
|
||||
// And: The team should have the correct properties
|
||||
expect(team.name.toString()).toBe('Test Team');
|
||||
expect(team.tag.toString()).toBe('TT');
|
||||
expect(team.description.toString()).toBe('A test team');
|
||||
expect(team.ownerId.toString()).toBe(driverId);
|
||||
expect(team.leagues.map(l => l.toString())).toContain(leagueId);
|
||||
|
||||
// And: The team should be in the repository
|
||||
const savedTeam = await teamRepository.findById(team.id.toString());
|
||||
expect(savedTeam).toBeDefined();
|
||||
expect(savedTeam?.name.toString()).toBe('Test Team');
|
||||
|
||||
// And: The driver should have an owner membership
|
||||
const membership = await membershipRepository.getMembership(team.id.toString(), driverId);
|
||||
expect(membership).toBeDefined();
|
||||
expect(membership?.role).toBe('owner');
|
||||
expect(membership?.status).toBe('active');
|
||||
});
|
||||
|
||||
it('should create a team with optional description', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with description
|
||||
// Given: A driver exists
|
||||
const driverId = 'd2';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '2', name: 'Jane Doe', country: 'UK' });
|
||||
|
||||
// And: A league exists
|
||||
const leagueId = 'l2';
|
||||
const league = League.create({ id: leagueId, name: 'League 2', description: 'Test League 2', ownerId: 'owner' });
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called with description
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'Team With Description',
|
||||
tag: 'TWD',
|
||||
description: 'This team has a detailed description',
|
||||
ownerId: driverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
|
||||
// Then: The team should be created with the description
|
||||
// And: EventPublisher should emit TeamCreatedEvent
|
||||
});
|
||||
|
||||
it('should create a team with custom roster size', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with custom roster size
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// When: CreateTeamUseCase.execute() is called with roster size
|
||||
// Then: The team should be created with the specified roster size
|
||||
// And: EventPublisher should emit TeamCreatedEvent
|
||||
});
|
||||
|
||||
it('should create a team with logo upload', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with logo
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// And: A logo file is provided
|
||||
// When: CreateTeamUseCase.execute() is called with logo
|
||||
// Then: The logo should be stored in file storage
|
||||
// And: The team should reference the logo URL
|
||||
// And: EventPublisher should emit TeamCreatedEvent
|
||||
});
|
||||
|
||||
it('should create a team with initial member invitations', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with invitations
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// And: Other drivers exist to invite
|
||||
// When: CreateTeamUseCase.execute() is called with invitations
|
||||
// Then: The team should be created
|
||||
// And: Invitation records should be created for each invited driver
|
||||
// And: EventPublisher should emit TeamCreatedEvent
|
||||
// And: EventPublisher should emit TeamInvitationCreatedEvent for each invitation
|
||||
expect(result.isOk()).toBe(true);
|
||||
const { team } = result.unwrap();
|
||||
expect(team.description.toString()).toBe('This team has a detailed description');
|
||||
});
|
||||
|
||||
it('should create a team with minimal required fields', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with minimal information
|
||||
// Given: A driver exists
|
||||
const driverId = 'd3';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '3', name: 'Bob Smith', country: 'CA' });
|
||||
|
||||
// And: A league exists
|
||||
const leagueId = 'l3';
|
||||
const league = League.create({ id: leagueId, name: 'League 3', description: 'Test League 3', ownerId: 'owner' });
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called with only required fields
|
||||
// Then: The team should be created with default values for optional fields
|
||||
// And: EventPublisher should emit TeamCreatedEvent
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'Minimal Team',
|
||||
tag: 'MT',
|
||||
description: '',
|
||||
ownerId: driverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
|
||||
// Then: The team should be created with default values
|
||||
expect(result.isOk()).toBe(true);
|
||||
const { team } = result.unwrap();
|
||||
expect(team.name.toString()).toBe('Minimal Team');
|
||||
expect(team.tag.toString()).toBe('MT');
|
||||
expect(team.description.toString()).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CreateTeamUseCase - Validation', () => {
|
||||
it('should reject team creation with empty team name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with empty name
|
||||
// Given: A driver exists
|
||||
const driverId = 'd4';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '4', name: 'Test Driver', country: 'US' });
|
||||
|
||||
// And: A league exists
|
||||
const leagueId = 'l4';
|
||||
const league = League.create({ id: leagueId, name: 'League 4', description: 'Test League 4', ownerId: 'owner' });
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called with empty team name
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: '',
|
||||
tag: 'TT',
|
||||
description: 'A test team',
|
||||
ownerId: driverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
|
||||
// Then: Should return error
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('VALIDATION_ERROR');
|
||||
});
|
||||
|
||||
it('should reject team creation with invalid team name format', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with invalid name format
|
||||
// Given: A driver exists
|
||||
const driverId = 'd5';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '5', name: 'Test Driver', country: 'US' });
|
||||
|
||||
// And: A league exists
|
||||
const leagueId = 'l5';
|
||||
const league = League.create({ id: leagueId, name: 'League 5', description: 'Test League 5', ownerId: 'owner' });
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called with invalid team name
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'Invalid!@#$%',
|
||||
tag: 'TT',
|
||||
description: 'A test team',
|
||||
ownerId: driverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
|
||||
// Then: Should return error
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('VALIDATION_ERROR');
|
||||
});
|
||||
|
||||
it('should reject team creation with team name exceeding character limit', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with name exceeding limit
|
||||
it('should reject team creation when driver already belongs to a team', async () => {
|
||||
// Scenario: Driver already belongs to a team
|
||||
// Given: A driver exists
|
||||
const driverId = 'd6';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '6', name: 'Test Driver', country: 'US' });
|
||||
|
||||
// And: A league exists
|
||||
// When: CreateTeamUseCase.execute() is called with name exceeding limit
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
const leagueId = 'l6';
|
||||
const league = League.create({ id: leagueId, name: 'League 6', description: 'Test League 6', ownerId: 'owner' });
|
||||
|
||||
// And: The driver already belongs to a team
|
||||
const existingTeam = Team.create({ id: 'existing', name: 'Existing Team', tag: 'ET', description: 'Existing', ownerId: driverId, leagues: [] });
|
||||
await teamRepository.create(existingTeam);
|
||||
await membershipRepository.saveMembership({
|
||||
teamId: 'existing',
|
||||
driverId: driverId,
|
||||
role: 'driver',
|
||||
status: 'active',
|
||||
joinedAt: new Date()
|
||||
});
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'New Team',
|
||||
tag: 'NT',
|
||||
description: 'A new team',
|
||||
ownerId: driverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
|
||||
it('should reject team creation with description exceeding character limit', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with description exceeding limit
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// When: CreateTeamUseCase.execute() is called with description exceeding limit
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject team creation with invalid roster size', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with invalid roster size
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// When: CreateTeamUseCase.execute() is called with invalid roster size
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject team creation with invalid logo format', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with invalid logo format
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// When: CreateTeamUseCase.execute() is called with invalid logo format
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should reject team creation with oversized logo', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Team creation with oversized logo
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// When: CreateTeamUseCase.execute() is called with oversized logo
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
// Then: Should return error
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('VALIDATION_ERROR');
|
||||
expect(error.details.message).toContain('already belongs to a team');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CreateTeamUseCase - Error Handling', () => {
|
||||
it('should throw error when driver does not exist', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Non-existent driver
|
||||
// Given: No driver exists with the given ID
|
||||
const nonExistentDriverId = 'nonexistent';
|
||||
|
||||
// And: A league exists
|
||||
const leagueId = 'l7';
|
||||
const league = League.create({ id: leagueId, name: 'League 7', description: 'Test League 7', ownerId: 'owner' });
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called with non-existent driver ID
|
||||
// Then: Should throw DriverNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'Test Team',
|
||||
tag: 'TT',
|
||||
description: 'A test team',
|
||||
ownerId: nonExistentDriverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
|
||||
// Then: Should return error
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('VALIDATION_ERROR');
|
||||
});
|
||||
|
||||
it('should throw error when league does not exist', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Non-existent league
|
||||
// Given: A driver exists
|
||||
const driverId = 'd8';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '8', name: 'Test Driver', country: 'US' });
|
||||
|
||||
// And: No league exists with the given ID
|
||||
const nonExistentLeagueId = 'nonexistent';
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called with non-existent league ID
|
||||
// Then: Should throw LeagueNotFoundError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'Test Team',
|
||||
tag: 'TT',
|
||||
description: 'A test team',
|
||||
ownerId: driverId,
|
||||
leagues: [nonExistentLeagueId]
|
||||
});
|
||||
|
||||
// Then: Should return error
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('LEAGUE_NOT_FOUND');
|
||||
});
|
||||
|
||||
it('should throw error when team name already exists', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Duplicate team name
|
||||
// Given: A driver exists
|
||||
const driverId = 'd9';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '9', name: 'Test Driver', country: 'US' });
|
||||
|
||||
// And: A league exists
|
||||
const leagueId = 'l9';
|
||||
const league = League.create({ id: leagueId, name: 'League 9', description: 'Test League 9', ownerId: 'owner' });
|
||||
|
||||
// And: A team with the same name already exists
|
||||
const existingTeam = Team.create({ id: 'existing2', name: 'Duplicate Team', tag: 'DT', description: 'Existing', ownerId: 'other', leagues: [] });
|
||||
await teamRepository.create(existingTeam);
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called with duplicate team name
|
||||
// Then: Should throw TeamNameAlreadyExistsError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'Duplicate Team',
|
||||
tag: 'DT2',
|
||||
description: 'A new team',
|
||||
ownerId: driverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
|
||||
it('should throw error when driver is already captain of another team', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Driver already captain
|
||||
// Given: A driver exists
|
||||
// And: The driver is already captain of another team
|
||||
// When: CreateTeamUseCase.execute() is called
|
||||
// Then: Should throw DriverAlreadyCaptainError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should handle repository errors gracefully', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Repository throws error
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// And: TeamRepository throws an error during save
|
||||
// When: CreateTeamUseCase.execute() is called
|
||||
// Then: Should propagate the error appropriately
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should handle file storage errors gracefully', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: File storage throws error
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// And: FileStorage throws an error during upload
|
||||
// When: CreateTeamUseCase.execute() is called with logo
|
||||
// Then: Should propagate the error appropriately
|
||||
// And: EventPublisher should NOT emit any events
|
||||
// Then: Should return error
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('VALIDATION_ERROR');
|
||||
expect(error.details.message).toContain('already exists');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CreateTeamUseCase - Business Logic', () => {
|
||||
it('should set the creating driver as team captain', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Driver becomes captain
|
||||
// Given: A driver exists
|
||||
const driverId = 'd10';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '10', name: 'Captain Driver', country: 'US' });
|
||||
|
||||
// And: A league exists
|
||||
const leagueId = 'l10';
|
||||
const league = League.create({ id: leagueId, name: 'League 10', description: 'Test League 10', ownerId: 'owner' });
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'Captain Team',
|
||||
tag: 'CT',
|
||||
description: 'A team with captain',
|
||||
ownerId: driverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
|
||||
// Then: The creating driver should be set as team captain
|
||||
expect(result.isOk()).toBe(true);
|
||||
const { team } = result.unwrap();
|
||||
|
||||
// And: The captain role should be recorded in the team roster
|
||||
});
|
||||
|
||||
it('should validate roster size against league limits', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Roster size validation
|
||||
// Given: A driver exists
|
||||
// And: A league exists with max roster size of 10
|
||||
// When: CreateTeamUseCase.execute() is called with roster size 15
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should assign default tier if not specified', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Default tier assignment
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// When: CreateTeamUseCase.execute() is called without tier
|
||||
// Then: The team should be assigned a default tier
|
||||
// And: EventPublisher should emit TeamCreatedEvent
|
||||
const membership = await membershipRepository.getMembership(team.id.toString(), driverId);
|
||||
expect(membership).toBeDefined();
|
||||
expect(membership?.role).toBe('owner');
|
||||
});
|
||||
|
||||
it('should generate unique team ID', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Unique team ID generation
|
||||
// Given: A driver exists
|
||||
const driverId = 'd11';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '11', name: 'Unique Driver', country: 'US' });
|
||||
|
||||
// And: A league exists
|
||||
const leagueId = 'l11';
|
||||
const league = League.create({ id: leagueId, name: 'League 11', description: 'Test League 11', ownerId: 'owner' });
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'Unique Team',
|
||||
tag: 'UT',
|
||||
description: 'A unique team',
|
||||
ownerId: driverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
|
||||
// Then: The team should have a unique ID
|
||||
expect(result.isOk()).toBe(true);
|
||||
const { team } = result.unwrap();
|
||||
expect(team.id.toString()).toBeDefined();
|
||||
expect(team.id.toString().length).toBeGreaterThan(0);
|
||||
|
||||
// And: The ID should not conflict with existing teams
|
||||
const existingTeam = await teamRepository.findById(team.id.toString());
|
||||
expect(existingTeam).toBeDefined();
|
||||
expect(existingTeam?.id.toString()).toBe(team.id.toString());
|
||||
});
|
||||
|
||||
it('should set creation timestamp', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Creation timestamp
|
||||
// Given: A driver exists
|
||||
const driverId = 'd12';
|
||||
const driver = Driver.create({ id: driverId, iracingId: '12', name: 'Timestamp Driver', country: 'US' });
|
||||
|
||||
// And: A league exists
|
||||
const leagueId = 'l12';
|
||||
const league = League.create({ id: leagueId, name: 'League 12', description: 'Test League 12', ownerId: 'owner' });
|
||||
|
||||
// When: CreateTeamUseCase.execute() is called
|
||||
const beforeCreate = new Date();
|
||||
const result = await createTeamUseCase.execute({
|
||||
name: 'Timestamp Team',
|
||||
tag: 'TT',
|
||||
description: 'A team with timestamp',
|
||||
ownerId: driverId,
|
||||
leagues: [leagueId]
|
||||
});
|
||||
const afterCreate = new Date();
|
||||
|
||||
// Then: The team should have a creation timestamp
|
||||
expect(result.isOk()).toBe(true);
|
||||
const { team } = result.unwrap();
|
||||
expect(team.createdAt).toBeDefined();
|
||||
|
||||
// And: The timestamp should be current or recent
|
||||
});
|
||||
});
|
||||
|
||||
describe('CreateTeamUseCase - Event Orchestration', () => {
|
||||
it('should emit TeamCreatedEvent with correct payload', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Event emission
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// When: CreateTeamUseCase.execute() is called
|
||||
// Then: EventPublisher should emit TeamCreatedEvent
|
||||
// And: The event should contain team ID, name, captain ID, and league ID
|
||||
});
|
||||
|
||||
it('should emit TeamInvitationCreatedEvent for each invitation', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invitation events
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// And: Other drivers exist to invite
|
||||
// When: CreateTeamUseCase.execute() is called with invitations
|
||||
// Then: EventPublisher should emit TeamInvitationCreatedEvent for each invitation
|
||||
// And: Each event should contain invitation ID, team ID, and invited driver ID
|
||||
});
|
||||
|
||||
it('should not emit events on validation failure', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: No events on validation failure
|
||||
// Given: A driver exists
|
||||
// And: A league exists
|
||||
// When: CreateTeamUseCase.execute() is called with invalid data
|
||||
// Then: EventPublisher should NOT emit any events
|
||||
const createdAt = team.createdAt.toDate();
|
||||
expect(createdAt.getTime()).toBeGreaterThanOrEqual(beforeCreate.getTime());
|
||||
expect(createdAt.getTime()).toBeLessThanOrEqual(afterCreate.getTime());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user