202 lines
6.8 KiB
TypeScript
202 lines
6.8 KiB
TypeScript
/**
|
|
* Integration Test: Team Admin Use Case Orchestration
|
|
*
|
|
* Tests the orchestration logic of team admin-related Use Cases:
|
|
* - UpdateTeamUseCase: Admin updates team details
|
|
* - 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 { UpdateTeamUseCase } from '../../../core/racing/application/use-cases/UpdateTeamUseCase';
|
|
import { Team } from '../../../core/racing/domain/entities/Team';
|
|
import { Logger } from '../../../core/shared/domain/Logger';
|
|
|
|
describe('Team Admin Use Case Orchestration', () => {
|
|
let teamRepository: InMemoryTeamRepository;
|
|
let membershipRepository: InMemoryTeamMembershipRepository;
|
|
let updateTeamUseCase: UpdateTeamUseCase;
|
|
let mockLogger: Logger;
|
|
|
|
beforeAll(() => {
|
|
mockLogger = {
|
|
info: () => {},
|
|
debug: () => {},
|
|
warn: () => {},
|
|
error: () => {},
|
|
} as unknown as Logger;
|
|
|
|
teamRepository = new InMemoryTeamRepository(mockLogger);
|
|
membershipRepository = new InMemoryTeamMembershipRepository(mockLogger);
|
|
updateTeamUseCase = new UpdateTeamUseCase(teamRepository, membershipRepository);
|
|
});
|
|
|
|
beforeEach(() => {
|
|
teamRepository.clear();
|
|
membershipRepository.clear();
|
|
});
|
|
|
|
describe('UpdateTeamUseCase - Success Path', () => {
|
|
it('should update team details when called by owner', async () => {
|
|
// Scenario: Owner updates team details
|
|
// Given: A team exists
|
|
const teamId = 't1';
|
|
const ownerId = 'o1';
|
|
const team = Team.create({ id: teamId, name: 'Old Name', tag: 'OLD', description: 'Old 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: UpdateTeamUseCase.execute() is called
|
|
const result = await updateTeamUseCase.execute({
|
|
teamId,
|
|
updatedBy: ownerId,
|
|
updates: {
|
|
name: 'New Name',
|
|
tag: 'NEW',
|
|
description: 'New Desc'
|
|
}
|
|
});
|
|
|
|
// Then: The team should be updated successfully
|
|
expect(result.isOk()).toBe(true);
|
|
const { team: updatedTeam } = result.unwrap();
|
|
expect(updatedTeam.name.toString()).toBe('New Name');
|
|
expect(updatedTeam.tag.toString()).toBe('NEW');
|
|
expect(updatedTeam.description.toString()).toBe('New Desc');
|
|
|
|
// And: The changes should be in the repository
|
|
const savedTeam = await teamRepository.findById(teamId);
|
|
expect(savedTeam?.name.toString()).toBe('New Name');
|
|
});
|
|
|
|
it('should update team details when called by manager', async () => {
|
|
// Scenario: Manager updates team details
|
|
// Given: A team exists
|
|
const teamId = 't2';
|
|
const managerId = 'm2';
|
|
const team = Team.create({ id: teamId, name: 'Team 2', tag: 'T2', description: 'Desc', ownerId: 'owner', leagues: [] });
|
|
await teamRepository.create(team);
|
|
|
|
// And: The driver is a manager
|
|
await membershipRepository.saveMembership({
|
|
teamId,
|
|
driverId: managerId,
|
|
role: 'manager',
|
|
status: 'active',
|
|
joinedAt: new Date()
|
|
});
|
|
|
|
// When: UpdateTeamUseCase.execute() is called
|
|
const result = await updateTeamUseCase.execute({
|
|
teamId,
|
|
updatedBy: managerId,
|
|
updates: {
|
|
name: 'Updated by Manager'
|
|
}
|
|
});
|
|
|
|
// Then: The team should be updated successfully
|
|
expect(result.isOk()).toBe(true);
|
|
const { team: updatedTeam } = result.unwrap();
|
|
expect(updatedTeam.name.toString()).toBe('Updated by Manager');
|
|
});
|
|
});
|
|
|
|
describe('UpdateTeamUseCase - Validation', () => {
|
|
it('should reject update when called by regular member', async () => {
|
|
// Scenario: Regular member tries to update team
|
|
// 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: UpdateTeamUseCase.execute() is called
|
|
const result = await updateTeamUseCase.execute({
|
|
teamId,
|
|
updatedBy: memberId,
|
|
updates: {
|
|
name: 'Unauthorized Update'
|
|
}
|
|
});
|
|
|
|
// Then: Should return error
|
|
expect(result.isErr()).toBe(true);
|
|
const error = result.unwrapErr();
|
|
expect(error.code).toBe('PERMISSION_DENIED');
|
|
});
|
|
|
|
it('should reject update when called by non-member', async () => {
|
|
// Scenario: Non-member tries to update team
|
|
// Given: A team exists
|
|
const teamId = 't4';
|
|
const team = Team.create({ id: teamId, name: 'Team 4', tag: 'T4', description: 'Desc', ownerId: 'owner', leagues: [] });
|
|
await teamRepository.create(team);
|
|
|
|
// When: UpdateTeamUseCase.execute() is called
|
|
const result = await updateTeamUseCase.execute({
|
|
teamId,
|
|
updatedBy: 'non-member',
|
|
updates: {
|
|
name: 'Unauthorized Update'
|
|
}
|
|
});
|
|
|
|
// Then: Should return error
|
|
expect(result.isErr()).toBe(true);
|
|
const error = result.unwrapErr();
|
|
expect(error.code).toBe('PERMISSION_DENIED');
|
|
});
|
|
});
|
|
|
|
describe('UpdateTeamUseCase - Error Handling', () => {
|
|
it('should throw error when team does not exist', async () => {
|
|
// Scenario: Non-existent team
|
|
// Given: A driver exists who is a manager of some team
|
|
const managerId = 'm5';
|
|
await membershipRepository.saveMembership({
|
|
teamId: 'some-team',
|
|
driverId: managerId,
|
|
role: 'manager',
|
|
status: 'active',
|
|
joinedAt: new Date()
|
|
});
|
|
|
|
// When: UpdateTeamUseCase.execute() is called with non-existent team ID
|
|
const result = await updateTeamUseCase.execute({
|
|
teamId: 'nonexistent',
|
|
updatedBy: managerId,
|
|
updates: {
|
|
name: 'New Name'
|
|
}
|
|
});
|
|
|
|
// Then: Should return error
|
|
expect(result.isErr()).toBe(true);
|
|
const error = result.unwrapErr();
|
|
expect(error.code).toBe('PERMISSION_DENIED'); // Because membership check fails first
|
|
});
|
|
});
|
|
});
|