132 lines
5.2 KiB
TypeScript
132 lines
5.2 KiB
TypeScript
/**
|
|
* Integration Test: Team Detail Use Case Orchestration
|
|
*
|
|
* Tests the orchestration logic of team detail-related Use Cases:
|
|
* - GetTeamDetailsUseCase: Retrieves detailed team information including roster and management permissions
|
|
* - 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, beforeEach } from 'vitest';
|
|
import { InMemoryTeamRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryTeamRepository';
|
|
import { InMemoryTeamMembershipRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryTeamMembershipRepository';
|
|
import { GetTeamDetailsUseCase } from '../../../core/racing/application/use-cases/GetTeamDetailsUseCase';
|
|
import { Team } from '../../../core/racing/domain/entities/Team';
|
|
import { Logger } from '../../../core/shared/domain/Logger';
|
|
|
|
describe('Team Detail Use Case Orchestration', () => {
|
|
let teamRepository: InMemoryTeamRepository;
|
|
let membershipRepository: InMemoryTeamMembershipRepository;
|
|
let getTeamDetailsUseCase: GetTeamDetailsUseCase;
|
|
let mockLogger: Logger;
|
|
|
|
beforeAll(() => {
|
|
mockLogger = {
|
|
info: () => {},
|
|
debug: () => {},
|
|
warn: () => {},
|
|
error: () => {},
|
|
} as unknown as Logger;
|
|
|
|
teamRepository = new InMemoryTeamRepository(mockLogger);
|
|
membershipRepository = new InMemoryTeamMembershipRepository(mockLogger);
|
|
getTeamDetailsUseCase = new GetTeamDetailsUseCase(teamRepository, membershipRepository);
|
|
});
|
|
|
|
beforeEach(() => {
|
|
teamRepository.clear();
|
|
membershipRepository.clear();
|
|
});
|
|
|
|
describe('GetTeamDetailsUseCase - Success Path', () => {
|
|
it('should retrieve team detail with membership and management permissions for owner', async () => {
|
|
// Scenario: Team owner views team details
|
|
// Given: A team exists
|
|
const teamId = 't1';
|
|
const ownerId = 'd1';
|
|
const team = Team.create({ id: teamId, name: 'Team 1', tag: 'T1', description: 'Desc', ownerId, leagues: [] });
|
|
await teamRepository.create(team);
|
|
|
|
// And: The driver is the owner
|
|
await membershipRepository.saveMembership({
|
|
teamId,
|
|
driverId: ownerId,
|
|
role: 'owner',
|
|
status: 'active',
|
|
joinedAt: new Date()
|
|
});
|
|
|
|
// When: GetTeamDetailsUseCase.execute() is called
|
|
const result = await getTeamDetailsUseCase.execute({ teamId, driverId: ownerId });
|
|
|
|
// Then: The result should contain team information and management permissions
|
|
expect(result.isOk()).toBe(true);
|
|
const data = result.unwrap();
|
|
expect(data.team.id.toString()).toBe(teamId);
|
|
expect(data.membership?.role).toBe('owner');
|
|
expect(data.canManage).toBe(true);
|
|
});
|
|
|
|
it('should retrieve team detail for a non-member', async () => {
|
|
// Scenario: Non-member views team details
|
|
// Given: A team exists
|
|
const teamId = 't2';
|
|
const team = Team.create({ id: teamId, name: 'Team 2', tag: 'T2', description: 'Desc', ownerId: 'owner', leagues: [] });
|
|
await teamRepository.create(team);
|
|
|
|
// When: GetTeamDetailsUseCase.execute() is called with a driver who is not a member
|
|
const result = await getTeamDetailsUseCase.execute({ teamId, driverId: 'non-member' });
|
|
|
|
// Then: The result should contain team information but no membership and no management permissions
|
|
expect(result.isOk()).toBe(true);
|
|
const data = result.unwrap();
|
|
expect(data.team.id.toString()).toBe(teamId);
|
|
expect(data.membership).toBeNull();
|
|
expect(data.canManage).toBe(false);
|
|
});
|
|
|
|
it('should retrieve team detail for a regular member', async () => {
|
|
// Scenario: Regular member views team details
|
|
// Given: A team exists
|
|
const teamId = 't3';
|
|
const memberId = 'd3';
|
|
const team = Team.create({ id: teamId, name: 'Team 3', tag: 'T3', description: 'Desc', ownerId: 'owner', leagues: [] });
|
|
await teamRepository.create(team);
|
|
|
|
// And: The driver is a regular member
|
|
await membershipRepository.saveMembership({
|
|
teamId,
|
|
driverId: memberId,
|
|
role: 'driver',
|
|
status: 'active',
|
|
joinedAt: new Date()
|
|
});
|
|
|
|
// When: GetTeamDetailsUseCase.execute() is called
|
|
const result = await getTeamDetailsUseCase.execute({ teamId, driverId: memberId });
|
|
|
|
// Then: The result should contain team information and membership but no management permissions
|
|
expect(result.isOk()).toBe(true);
|
|
const data = result.unwrap();
|
|
expect(data.team.id.toString()).toBe(teamId);
|
|
expect(data.membership?.role).toBe('driver');
|
|
expect(data.canManage).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('GetTeamDetailsUseCase - Error Handling', () => {
|
|
it('should throw error when team does not exist', async () => {
|
|
// Scenario: Non-existent team
|
|
// When: GetTeamDetailsUseCase.execute() is called with non-existent team ID
|
|
const result = await getTeamDetailsUseCase.execute({ teamId: 'nonexistent', driverId: 'any' });
|
|
|
|
// Then: Should return error
|
|
expect(result.isErr()).toBe(true);
|
|
const error = result.unwrapErr();
|
|
expect(error.code).toBe('TEAM_NOT_FOUND');
|
|
});
|
|
});
|
|
});
|