tests
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
import { DashboardStatsPresenter } from './DashboardStatsPresenter';
|
||||
|
||||
describe('DashboardStatsPresenter', () => {
|
||||
let presenter: DashboardStatsPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new DashboardStatsPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map result to response model', () => {
|
||||
const result = {
|
||||
totalUsers: 100,
|
||||
activeUsers: 80,
|
||||
suspendedUsers: 10,
|
||||
deletedUsers: 10,
|
||||
systemAdmins: 5,
|
||||
recentLogins: 20,
|
||||
newUsersToday: 5,
|
||||
userGrowth: [
|
||||
{ label: 'Day 1', value: 10, color: '#000' },
|
||||
{ label: 'Day 2', value: 15, color: '#000' },
|
||||
],
|
||||
roleDistribution: [
|
||||
{ label: 'Admin', value: 5, color: '#000' },
|
||||
{ label: 'User', value: 95, color: '#000' },
|
||||
],
|
||||
statusDistribution: {
|
||||
active: 80,
|
||||
suspended: 10,
|
||||
deleted: 10,
|
||||
},
|
||||
activityTimeline: [
|
||||
{ date: '2024-01-01', newUsers: 5, logins: 20 },
|
||||
],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
totalUsers: 100,
|
||||
activeUsers: 80,
|
||||
suspendedUsers: 10,
|
||||
deletedUsers: 10,
|
||||
systemAdmins: 5,
|
||||
recentLogins: 20,
|
||||
newUsersToday: 5,
|
||||
userGrowth: [
|
||||
{ label: 'Day 1', value: 10, color: '#000' },
|
||||
{ label: 'Day 2', value: 15, color: '#000' },
|
||||
],
|
||||
roleDistribution: [
|
||||
{ label: 'Admin', value: 5, color: '#000' },
|
||||
{ label: 'User', value: 95, color: '#000' },
|
||||
],
|
||||
statusDistribution: {
|
||||
active: 80,
|
||||
suspended: 10,
|
||||
deleted: 10,
|
||||
},
|
||||
activityTimeline: [
|
||||
{ date: '2024-01-01', newUsers: 5, logins: 20 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty arrays', () => {
|
||||
const result = {
|
||||
totalUsers: 0,
|
||||
activeUsers: 0,
|
||||
suspendedUsers: 0,
|
||||
deletedUsers: 0,
|
||||
systemAdmins: 0,
|
||||
recentLogins: 0,
|
||||
newUsersToday: 0,
|
||||
userGrowth: [],
|
||||
roleDistribution: [],
|
||||
statusDistribution: {
|
||||
active: 0,
|
||||
suspended: 0,
|
||||
deleted: 0,
|
||||
},
|
||||
activityTimeline: [],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel.userGrowth).toEqual([]);
|
||||
expect(presenter.responseModel.roleDistribution).toEqual([]);
|
||||
expect(presenter.responseModel.activityTimeline).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the response model', () => {
|
||||
const result = {
|
||||
totalUsers: 100,
|
||||
activeUsers: 80,
|
||||
suspendedUsers: 10,
|
||||
deletedUsers: 10,
|
||||
systemAdmins: 5,
|
||||
recentLogins: 20,
|
||||
newUsersToday: 5,
|
||||
userGrowth: [],
|
||||
roleDistribution: [],
|
||||
statusDistribution: {
|
||||
active: 80,
|
||||
suspended: 10,
|
||||
deleted: 10,
|
||||
},
|
||||
activityTimeline: [],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
expect(presenter.responseModel).toBeDefined();
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.responseModel).toThrow('No response model available. Call present() first.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before present()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('No response model available. Call present() first.');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import { ForgotPasswordPresenter } from './ForgotPasswordPresenter';
|
||||
|
||||
describe('ForgotPasswordPresenter', () => {
|
||||
let presenter: ForgotPasswordPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new ForgotPasswordPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map result to response model', () => {
|
||||
const result = { message: 'Password reset link generated successfully', magicLink: 'http://example.com/reset?token=abc123' };
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({ message: 'Password reset link generated successfully', magicLink: 'http://example.com/reset?token=abc123' });
|
||||
});
|
||||
|
||||
it('should handle result without magicLink', () => {
|
||||
const result = { message: 'If an account exists with this email, a password reset link will be sent', magicLink: null };
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({ message: 'If an account exists with this email, a password reset link will be sent', magicLink: null });
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the response model', () => {
|
||||
presenter.present({ message: 'Password reset link generated successfully', magicLink: 'http://example.com' });
|
||||
expect(presenter.responseModel).toBeDefined();
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.responseModel).toThrow('ForgotPasswordPresenter: No response model available');
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before present()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('ForgotPasswordPresenter: No response model available');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import { ResetPasswordPresenter } from './ResetPasswordPresenter';
|
||||
|
||||
describe('ResetPasswordPresenter', () => {
|
||||
let presenter: ResetPasswordPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new ResetPasswordPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map result to response model', () => {
|
||||
const result = { message: 'Password reset successfully. You can now log in with your new password.' };
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({ message: 'Password reset successfully. You can now log in with your new password.' });
|
||||
});
|
||||
|
||||
it('should handle different message', () => {
|
||||
const result = { message: 'Password updated' };
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({ message: 'Password updated' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the response model', () => {
|
||||
presenter.present({ message: 'Password reset successfully' });
|
||||
expect(presenter.responseModel).toBeDefined();
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.responseModel).toThrow('ResetPasswordPresenter: No response model available');
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before present()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('ResetPasswordPresenter: No response model available');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { CompleteOnboardingPresenter } from './CompleteOnboardingPresenter';
|
||||
|
||||
describe('CompleteOnboardingPresenter', () => {
|
||||
let presenter: CompleteOnboardingPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new CompleteOnboardingPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map result to response model', () => {
|
||||
const result = {
|
||||
driver: {
|
||||
id: 'driver-123',
|
||||
} as any,
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
success: true,
|
||||
driverId: 'driver-123',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle different driver IDs', () => {
|
||||
const result = {
|
||||
driver: {
|
||||
id: 'driver-456',
|
||||
} as any,
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
success: true,
|
||||
driverId: 'driver-456',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResponseModel', () => {
|
||||
it('should throw error when accessed before present()', () => {
|
||||
expect(() => presenter.getResponseModel()).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('should return model after present()', () => {
|
||||
presenter.present({ driver: { id: 'driver-123' } } as any);
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
success: true,
|
||||
driverId: 'driver-123',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,487 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { AllLeaguesWithCapacityAndScoringPresenter } from './AllLeaguesWithCapacityAndScoringPresenter';
|
||||
import { League } from '@core/racing/domain/entities/League';
|
||||
import { Season } from '@core/racing/domain/entities/season/Season';
|
||||
import { LeagueScoringConfig } from '@core/racing/domain/entities/LeagueScoringConfig';
|
||||
import { Game } from '@core/racing/domain/entities/Game';
|
||||
import { MediaReference } from '@core/domain/media/MediaReference';
|
||||
import type { LeagueScoringPreset } from '@core/racing/domain/types/LeagueScoringPreset';
|
||||
import { PointsTable } from '@core/racing/domain/value-objects/PointsTable';
|
||||
|
||||
describe('AllLeaguesWithCapacityAndScoringPresenter', () => {
|
||||
let presenter: AllLeaguesWithCapacityAndScoringPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new AllLeaguesWithCapacityAndScoringPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map empty leagues array to DTO', async () => {
|
||||
await presenter.present({ leagues: [] });
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
leagues: [],
|
||||
totalCount: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('should map leagues with basic information', async () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: {
|
||||
pointsSystem: 'f1-2024',
|
||||
maxDrivers: 20,
|
||||
},
|
||||
createdAt: new Date('2024-01-01T00:00:00Z'),
|
||||
});
|
||||
|
||||
await presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 5,
|
||||
maxDrivers: 20,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues).toHaveLength(1);
|
||||
expect(vm.leagues[0]!.id).toBe('league-1');
|
||||
expect(vm.leagues[0]!.name).toBe('Test League');
|
||||
expect(vm.leagues[0]!.description).toBe('A test league');
|
||||
expect(vm.leagues[0]!.ownerId).toBe('owner-1');
|
||||
expect(vm.leagues[0]!.createdAt).toBe('2024-01-01T00:00:00.000Z');
|
||||
expect(vm.leagues[0]!.settings.maxDrivers).toBe(20);
|
||||
expect(vm.leagues[0]!.usedSlots).toBe(5);
|
||||
expect(vm.totalCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should map leagues with social links', async () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
socialLinks: {
|
||||
discordUrl: 'https://discord.gg/test',
|
||||
youtubeUrl: 'https://youtube.com/test',
|
||||
websiteUrl: 'https://test.com',
|
||||
},
|
||||
});
|
||||
|
||||
await presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 3,
|
||||
maxDrivers: 32,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.socialLinks).toEqual({
|
||||
discordUrl: 'https://discord.gg/test',
|
||||
youtubeUrl: 'https://youtube.com/test',
|
||||
websiteUrl: 'https://test.com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should map leagues with category', async () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
category: 'Formula',
|
||||
});
|
||||
|
||||
await presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 2,
|
||||
maxDrivers: 32,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.category).toBe('Formula');
|
||||
});
|
||||
|
||||
it('should map leagues with session duration and qualifying format', async () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: {
|
||||
pointsSystem: 'f1-2024',
|
||||
sessionDuration: 90,
|
||||
qualifyingFormat: 'single-lap',
|
||||
},
|
||||
});
|
||||
|
||||
await presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 4,
|
||||
maxDrivers: 32,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.settings.sessionDuration).toBe(90);
|
||||
expect(vm.leagues[0]!.settings.qualifyingFormat).toBe('single-lap');
|
||||
});
|
||||
|
||||
it('should map leagues with timing summary for hours', async () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
});
|
||||
|
||||
const season = Season.create({
|
||||
id: 'season-1',
|
||||
leagueId: 'league-1',
|
||||
gameId: 'iracing',
|
||||
name: 'Season 1',
|
||||
status: 'active',
|
||||
schedule: {
|
||||
startDate: new Date('2024-01-01'),
|
||||
timeOfDay: { hour: 20, minute: 0 },
|
||||
} as any,
|
||||
} as any);
|
||||
|
||||
const scoringConfig = LeagueScoringConfig.create({
|
||||
id: 'scoring-1',
|
||||
seasonId: 'season-1',
|
||||
scoringPresetId: 'preset-1',
|
||||
championships: [
|
||||
{
|
||||
id: 'champ-1',
|
||||
name: 'Drivers Championship',
|
||||
type: 'driver',
|
||||
sessionTypes: ['main'],
|
||||
pointsTableBySessionType: {
|
||||
practice: new PointsTable({}),
|
||||
qualifying: new PointsTable({}),
|
||||
q1: new PointsTable({}),
|
||||
q2: new PointsTable({}),
|
||||
q3: new PointsTable({}),
|
||||
sprint: new PointsTable({}),
|
||||
main: new PointsTable({ 1: 25, 2: 18, 3: 15, 4: 12, 5: 10, 6: 8, 7: 6, 8: 4, 9: 2, 10: 1 }),
|
||||
timeTrial: new PointsTable({}),
|
||||
},
|
||||
dropScorePolicy: { strategy: 'bestNResults', count: 3 },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const game = Game.create({
|
||||
id: 'iracing',
|
||||
name: 'iRacing',
|
||||
});
|
||||
|
||||
const preset: LeagueScoringPreset = {
|
||||
id: 'preset-1',
|
||||
name: 'Test Preset',
|
||||
description: 'Test preset description',
|
||||
primaryChampionshipType: 'driver',
|
||||
dropPolicySummary: 'Best 8 of 12',
|
||||
sessionSummary: 'Qualifying + Race',
|
||||
bonusSummary: 'Bonus points for top 3',
|
||||
defaultTimings: {
|
||||
mainRaceMinutes: 120,
|
||||
practiceMinutes: 30,
|
||||
qualifyingMinutes: 20,
|
||||
sprintRaceMinutes: 0,
|
||||
sessionCount: 1
|
||||
},
|
||||
};
|
||||
|
||||
await presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 5,
|
||||
maxDrivers: 32,
|
||||
season,
|
||||
scoringConfig,
|
||||
game,
|
||||
preset,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.timingSummary).toBe('2h Race');
|
||||
expect(vm.leagues[0]!.scoring).toEqual({
|
||||
gameId: 'iracing',
|
||||
gameName: 'iRacing',
|
||||
primaryChampionshipType: 'driver',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Test Preset',
|
||||
dropPolicySummary: 'Best 8 of 12',
|
||||
scoringPatternSummary: 'Qualifying + Race',
|
||||
});
|
||||
});
|
||||
|
||||
it('should map leagues with timing summary for minutes', async () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
});
|
||||
|
||||
const season = Season.create({
|
||||
id: 'season-1',
|
||||
leagueId: 'league-1',
|
||||
gameId: 'iracing',
|
||||
name: 'Season 1',
|
||||
status: 'active',
|
||||
schedule: {
|
||||
startDate: new Date('2024-01-01'),
|
||||
timeOfDay: { hour: 20, minute: 0 },
|
||||
} as any,
|
||||
} as any);
|
||||
|
||||
const scoringConfig = LeagueScoringConfig.create({
|
||||
id: 'scoring-1',
|
||||
seasonId: 'season-1',
|
||||
scoringPresetId: 'preset-1',
|
||||
championships: [
|
||||
{
|
||||
id: 'champ-1',
|
||||
name: 'Drivers Championship',
|
||||
type: 'driver',
|
||||
sessionTypes: ['main'],
|
||||
pointsTableBySessionType: {
|
||||
practice: new PointsTable({}),
|
||||
qualifying: new PointsTable({}),
|
||||
q1: new PointsTable({}),
|
||||
q2: new PointsTable({}),
|
||||
q3: new PointsTable({}),
|
||||
sprint: new PointsTable({}),
|
||||
main: new PointsTable({ 1: 25, 2: 18, 3: 15, 4: 12, 5: 10, 6: 8, 7: 6, 8: 4, 9: 2, 10: 1 }),
|
||||
timeTrial: new PointsTable({}),
|
||||
},
|
||||
dropScorePolicy: { strategy: 'bestNResults', count: 3 },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const game = Game.create({
|
||||
id: 'iracing',
|
||||
name: 'iRacing',
|
||||
});
|
||||
|
||||
const preset: LeagueScoringPreset = {
|
||||
id: 'preset-1',
|
||||
name: 'Test Preset',
|
||||
description: 'Test preset description',
|
||||
primaryChampionshipType: 'driver',
|
||||
dropPolicySummary: 'Best 8 of 12',
|
||||
sessionSummary: 'Qualifying + Race',
|
||||
bonusSummary: 'Bonus points for top 3',
|
||||
defaultTimings: {
|
||||
mainRaceMinutes: 45,
|
||||
practiceMinutes: 15,
|
||||
qualifyingMinutes: 10,
|
||||
sprintRaceMinutes: 0,
|
||||
sessionCount: 1
|
||||
},
|
||||
};
|
||||
|
||||
await presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 5,
|
||||
maxDrivers: 32,
|
||||
season,
|
||||
scoringConfig,
|
||||
game,
|
||||
preset,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.timingSummary).toBe('45m Race');
|
||||
});
|
||||
|
||||
it('should handle leagues without scoring information', async () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
});
|
||||
|
||||
await presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 5,
|
||||
maxDrivers: 32,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.scoring).toBeUndefined();
|
||||
expect(vm.leagues[0]!.timingSummary).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle leagues with system default logoRef', async () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
});
|
||||
|
||||
await presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 5,
|
||||
maxDrivers: 32,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
// Should be null when it's system default (as per presenter logic)
|
||||
expect(vm.leagues[0]!.logoUrl).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle multiple leagues with different configurations', async () => {
|
||||
const league1 = League.create({
|
||||
id: 'league-1',
|
||||
name: 'League One',
|
||||
description: 'First league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024', maxDrivers: 20 },
|
||||
category: 'Formula',
|
||||
});
|
||||
|
||||
const league2 = League.create({
|
||||
id: 'league-2',
|
||||
name: 'League Two',
|
||||
description: 'Second league',
|
||||
ownerId: 'owner-2',
|
||||
settings: { pointsSystem: 'indycar', maxDrivers: 40 },
|
||||
socialLinks: { discordUrl: 'https://discord.gg/league2' },
|
||||
});
|
||||
|
||||
await presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league: league1,
|
||||
currentDrivers: 10,
|
||||
maxDrivers: 20,
|
||||
},
|
||||
{
|
||||
league: league2,
|
||||
currentDrivers: 25,
|
||||
maxDrivers: 40,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues).toHaveLength(2);
|
||||
expect(vm.totalCount).toBe(2);
|
||||
expect(vm.leagues[0]!.id).toBe('league-1');
|
||||
expect(vm.leagues[0]!.category).toBe('Formula');
|
||||
expect(vm.leagues[0]!.settings.maxDrivers).toBe(20);
|
||||
expect(vm.leagues[1]!.id).toBe('league-2');
|
||||
expect(vm.leagues[1]!.socialLinks?.discordUrl).toBe('https://discord.gg/league2');
|
||||
expect(vm.leagues[1]!.settings.maxDrivers).toBe(40);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getViewModel', () => {
|
||||
it('should throw error when not presented', () => {
|
||||
expect(() => presenter.getViewModel()).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('should return the model when presented', async () => {
|
||||
await presenter.present({ leagues: [] });
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
leagues: [],
|
||||
totalCount: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setMediaResolver', () => {
|
||||
it('should use media resolver to resolve logo URLs', async () => {
|
||||
const mockResolver = {
|
||||
resolve: async () => 'https://cdn.example.com/league-logo.png',
|
||||
};
|
||||
|
||||
presenter.setMediaResolver(mockResolver);
|
||||
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
});
|
||||
|
||||
// Override logoRef to uploaded type
|
||||
(league as any).logoRef = MediaReference.fromJSON({
|
||||
type: 'uploaded',
|
||||
mediaId: 'media-123',
|
||||
});
|
||||
|
||||
await presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 5,
|
||||
maxDrivers: 32,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.logoUrl).toBe('https://cdn.example.com/league-logo.png');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,228 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { AllLeaguesWithCapacityPresenter } from './AllLeaguesWithCapacityPresenter';
|
||||
import { League } from '@core/racing/domain/entities/League';
|
||||
|
||||
describe('AllLeaguesWithCapacityPresenter', () => {
|
||||
let presenter: AllLeaguesWithCapacityPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new AllLeaguesWithCapacityPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map empty leagues array to DTO', () => {
|
||||
presenter.present({ leagues: [] });
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
leagues: [],
|
||||
totalCount: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('should map leagues with basic information', () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: {
|
||||
pointsSystem: 'f1-2024',
|
||||
maxDrivers: 20,
|
||||
},
|
||||
createdAt: new Date('2024-01-01T00:00:00Z'),
|
||||
});
|
||||
|
||||
presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 5,
|
||||
maxDrivers: 20,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues).toHaveLength(1);
|
||||
expect(vm.leagues[0]!.id).toBe('league-1');
|
||||
expect(vm.leagues[0]!.name).toBe('Test League');
|
||||
expect(vm.leagues[0]!.description).toBe('A test league');
|
||||
expect(vm.leagues[0]!.ownerId).toBe('owner-1');
|
||||
expect(vm.leagues[0]!.createdAt).toBe('2024-01-01T00:00:00.000Z');
|
||||
expect(vm.leagues[0]!.settings.maxDrivers).toBe(20);
|
||||
expect(vm.leagues[0]!.usedSlots).toBe(5);
|
||||
expect(vm.totalCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should map leagues with social links', () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
socialLinks: {
|
||||
discordUrl: 'https://discord.gg/test',
|
||||
youtubeUrl: 'https://youtube.com/test',
|
||||
websiteUrl: 'https://test.com',
|
||||
},
|
||||
});
|
||||
|
||||
presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 3,
|
||||
maxDrivers: 32,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.socialLinks).toEqual({
|
||||
discordUrl: 'https://discord.gg/test',
|
||||
youtubeUrl: 'https://youtube.com/test',
|
||||
websiteUrl: 'https://test.com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle leagues without social links', () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
});
|
||||
|
||||
presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 2,
|
||||
maxDrivers: 32,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.socialLinks).toEqual({});
|
||||
});
|
||||
|
||||
it('should handle multiple leagues with different configurations', () => {
|
||||
const league1 = League.create({
|
||||
id: 'league-1',
|
||||
name: 'League One',
|
||||
description: 'First league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024', maxDrivers: 20 },
|
||||
});
|
||||
|
||||
const league2 = League.create({
|
||||
id: 'league-2',
|
||||
name: 'League Two',
|
||||
description: 'Second league',
|
||||
ownerId: 'owner-2',
|
||||
settings: { pointsSystem: 'indycar', maxDrivers: 40 },
|
||||
socialLinks: { discordUrl: 'https://discord.gg/league2' },
|
||||
});
|
||||
|
||||
presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league: league1,
|
||||
currentDrivers: 10,
|
||||
maxDrivers: 20,
|
||||
},
|
||||
{
|
||||
league: league2,
|
||||
currentDrivers: 25,
|
||||
maxDrivers: 40,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues).toHaveLength(2);
|
||||
expect(vm.totalCount).toBe(2);
|
||||
expect(vm.leagues[0]!.id).toBe('league-1');
|
||||
expect(vm.leagues[0]!.settings.maxDrivers).toBe(20);
|
||||
expect(vm.leagues[0]!.usedSlots).toBe(10);
|
||||
expect(vm.leagues[1]!.id).toBe('league-2');
|
||||
expect(vm.leagues[1]!.socialLinks?.discordUrl).toBe('https://discord.gg/league2');
|
||||
expect(vm.leagues[1]!.settings.maxDrivers).toBe(40);
|
||||
expect(vm.leagues[1]!.usedSlots).toBe(25);
|
||||
});
|
||||
|
||||
it('should handle leagues with zero drivers', () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Empty League',
|
||||
description: 'No drivers yet',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024', maxDrivers: 32 },
|
||||
});
|
||||
|
||||
presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 0,
|
||||
maxDrivers: 32,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.usedSlots).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle leagues with description containing special characters', () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league with "quotes" and <tags> & symbols!',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
});
|
||||
|
||||
presenter.present({
|
||||
leagues: [
|
||||
{
|
||||
league,
|
||||
currentDrivers: 5,
|
||||
maxDrivers: 32,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm.leagues[0]!.description).toBe('A test league with "quotes" and <tags> & symbols!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getViewModel', () => {
|
||||
it('should throw error when not presented', () => {
|
||||
expect(() => presenter.getViewModel()).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('should return the model when presented', () => {
|
||||
presenter.present({ leagues: [] });
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
leagues: [],
|
||||
totalCount: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { ApproveLeagueJoinRequestPresenter } from './ApproveLeagueJoinRequestPresenter';
|
||||
|
||||
describe('ApproveLeagueJoinRequestPresenter', () => {
|
||||
let presenter: ApproveLeagueJoinRequestPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new ApproveLeagueJoinRequestPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should present successful approval result', () => {
|
||||
const result = {
|
||||
success: true,
|
||||
message: 'Join request approved successfully',
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
success: true,
|
||||
message: 'Join request approved successfully',
|
||||
});
|
||||
});
|
||||
|
||||
it('should present failed approval result', () => {
|
||||
const result = {
|
||||
success: false,
|
||||
message: 'Failed to approve join request',
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
success: false,
|
||||
message: 'Failed to approve join request',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty message', () => {
|
||||
const result = {
|
||||
success: true,
|
||||
message: '',
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
success: true,
|
||||
message: '',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getViewModel', () => {
|
||||
it('should return null before presentation', () => {
|
||||
expect(presenter.getViewModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return the model after presentation', () => {
|
||||
presenter.present({ success: true, message: 'Test' });
|
||||
|
||||
expect(presenter.getViewModel()).toEqual({
|
||||
success: true,
|
||||
message: 'Test',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should reset the model to null', () => {
|
||||
presenter.present({ success: true, message: 'Test' });
|
||||
expect(presenter.getViewModel()).not.toBeNull();
|
||||
|
||||
presenter.reset();
|
||||
|
||||
expect(presenter.getViewModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,228 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { CreateLeaguePresenter } from './CreateLeaguePresenter';
|
||||
import { League } from '@core/racing/domain/entities/League';
|
||||
import { Season } from '@core/racing/domain/entities/season/Season';
|
||||
import { LeagueScoringConfig } from '@core/racing/domain/entities/LeagueScoringConfig';
|
||||
import { PointsTable } from '@core/racing/domain/value-objects/PointsTable';
|
||||
|
||||
describe('CreateLeaguePresenter', () => {
|
||||
let presenter: CreateLeaguePresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new CreateLeaguePresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should present successful league creation', () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
});
|
||||
|
||||
const season = Season.create({
|
||||
id: 'season-1',
|
||||
leagueId: 'league-1',
|
||||
gameId: 'iracing',
|
||||
name: 'Test League Season 1',
|
||||
status: 'active',
|
||||
} as any);
|
||||
|
||||
const scoringConfig = LeagueScoringConfig.create({
|
||||
id: 'scoring-1',
|
||||
seasonId: 'season-1',
|
||||
scoringPresetId: 'preset-1',
|
||||
championships: [
|
||||
{
|
||||
id: 'champ-1',
|
||||
name: 'Driver Championship',
|
||||
type: 'driver',
|
||||
sessionTypes: ['main'],
|
||||
pointsTableBySessionType: {
|
||||
practice: new PointsTable({}),
|
||||
qualifying: new PointsTable({}),
|
||||
q1: new PointsTable({}),
|
||||
q2: new PointsTable({}),
|
||||
q3: new PointsTable({}),
|
||||
sprint: new PointsTable({}),
|
||||
main: new PointsTable({ 1: 25, 2: 18, 3: 15 }),
|
||||
timeTrial: new PointsTable({}),
|
||||
},
|
||||
dropScorePolicy: { strategy: 'none' },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
presenter.present({ league, season, scoringConfig });
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
leagueId: 'league-1',
|
||||
success: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should present league with different ID', () => {
|
||||
const league = League.create({
|
||||
id: 'league-abc-123',
|
||||
name: 'Another League',
|
||||
description: 'Another test league',
|
||||
ownerId: 'owner-2',
|
||||
settings: { pointsSystem: 'indycar' },
|
||||
});
|
||||
|
||||
const season = Season.create({
|
||||
id: 'season-2',
|
||||
leagueId: 'league-abc-123',
|
||||
gameId: 'iracing',
|
||||
name: 'Another League Season 1',
|
||||
status: 'active',
|
||||
} as any);
|
||||
|
||||
const scoringConfig = LeagueScoringConfig.create({
|
||||
id: 'scoring-2',
|
||||
seasonId: 'season-2',
|
||||
scoringPresetId: 'preset-2',
|
||||
championships: [
|
||||
{
|
||||
id: 'champ-2',
|
||||
name: 'Driver Championship',
|
||||
type: 'driver',
|
||||
sessionTypes: ['main'],
|
||||
pointsTableBySessionType: {
|
||||
practice: new PointsTable({}),
|
||||
qualifying: new PointsTable({}),
|
||||
q1: new PointsTable({}),
|
||||
q2: new PointsTable({}),
|
||||
q3: new PointsTable({}),
|
||||
sprint: new PointsTable({}),
|
||||
main: new PointsTable({ 1: 25, 2: 18, 3: 15 }),
|
||||
timeTrial: new PointsTable({}),
|
||||
},
|
||||
dropScorePolicy: { strategy: 'none' },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
presenter.present({ league, season, scoringConfig });
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
leagueId: 'league-abc-123',
|
||||
success: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getViewModel', () => {
|
||||
it('should throw error when not presented', () => {
|
||||
expect(() => presenter.getViewModel()).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('should return the model when presented', () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
});
|
||||
|
||||
const season = Season.create({
|
||||
id: 'season-1',
|
||||
leagueId: 'league-1',
|
||||
gameId: 'iracing',
|
||||
name: 'Test League Season 1',
|
||||
status: 'active',
|
||||
} as any);
|
||||
|
||||
const scoringConfig = LeagueScoringConfig.create({
|
||||
id: 'scoring-1',
|
||||
seasonId: 'season-1',
|
||||
scoringPresetId: 'preset-1',
|
||||
championships: [
|
||||
{
|
||||
id: 'champ-1',
|
||||
name: 'Driver Championship',
|
||||
type: 'driver',
|
||||
sessionTypes: ['main'],
|
||||
pointsTableBySessionType: {
|
||||
practice: new PointsTable({}),
|
||||
qualifying: new PointsTable({}),
|
||||
q1: new PointsTable({}),
|
||||
q2: new PointsTable({}),
|
||||
q3: new PointsTable({}),
|
||||
sprint: new PointsTable({}),
|
||||
main: new PointsTable({ 1: 25, 2: 18, 3: 15 }),
|
||||
timeTrial: new PointsTable({}),
|
||||
},
|
||||
dropScorePolicy: { strategy: 'none' },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
presenter.present({ league, season, scoringConfig });
|
||||
|
||||
expect(presenter.getViewModel()).toEqual({
|
||||
leagueId: 'league-1',
|
||||
success: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should reset the model and cause getViewModel to throw', () => {
|
||||
const league = League.create({
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
settings: { pointsSystem: 'f1-2024' },
|
||||
});
|
||||
|
||||
const season = Season.create({
|
||||
id: 'season-1',
|
||||
leagueId: 'league-1',
|
||||
gameId: 'iracing',
|
||||
name: 'Test League Season 1',
|
||||
status: 'active',
|
||||
} as any);
|
||||
|
||||
const scoringConfig = LeagueScoringConfig.create({
|
||||
id: 'scoring-1',
|
||||
seasonId: 'season-1',
|
||||
scoringPresetId: 'preset-1',
|
||||
championships: [
|
||||
{
|
||||
id: 'champ-1',
|
||||
name: 'Driver Championship',
|
||||
type: 'driver',
|
||||
sessionTypes: ['main'],
|
||||
pointsTableBySessionType: {
|
||||
practice: new PointsTable({}),
|
||||
qualifying: new PointsTable({}),
|
||||
q1: new PointsTable({}),
|
||||
q2: new PointsTable({}),
|
||||
q3: new PointsTable({}),
|
||||
sprint: new PointsTable({}),
|
||||
main: new PointsTable({ 1: 25, 2: 18, 3: 15 }),
|
||||
timeTrial: new PointsTable({}),
|
||||
},
|
||||
dropScorePolicy: { strategy: 'none' },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
presenter.present({ league, season, scoringConfig });
|
||||
expect(presenter.getViewModel()).not.toBeNull();
|
||||
|
||||
presenter.reset();
|
||||
|
||||
expect(() => presenter.getViewModel()).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,70 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { RejectLeagueJoinRequestPresenter } from './RejectLeagueJoinRequestPresenter';
|
||||
|
||||
describe('RejectLeagueJoinRequestPresenter', () => {
|
||||
let presenter: RejectLeagueJoinRequestPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new RejectLeagueJoinRequestPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should present successful rejection result', () => {
|
||||
const result = {
|
||||
success: true,
|
||||
message: 'Join request rejected successfully',
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
success: true,
|
||||
message: 'Join request rejected successfully',
|
||||
});
|
||||
});
|
||||
|
||||
it('should present failed rejection result', () => {
|
||||
const result = {
|
||||
success: false,
|
||||
message: 'Failed to reject join request',
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
success: false,
|
||||
message: 'Failed to reject join request',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getViewModel', () => {
|
||||
it('should return null before presentation', () => {
|
||||
expect(presenter.getViewModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return the model after presentation', () => {
|
||||
presenter.present({ success: true, message: 'Test' });
|
||||
|
||||
expect(presenter.getViewModel()).toEqual({
|
||||
success: true,
|
||||
message: 'Test',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should reset the model to null', () => {
|
||||
presenter.present({ success: true, message: 'Test' });
|
||||
expect(presenter.getViewModel()).not.toBeNull();
|
||||
|
||||
presenter.reset();
|
||||
|
||||
expect(presenter.getViewModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { TotalLeaguesPresenter } from './TotalLeaguesPresenter';
|
||||
|
||||
describe('TotalLeaguesPresenter', () => {
|
||||
let presenter: TotalLeaguesPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new TotalLeaguesPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should present total leagues count', () => {
|
||||
presenter.present({ totalLeagues: 42 });
|
||||
|
||||
const vm = presenter.getResponseModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
totalLeagues: 42,
|
||||
});
|
||||
});
|
||||
|
||||
it('should present zero total leagues', () => {
|
||||
presenter.present({ totalLeagues: 0 });
|
||||
|
||||
const vm = presenter.getResponseModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
totalLeagues: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('should present large total leagues count', () => {
|
||||
presenter.present({ totalLeagues: 999999 });
|
||||
|
||||
const vm = presenter.getResponseModel();
|
||||
|
||||
expect(vm).toEqual({
|
||||
totalLeagues: 999999,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResponseModel', () => {
|
||||
it('should return null before presentation', () => {
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return the model after presentation', () => {
|
||||
presenter.present({ totalLeagues: 10 });
|
||||
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
totalLeagues: 10,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should reset the model to null', () => {
|
||||
presenter.present({ totalLeagues: 25 });
|
||||
expect(presenter.getResponseModel()).not.toBeNull();
|
||||
|
||||
presenter.reset();
|
||||
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { DeleteMediaPresenter } from './DeleteMediaPresenter';
|
||||
|
||||
describe('DeleteMediaPresenter', () => {
|
||||
let presenter: DeleteMediaPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new DeleteMediaPresenter();
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should map successful result to response model', () => {
|
||||
const result = { mediaId: 'media-123', deleted: true };
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({ success: true });
|
||||
expect(presenter.getResponseModel()).toEqual({ success: true });
|
||||
});
|
||||
|
||||
it('should handle failed deletion', () => {
|
||||
const result = { mediaId: 'media-123', deleted: false };
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({ success: false });
|
||||
expect(presenter.getResponseModel()).toEqual({ success: false });
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.transform({ mediaId: 'media-123', deleted: true });
|
||||
expect(presenter.getResponseModel()).not.toBeNull();
|
||||
|
||||
presenter.reset();
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before transform()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({ mediaId: 'media-123', deleted: true });
|
||||
expect(presenter.responseModel).toEqual({ success: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResponseModel', () => {
|
||||
it('should return null before transform()', () => {
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({ mediaId: 'media-123', deleted: true });
|
||||
expect(presenter.getResponseModel()).toEqual({ success: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,95 @@
|
||||
import { GetAvatarPresenter } from './GetAvatarPresenter';
|
||||
|
||||
describe('GetAvatarPresenter', () => {
|
||||
let presenter: GetAvatarPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new GetAvatarPresenter();
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should map result to response model', () => {
|
||||
const result = {
|
||||
avatar: {
|
||||
id: 'avatar-123',
|
||||
driverId: 'driver-456',
|
||||
mediaUrl: 'https://example.com/avatar.png',
|
||||
selectedAt: new Date('2024-01-01'),
|
||||
},
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({ avatarUrl: 'https://example.com/avatar.png' });
|
||||
expect(presenter.getResponseModel()).toEqual({ avatarUrl: 'https://example.com/avatar.png' });
|
||||
});
|
||||
|
||||
it('should handle different avatar URLs', () => {
|
||||
const result = {
|
||||
avatar: {
|
||||
id: 'avatar-789',
|
||||
driverId: 'driver-456',
|
||||
mediaUrl: 'https://cdn.example.com/avatars/test.jpg',
|
||||
selectedAt: new Date('2024-01-02'),
|
||||
},
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({ avatarUrl: 'https://cdn.example.com/avatars/test.jpg' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.transform({
|
||||
avatar: {
|
||||
id: 'avatar-123',
|
||||
driverId: 'driver-456',
|
||||
mediaUrl: 'https://example.com/avatar.png',
|
||||
selectedAt: new Date('2024-01-01'),
|
||||
},
|
||||
});
|
||||
expect(presenter.getResponseModel()).not.toBeNull();
|
||||
|
||||
presenter.reset();
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should return null when model is null', () => {
|
||||
expect(presenter.responseModel).toBeNull();
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({
|
||||
avatar: {
|
||||
id: 'avatar-123',
|
||||
driverId: 'driver-456',
|
||||
mediaUrl: 'https://example.com/avatar.png',
|
||||
selectedAt: new Date('2024-01-01'),
|
||||
},
|
||||
});
|
||||
expect(presenter.responseModel).toEqual({ avatarUrl: 'https://example.com/avatar.png' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResponseModel', () => {
|
||||
it('should return null before transform()', () => {
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({
|
||||
avatar: {
|
||||
id: 'avatar-123',
|
||||
driverId: 'driver-456',
|
||||
mediaUrl: 'https://example.com/avatar.png',
|
||||
selectedAt: new Date('2024-01-01'),
|
||||
},
|
||||
});
|
||||
expect(presenter.getResponseModel()).toEqual({ avatarUrl: 'https://example.com/avatar.png' });
|
||||
});
|
||||
});
|
||||
});
|
||||
165
apps/api/src/domain/media/presenters/GetMediaPresenter.test.ts
Normal file
165
apps/api/src/domain/media/presenters/GetMediaPresenter.test.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
import { GetMediaPresenter } from './GetMediaPresenter';
|
||||
|
||||
describe('GetMediaPresenter', () => {
|
||||
let presenter: GetMediaPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new GetMediaPresenter();
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should map result to response model', () => {
|
||||
const result = {
|
||||
media: {
|
||||
id: 'media-123',
|
||||
filename: 'avatar.png',
|
||||
originalName: 'my-avatar.png',
|
||||
mimeType: 'image/png',
|
||||
size: 12345,
|
||||
url: 'https://example.com/avatar.png',
|
||||
type: 'image',
|
||||
uploadedBy: 'user-456',
|
||||
uploadedAt: new Date('2024-01-01'),
|
||||
},
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({
|
||||
id: 'media-123',
|
||||
url: 'https://example.com/avatar.png',
|
||||
type: 'image',
|
||||
uploadedAt: new Date('2024-01-01'),
|
||||
size: 12345,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle metadata', () => {
|
||||
const result = {
|
||||
media: {
|
||||
id: 'media-123',
|
||||
filename: 'avatar.png',
|
||||
originalName: 'my-avatar.png',
|
||||
mimeType: 'image/png',
|
||||
size: 12345,
|
||||
url: 'https://example.com/avatar.png',
|
||||
type: 'image',
|
||||
uploadedBy: 'user-456',
|
||||
uploadedAt: new Date('2024-01-01'),
|
||||
metadata: { category: 'profile', width: 100, height: 100 },
|
||||
},
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({
|
||||
id: 'media-123',
|
||||
url: 'https://example.com/avatar.png',
|
||||
type: 'image',
|
||||
uploadedAt: new Date('2024-01-01'),
|
||||
size: 12345,
|
||||
category: 'profile',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle result without metadata', () => {
|
||||
const result = {
|
||||
media: {
|
||||
id: 'media-123',
|
||||
filename: 'avatar.png',
|
||||
originalName: 'my-avatar.png',
|
||||
mimeType: 'image/png',
|
||||
size: 12345,
|
||||
url: 'https://example.com/avatar.png',
|
||||
type: 'image',
|
||||
uploadedBy: 'user-456',
|
||||
uploadedAt: new Date('2024-01-01'),
|
||||
},
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response?.category).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.transform({
|
||||
media: {
|
||||
id: 'media-123',
|
||||
filename: 'avatar.png',
|
||||
originalName: 'my-avatar.png',
|
||||
mimeType: 'image/png',
|
||||
size: 12345,
|
||||
url: 'https://example.com/avatar.png',
|
||||
type: 'image',
|
||||
uploadedBy: 'user-456',
|
||||
uploadedAt: new Date('2024-01-01'),
|
||||
},
|
||||
});
|
||||
expect(presenter.getResponseModel()).not.toBeNull();
|
||||
|
||||
presenter.reset();
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should return null when model is null', () => {
|
||||
expect(presenter.responseModel).toBeNull();
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({
|
||||
media: {
|
||||
id: 'media-123',
|
||||
filename: 'avatar.png',
|
||||
originalName: 'my-avatar.png',
|
||||
mimeType: 'image/png',
|
||||
size: 12345,
|
||||
url: 'https://example.com/avatar.png',
|
||||
type: 'image',
|
||||
uploadedBy: 'user-456',
|
||||
uploadedAt: new Date('2024-01-01'),
|
||||
},
|
||||
});
|
||||
expect(presenter.responseModel).toEqual({
|
||||
id: 'media-123',
|
||||
url: 'https://example.com/avatar.png',
|
||||
type: 'image',
|
||||
uploadedAt: new Date('2024-01-01'),
|
||||
size: 12345,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResponseModel', () => {
|
||||
it('should return null before transform()', () => {
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({
|
||||
media: {
|
||||
id: 'media-123',
|
||||
filename: 'avatar.png',
|
||||
originalName: 'my-avatar.png',
|
||||
mimeType: 'image/png',
|
||||
size: 12345,
|
||||
url: 'https://example.com/avatar.png',
|
||||
type: 'image',
|
||||
uploadedBy: 'user-456',
|
||||
uploadedAt: new Date('2024-01-01'),
|
||||
},
|
||||
});
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
id: 'media-123',
|
||||
url: 'https://example.com/avatar.png',
|
||||
type: 'image',
|
||||
uploadedAt: new Date('2024-01-01'),
|
||||
size: 12345,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,126 @@
|
||||
import { RequestAvatarGenerationPresenter } from './RequestAvatarGenerationPresenter';
|
||||
|
||||
describe('RequestAvatarGenerationPresenter', () => {
|
||||
let presenter: RequestAvatarGenerationPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new RequestAvatarGenerationPresenter();
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should map completed result to response model', () => {
|
||||
const result = {
|
||||
requestId: 'req-123',
|
||||
status: 'completed' as const,
|
||||
avatarUrls: ['https://example.com/avatar1.png', 'https://example.com/avatar2.png'],
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({
|
||||
success: true,
|
||||
requestId: 'req-123',
|
||||
avatarUrls: ['https://example.com/avatar1.png', 'https://example.com/avatar2.png'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty avatarUrls', () => {
|
||||
const result = {
|
||||
requestId: 'req-123',
|
||||
status: 'completed' as const,
|
||||
avatarUrls: [],
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({
|
||||
success: true,
|
||||
requestId: 'req-123',
|
||||
avatarUrls: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle undefined avatarUrls', () => {
|
||||
const result = {
|
||||
requestId: 'req-123',
|
||||
status: 'completed' as const,
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({
|
||||
success: true,
|
||||
requestId: 'req-123',
|
||||
avatarUrls: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle non-completed status', () => {
|
||||
const result = {
|
||||
requestId: 'req-123',
|
||||
status: 'generating' as const,
|
||||
avatarUrls: [],
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({
|
||||
success: false,
|
||||
requestId: 'req-123',
|
||||
avatarUrls: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.transform({
|
||||
requestId: 'req-123',
|
||||
status: 'completed' as const,
|
||||
avatarUrls: ['https://example.com/avatar1.png'],
|
||||
});
|
||||
expect(presenter.getResponseModel()).not.toBeNull();
|
||||
|
||||
presenter.reset();
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before transform()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({
|
||||
requestId: 'req-123',
|
||||
status: 'completed' as const,
|
||||
avatarUrls: ['https://example.com/avatar1.png'],
|
||||
});
|
||||
expect(presenter.responseModel).toEqual({
|
||||
success: true,
|
||||
requestId: 'req-123',
|
||||
avatarUrls: ['https://example.com/avatar1.png'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResponseModel', () => {
|
||||
it('should return null before transform()', () => {
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({
|
||||
requestId: 'req-123',
|
||||
status: 'completed' as const,
|
||||
avatarUrls: ['https://example.com/avatar1.png'],
|
||||
});
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
success: true,
|
||||
requestId: 'req-123',
|
||||
avatarUrls: ['https://example.com/avatar1.png'],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
import { UpdateAvatarPresenter } from './UpdateAvatarPresenter';
|
||||
|
||||
describe('UpdateAvatarPresenter', () => {
|
||||
let presenter: UpdateAvatarPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new UpdateAvatarPresenter();
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should map result to response model', () => {
|
||||
const result = {
|
||||
avatarId: 'avatar-123',
|
||||
driverId: 'driver-456',
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({ success: true });
|
||||
expect(presenter.getResponseModel()).toEqual({ success: true });
|
||||
});
|
||||
|
||||
it('should always return success true', () => {
|
||||
const result = {
|
||||
avatarId: 'avatar-789',
|
||||
driverId: 'driver-999',
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.transform({ avatarId: 'avatar-123', driverId: 'driver-456' });
|
||||
expect(presenter.getResponseModel()).not.toBeNull();
|
||||
|
||||
presenter.reset();
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before transform()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({ avatarId: 'avatar-123', driverId: 'driver-456' });
|
||||
expect(presenter.responseModel).toEqual({ success: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResponseModel', () => {
|
||||
it('should return null before transform()', () => {
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({ avatarId: 'avatar-123', driverId: 'driver-456' });
|
||||
expect(presenter.getResponseModel()).toEqual({ success: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
import { UploadMediaPresenter } from './UploadMediaPresenter';
|
||||
|
||||
describe('UploadMediaPresenter', () => {
|
||||
let presenter: UploadMediaPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new UploadMediaPresenter();
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should map result with URL to response model', () => {
|
||||
const result = {
|
||||
mediaId: 'media-123',
|
||||
url: 'https://example.com/uploaded-file.png',
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({
|
||||
success: true,
|
||||
mediaId: 'media-123',
|
||||
url: 'https://example.com/uploaded-file.png',
|
||||
});
|
||||
});
|
||||
|
||||
it('should map result without URL to response model', () => {
|
||||
const result = {
|
||||
mediaId: 'media-123',
|
||||
url: undefined,
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response).toEqual({
|
||||
success: true,
|
||||
mediaId: 'media-123',
|
||||
});
|
||||
expect(response.url).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should always set success to true', () => {
|
||||
const result = {
|
||||
mediaId: 'media-456',
|
||||
url: 'https://example.com/test.jpg',
|
||||
};
|
||||
|
||||
const response = presenter.transform(result);
|
||||
|
||||
expect(response.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.transform({ mediaId: 'media-123', url: 'https://example.com/file.png' });
|
||||
expect(presenter.getResponseModel()).not.toBeNull();
|
||||
|
||||
presenter.reset();
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before transform()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({ mediaId: 'media-123', url: 'https://example.com/file.png' });
|
||||
expect(presenter.responseModel).toEqual({
|
||||
success: true,
|
||||
mediaId: 'media-123',
|
||||
url: 'https://example.com/file.png',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResponseModel', () => {
|
||||
it('should return null before transform()', () => {
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return model after transform()', () => {
|
||||
presenter.transform({ mediaId: 'media-123', url: 'https://example.com/file.png' });
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
success: true,
|
||||
mediaId: 'media-123',
|
||||
url: 'https://example.com/file.png',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,134 @@
|
||||
import { AllRacesPageDataPresenter } from './AllRacesPageDataPresenter';
|
||||
import type { GetAllRacesPageDataResult } from '@core/racing/application/use-cases/GetAllRacesPageDataUseCase';
|
||||
|
||||
describe('AllRacesPageDataPresenter', () => {
|
||||
let presenter: AllRacesPageDataPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new AllRacesPageDataPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map result to response model', () => {
|
||||
const result: GetAllRacesPageDataResult = {
|
||||
races: [
|
||||
{
|
||||
id: 'race-1',
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
status: 'scheduled',
|
||||
leagueId: 'league-1',
|
||||
leagueName: 'League A',
|
||||
strengthOfField: 1500,
|
||||
},
|
||||
{
|
||||
id: 'race-2',
|
||||
track: 'Track B',
|
||||
car: 'Car B',
|
||||
scheduledAt: '2024-01-02T10:00:00Z',
|
||||
status: 'completed',
|
||||
leagueId: 'league-2',
|
||||
leagueName: 'League B',
|
||||
strengthOfField: null,
|
||||
},
|
||||
],
|
||||
filters: {
|
||||
statuses: [
|
||||
{ value: 'all', label: 'All Statuses' },
|
||||
{ value: 'scheduled', label: 'Scheduled' },
|
||||
],
|
||||
leagues: [
|
||||
{ id: 'league-1', name: 'League A' },
|
||||
{ id: 'league-2', name: 'League B' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
races: [
|
||||
{
|
||||
id: 'race-1',
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
status: 'scheduled',
|
||||
leagueId: 'league-1',
|
||||
leagueName: 'League A',
|
||||
strengthOfField: 1500,
|
||||
},
|
||||
{
|
||||
id: 'race-2',
|
||||
track: 'Track B',
|
||||
car: 'Car B',
|
||||
scheduledAt: '2024-01-02T10:00:00Z',
|
||||
status: 'completed',
|
||||
leagueId: 'league-2',
|
||||
leagueName: 'League B',
|
||||
strengthOfField: null,
|
||||
},
|
||||
],
|
||||
filters: {
|
||||
statuses: [
|
||||
{ value: 'all', label: 'All Statuses' },
|
||||
{ value: 'scheduled', label: 'Scheduled' },
|
||||
],
|
||||
leagues: [
|
||||
{ id: 'league-1', name: 'League A' },
|
||||
{ id: 'league-2', name: 'League B' },
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty races', () => {
|
||||
const result: GetAllRacesPageDataResult = {
|
||||
races: [],
|
||||
filters: {
|
||||
statuses: [{ value: 'all', label: 'All Statuses' }],
|
||||
leagues: [],
|
||||
},
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel.races).toEqual([]);
|
||||
expect(presenter.responseModel.filters.leagues).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
const result: GetAllRacesPageDataResult = {
|
||||
races: [{ id: 'race-1', track: 'Track A', car: 'Car A', scheduledAt: '2024-01-01', status: 'scheduled', leagueId: 'league-1', leagueName: 'League A', strengthOfField: null }],
|
||||
filters: { statuses: [], leagues: [] },
|
||||
};
|
||||
presenter.present(result);
|
||||
expect(presenter.responseModel).toBeDefined();
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before present()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
|
||||
describe('viewModel', () => {
|
||||
it('should return same as responseModel', () => {
|
||||
const result: GetAllRacesPageDataResult = {
|
||||
races: [{ id: 'race-1', track: 'Track A', car: 'Car A', scheduledAt: '2024-01-01', status: 'scheduled', leagueId: 'league-1', leagueName: 'League A', strengthOfField: null }],
|
||||
filters: { statuses: [], leagues: [] },
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.viewModel).toEqual(presenter.responseModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
import { GetTotalRacesPresenter } from './GetTotalRacesPresenter';
|
||||
import type { GetTotalRacesResult } from '@core/racing/application/use-cases/GetTotalRacesUseCase';
|
||||
|
||||
describe('GetTotalRacesPresenter', () => {
|
||||
let presenter: GetTotalRacesPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new GetTotalRacesPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map result to response model', () => {
|
||||
const result: GetTotalRacesResult = { totalRaces: 42 };
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({ totalRaces: 42 });
|
||||
});
|
||||
|
||||
it('should handle zero races', () => {
|
||||
const result: GetTotalRacesResult = { totalRaces: 0 };
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({ totalRaces: 0 });
|
||||
});
|
||||
|
||||
it('should handle large numbers', () => {
|
||||
const result: GetTotalRacesResult = { totalRaces: 999999 };
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({ totalRaces: 999999 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.present({ totalRaces: 42 });
|
||||
expect(presenter.responseModel).toBeDefined();
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before present()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
|
||||
describe('viewModel', () => {
|
||||
it('should return same as responseModel', () => {
|
||||
const result: GetTotalRacesResult = { totalRaces: 42 };
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.viewModel).toEqual(presenter.responseModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,115 @@
|
||||
import { ImportRaceResultsApiPresenter } from './ImportRaceResultsApiPresenter';
|
||||
import type { ImportRaceResultsApiResult } from '@core/racing/application/use-cases/ImportRaceResultsApiUseCase';
|
||||
|
||||
describe('ImportRaceResultsApiPresenter', () => {
|
||||
let presenter: ImportRaceResultsApiPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new ImportRaceResultsApiPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map successful result to response model', () => {
|
||||
const result: ImportRaceResultsApiResult = {
|
||||
success: true,
|
||||
raceId: 'race-123',
|
||||
leagueId: 'league-456',
|
||||
driversProcessed: 10,
|
||||
resultsRecorded: 10,
|
||||
errors: [],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
success: true,
|
||||
raceId: 'race-123',
|
||||
driversProcessed: 10,
|
||||
resultsRecorded: 10,
|
||||
errors: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle result with errors', () => {
|
||||
const result: ImportRaceResultsApiResult = {
|
||||
success: true,
|
||||
raceId: 'race-123',
|
||||
leagueId: 'league-456',
|
||||
driversProcessed: 10,
|
||||
resultsRecorded: 8,
|
||||
errors: ['Driver not found: 12345', 'Driver not found: 67890'],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
success: true,
|
||||
raceId: 'race-123',
|
||||
driversProcessed: 10,
|
||||
resultsRecorded: 8,
|
||||
errors: ['Driver not found: 12345', 'Driver not found: 67890'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle zero drivers processed', () => {
|
||||
const result: ImportRaceResultsApiResult = {
|
||||
success: true,
|
||||
raceId: 'race-123',
|
||||
leagueId: 'league-456',
|
||||
driversProcessed: 0,
|
||||
resultsRecorded: 0,
|
||||
errors: [],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
success: true,
|
||||
raceId: 'race-123',
|
||||
driversProcessed: 0,
|
||||
resultsRecorded: 0,
|
||||
errors: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.present({
|
||||
success: true,
|
||||
raceId: 'race-123',
|
||||
leagueId: 'league-456',
|
||||
driversProcessed: 10,
|
||||
resultsRecorded: 10,
|
||||
errors: [],
|
||||
});
|
||||
expect(presenter.responseModel).toBeDefined();
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before present()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
|
||||
describe('viewModel', () => {
|
||||
it('should return same as responseModel', () => {
|
||||
const result: ImportRaceResultsApiResult = {
|
||||
success: true,
|
||||
raceId: 'race-123',
|
||||
leagueId: 'league-456',
|
||||
driversProcessed: 10,
|
||||
resultsRecorded: 10,
|
||||
errors: [],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.viewModel).toEqual(presenter.responseModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,159 @@
|
||||
import { RacePenaltiesPresenter } from './RacePenaltiesPresenter';
|
||||
import type { GetRacePenaltiesResult } from '@core/racing/application/use-cases/GetRacePenaltiesUseCase';
|
||||
|
||||
describe('RacePenaltiesPresenter', () => {
|
||||
let presenter: RacePenaltiesPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new RacePenaltiesPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map result to response model', () => {
|
||||
const mockPenalty = {
|
||||
id: 'penalty-123',
|
||||
driverId: 'driver-456',
|
||||
type: 'time_penalty',
|
||||
value: 10,
|
||||
reason: 'Track limits violation',
|
||||
issuedBy: 'steward-789',
|
||||
issuedAt: new Date('2024-01-01T10:00:00Z'),
|
||||
notes: 'Multiple violations',
|
||||
};
|
||||
|
||||
const mockDriver = {
|
||||
id: 'driver-456',
|
||||
name: { toString: () => 'John Doe' } as any,
|
||||
};
|
||||
|
||||
const result: GetRacePenaltiesResult = {
|
||||
penalties: [mockPenalty as any],
|
||||
drivers: [mockDriver as any],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-123',
|
||||
driverId: 'driver-456',
|
||||
type: 'time_penalty',
|
||||
value: 10,
|
||||
reason: 'Track limits violation',
|
||||
issuedBy: 'steward-789',
|
||||
issuedAt: '2024-01-01T10:00:00.000Z',
|
||||
notes: 'Multiple violations',
|
||||
},
|
||||
],
|
||||
driverMap: {
|
||||
'driver-456': 'John Doe',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple penalties and drivers', () => {
|
||||
const result: GetRacePenaltiesResult = {
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-1',
|
||||
driverId: 'driver-1',
|
||||
type: 'time_penalty',
|
||||
value: 5,
|
||||
reason: 'Reason 1',
|
||||
issuedBy: 'steward-1',
|
||||
issuedAt: new Date('2024-01-01T10:00:00Z'),
|
||||
} as any,
|
||||
{
|
||||
id: 'penalty-2',
|
||||
driverId: 'driver-2',
|
||||
type: 'drive_through',
|
||||
value: 0,
|
||||
reason: 'Reason 2',
|
||||
issuedBy: 'steward-1',
|
||||
issuedAt: new Date('2024-01-01T10:05:00Z'),
|
||||
} as any,
|
||||
],
|
||||
drivers: [
|
||||
{ id: 'driver-1', name: { toString: () => 'Driver One' } } as any,
|
||||
{ id: 'driver-2', name: { toString: () => 'Driver Two' } } as any,
|
||||
],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel.penalties).toHaveLength(2);
|
||||
expect(presenter.responseModel.driverMap).toEqual({
|
||||
'driver-1': 'Driver One',
|
||||
'driver-2': 'Driver Two',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty penalties', () => {
|
||||
const result: GetRacePenaltiesResult = {
|
||||
penalties: [],
|
||||
drivers: [],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
penalties: [],
|
||||
driverMap: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle penalties with undefined value', () => {
|
||||
const result: GetRacePenaltiesResult = {
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-1',
|
||||
driverId: 'driver-1',
|
||||
type: 'disqualification',
|
||||
value: undefined,
|
||||
reason: 'Reason',
|
||||
issuedBy: 'steward-1',
|
||||
issuedAt: new Date('2024-01-01T10:00:00Z'),
|
||||
} as any,
|
||||
],
|
||||
drivers: [{ id: 'driver-1', name: { toString: () => 'Driver One' } } as any],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel.penalties[0]?.value).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.present({
|
||||
penalties: [{ id: 'p1', driverId: 'd1', type: 't', value: 1, reason: 'r', issuedBy: 's1', issuedAt: new Date() } as any],
|
||||
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as any],
|
||||
});
|
||||
expect(presenter.responseModel).toBeDefined();
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before present()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
|
||||
describe('viewModel', () => {
|
||||
it('should return same as responseModel', () => {
|
||||
const result: GetRacePenaltiesResult = {
|
||||
penalties: [{ id: 'p1', driverId: 'd1', type: 't', value: 1, reason: 'r', issuedBy: 's1', issuedAt: new Date() } as any],
|
||||
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as any],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.viewModel).toEqual(presenter.responseModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,198 @@
|
||||
import { RaceProtestsPresenter } from './RaceProtestsPresenter';
|
||||
import type { GetRaceProtestsResult } from '@core/racing/application/use-cases/GetRaceProtestsUseCase';
|
||||
|
||||
describe('RaceProtestsPresenter', () => {
|
||||
let presenter: RaceProtestsPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new RaceProtestsPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map result to response model', () => {
|
||||
const mockProtest = {
|
||||
id: 'protest-123',
|
||||
protestingDriverId: 'driver-456',
|
||||
accusedDriverId: 'driver-789',
|
||||
incident: {
|
||||
lap: { toNumber: () => 5 } as any,
|
||||
description: { toString: () => 'Contact at turn 3' } as any,
|
||||
},
|
||||
status: { toString: () => 'pending' } as any,
|
||||
filedAt: new Date('2024-01-01T10:30:00Z'),
|
||||
};
|
||||
|
||||
const mockDriver1 = {
|
||||
id: 'driver-456',
|
||||
name: { toString: () => 'John Doe' } as any,
|
||||
};
|
||||
|
||||
const mockDriver2 = {
|
||||
id: 'driver-789',
|
||||
name: { toString: () => 'Jane Smith' } as any,
|
||||
};
|
||||
|
||||
const result: GetRaceProtestsResult = {
|
||||
protests: [mockProtest as any],
|
||||
drivers: [mockDriver1 as any, mockDriver2 as any],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
protests: [
|
||||
{
|
||||
id: 'protest-123',
|
||||
protestingDriverId: 'driver-456',
|
||||
accusedDriverId: 'driver-789',
|
||||
incident: {
|
||||
lap: 5,
|
||||
description: 'Contact at turn 3',
|
||||
},
|
||||
status: 'pending',
|
||||
filedAt: '2024-01-01T10:30:00.000Z',
|
||||
},
|
||||
],
|
||||
driverMap: {
|
||||
'driver-456': 'John Doe',
|
||||
'driver-789': 'Jane Smith',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple protests and drivers', () => {
|
||||
const result: GetRaceProtestsResult = {
|
||||
protests: [
|
||||
{
|
||||
id: 'protest-1',
|
||||
protestingDriverId: 'driver-1',
|
||||
accusedDriverId: 'driver-2',
|
||||
incident: {
|
||||
lap: { toNumber: () => 3 } as any,
|
||||
description: { toString: () => 'Incident 1' } as any
|
||||
},
|
||||
status: { toString: () => 'pending' } as any,
|
||||
filedAt: new Date('2024-01-01T10:00:00Z'),
|
||||
} as any,
|
||||
{
|
||||
id: 'protest-2',
|
||||
protestingDriverId: 'driver-3',
|
||||
accusedDriverId: 'driver-1',
|
||||
incident: {
|
||||
lap: { toNumber: () => 7 } as any,
|
||||
description: { toString: () => 'Incident 2' } as any
|
||||
},
|
||||
status: { toString: () => 'reviewed' } as any,
|
||||
filedAt: new Date('2024-01-01T10:10:00Z'),
|
||||
} as any,
|
||||
],
|
||||
drivers: [
|
||||
{ id: 'driver-1', name: { toString: () => 'Driver One' } } as any,
|
||||
{ id: 'driver-2', name: { toString: () => 'Driver Two' } } as any,
|
||||
{ id: 'driver-3', name: { toString: () => 'Driver Three' } } as any,
|
||||
],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel.protests).toHaveLength(2);
|
||||
expect(presenter.responseModel.driverMap).toEqual({
|
||||
'driver-1': 'Driver One',
|
||||
'driver-2': 'Driver Two',
|
||||
'driver-3': 'Driver Three',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty protests', () => {
|
||||
const result: GetRaceProtestsResult = {
|
||||
protests: [],
|
||||
drivers: [],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
protests: [],
|
||||
driverMap: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle protests with reviewed status', () => {
|
||||
const result: GetRaceProtestsResult = {
|
||||
protests: [
|
||||
{
|
||||
id: 'protest-1',
|
||||
protestingDriverId: 'driver-1',
|
||||
accusedDriverId: 'driver-2',
|
||||
incident: {
|
||||
lap: { toNumber: () => 5 } as any,
|
||||
description: { toString: () => 'Test' } as any
|
||||
},
|
||||
status: { toString: () => 'approved' } as any,
|
||||
filedAt: new Date('2024-01-01T10:00:00Z'),
|
||||
} as any,
|
||||
],
|
||||
drivers: [
|
||||
{ id: 'driver-1', name: { toString: () => 'Driver One' } } as any,
|
||||
{ id: 'driver-2', name: { toString: () => 'Driver Two' } } as any,
|
||||
],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel.protests[0]?.status).toBe('approved');
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.present({
|
||||
protests: [{
|
||||
id: 'p1',
|
||||
protestingDriverId: 'd1',
|
||||
accusedDriverId: 'd2',
|
||||
incident: {
|
||||
lap: { toNumber: () => 1 } as any,
|
||||
description: { toString: () => 'test' } as any
|
||||
},
|
||||
status: { toString: () => 'pending' } as any,
|
||||
filedAt: new Date()
|
||||
} as any],
|
||||
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as any, { id: 'd2', name: { toString: () => 'D2' } } as any],
|
||||
});
|
||||
expect(presenter.responseModel).toBeDefined();
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before present()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
});
|
||||
|
||||
describe('viewModel', () => {
|
||||
it('should return same as responseModel', () => {
|
||||
const result: GetRaceProtestsResult = {
|
||||
protests: [{
|
||||
id: 'p1',
|
||||
protestingDriverId: 'd1',
|
||||
accusedDriverId: 'd2',
|
||||
incident: {
|
||||
lap: { toNumber: () => 1 } as any,
|
||||
description: { toString: () => 'test' } as any
|
||||
},
|
||||
status: { toString: () => 'pending' } as any,
|
||||
filedAt: new Date()
|
||||
} as any],
|
||||
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as any, { id: 'd2', name: { toString: () => 'D2' } } as any],
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.viewModel).toEqual(presenter.responseModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,79 @@
|
||||
import { CreateTeamPresenter } from './CreateTeamPresenter';
|
||||
|
||||
describe('CreateTeamPresenter', () => {
|
||||
let presenter: CreateTeamPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new CreateTeamPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map result to response model', () => {
|
||||
const result = {
|
||||
team: {
|
||||
id: 'team-123',
|
||||
} as any,
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
id: 'team-123',
|
||||
success: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle different team IDs', () => {
|
||||
const result = {
|
||||
team: {
|
||||
id: 'team-456',
|
||||
} as any,
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
id: 'team-456',
|
||||
success: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.present({ team: { id: 'team-123' } } as any);
|
||||
expect(presenter.responseModel).toBeDefined();
|
||||
|
||||
presenter.reset();
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResponseModel', () => {
|
||||
it('should return null before present()', () => {
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return model after present()', () => {
|
||||
presenter.present({ team: { id: 'team-123' } } as any);
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
id: 'team-123',
|
||||
success: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('responseModel', () => {
|
||||
it('should throw error when accessed before present()', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('should return model after present()', () => {
|
||||
presenter.present({ team: { id: 'team-123' } } as any);
|
||||
expect(presenter.responseModel).toEqual({
|
||||
id: 'team-123',
|
||||
success: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
218
apps/api/src/domain/team/presenters/DriverTeamPresenter.test.ts
Normal file
218
apps/api/src/domain/team/presenters/DriverTeamPresenter.test.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
import { DriverTeamPresenter } from './DriverTeamPresenter';
|
||||
|
||||
describe('DriverTeamPresenter', () => {
|
||||
let presenter: DriverTeamPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
presenter = new DriverTeamPresenter();
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map result to response model for owner', () => {
|
||||
const result = {
|
||||
driverId: 'driver-123',
|
||||
team: {
|
||||
id: 'team-456',
|
||||
name: { toString: () => 'Team Alpha' } as any,
|
||||
tag: { toString: () => 'TA' } as any,
|
||||
description: { toString: () => 'Best team' } as any,
|
||||
ownerId: { toString: () => 'driver-123' } as any,
|
||||
leagues: [{ toString: () => 'league-1' } as any],
|
||||
isRecruiting: true,
|
||||
createdAt: { toDate: () => new Date('2024-01-01') } as any,
|
||||
} as any,
|
||||
membership: {
|
||||
role: 'owner' as const,
|
||||
joinedAt: new Date('2024-01-01'),
|
||||
status: 'active' as const,
|
||||
} as any,
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
const model = presenter.getResponseModel();
|
||||
expect(model).toEqual({
|
||||
team: {
|
||||
id: 'team-456',
|
||||
name: 'Team Alpha',
|
||||
tag: 'TA',
|
||||
description: 'Best team',
|
||||
ownerId: 'driver-123',
|
||||
leagues: ['league-1'],
|
||||
isRecruiting: true,
|
||||
createdAt: '2024-01-01T00:00:00.000Z',
|
||||
},
|
||||
membership: {
|
||||
role: 'owner',
|
||||
joinedAt: '2024-01-01T00:00:00.000Z',
|
||||
isActive: true,
|
||||
},
|
||||
isOwner: true,
|
||||
canManage: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should map result for manager', () => {
|
||||
const result = {
|
||||
driverId: 'driver-456',
|
||||
team: {
|
||||
id: 'team-789',
|
||||
name: { toString: () => 'Team Beta' } as any,
|
||||
tag: { toString: () => 'TB' } as any,
|
||||
description: { toString: () => '' } as any,
|
||||
ownerId: { toString: () => 'driver-123' } as any,
|
||||
leagues: [] as any[],
|
||||
isRecruiting: false,
|
||||
createdAt: { toDate: () => new Date('2024-01-02') } as any,
|
||||
} as any,
|
||||
membership: {
|
||||
role: 'manager' as const,
|
||||
joinedAt: new Date('2024-01-02'),
|
||||
status: 'active' as const,
|
||||
} as any,
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
const model = presenter.getResponseModel();
|
||||
expect(model?.isOwner).toBe(false);
|
||||
expect(model?.canManage).toBe(true);
|
||||
expect(model?.membership.role).toBe('manager');
|
||||
});
|
||||
|
||||
it('should map result for member', () => {
|
||||
const result = {
|
||||
driverId: 'driver-789',
|
||||
team: {
|
||||
id: 'team-abc',
|
||||
name: { toString: () => 'Team Gamma' } as any,
|
||||
tag: { toString: () => 'TG' } as any,
|
||||
description: { toString: () => 'Test team' } as any,
|
||||
ownerId: { toString: () => 'driver-123' } as any,
|
||||
leagues: [{ toString: () => 'league-2' } as any],
|
||||
isRecruiting: false,
|
||||
createdAt: { toDate: () => new Date('2024-01-03') } as any,
|
||||
} as any,
|
||||
membership: {
|
||||
role: 'driver' as const,
|
||||
joinedAt: new Date('2024-01-03'),
|
||||
status: 'active' as const,
|
||||
} as any,
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
const model = presenter.getResponseModel();
|
||||
expect(model?.isOwner).toBe(false);
|
||||
expect(model?.canManage).toBe(false);
|
||||
expect(model?.membership.role).toBe('member');
|
||||
});
|
||||
|
||||
it('should handle empty description', () => {
|
||||
const result = {
|
||||
driverId: 'driver-123',
|
||||
team: {
|
||||
id: 'team-456',
|
||||
name: { toString: () => 'Team' } as any,
|
||||
tag: { toString: () => 'T' } as any,
|
||||
description: { toString: () => '' } as any,
|
||||
ownerId: { toString: () => 'driver-123' } as any,
|
||||
leagues: [] as any[],
|
||||
isRecruiting: false,
|
||||
createdAt: { toDate: () => new Date('2024-01-01') } as any,
|
||||
} as any,
|
||||
membership: {
|
||||
role: 'owner' as const,
|
||||
joinedAt: new Date('2024-01-01'),
|
||||
status: 'active' as const,
|
||||
} as any,
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
const model = presenter.getResponseModel();
|
||||
expect(model?.team.description).toBe('');
|
||||
});
|
||||
|
||||
it('should handle empty leagues', () => {
|
||||
const result = {
|
||||
driverId: 'driver-123',
|
||||
team: {
|
||||
id: 'team-456',
|
||||
name: { toString: () => 'Team' } as any,
|
||||
tag: { toString: () => 'T' } as any,
|
||||
description: { toString: () => 'Test' } as any,
|
||||
ownerId: { toString: () => 'driver-123' } as any,
|
||||
leagues: [] as any[],
|
||||
isRecruiting: false,
|
||||
createdAt: { toDate: () => new Date('2024-01-01') } as any,
|
||||
} as any,
|
||||
membership: {
|
||||
role: 'owner' as const,
|
||||
joinedAt: new Date('2024-01-01'),
|
||||
status: 'active' as const,
|
||||
} as any,
|
||||
};
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
const model = presenter.getResponseModel();
|
||||
expect(model?.team.leagues).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should clear the model', () => {
|
||||
presenter.present({
|
||||
driverId: 'driver-123',
|
||||
team: {
|
||||
id: 'team-456',
|
||||
name: { toString: () => 'Team' } as any,
|
||||
tag: { toString: () => 'T' } as any,
|
||||
description: { toString: () => '' } as any,
|
||||
ownerId: { toString: () => 'driver-123' } as any,
|
||||
leagues: [] as any[],
|
||||
isRecruiting: false,
|
||||
createdAt: { toDate: () => new Date('2024-01-01') } as any,
|
||||
} as any,
|
||||
membership: {
|
||||
role: 'owner' as const,
|
||||
joinedAt: new Date('2024-01-01'),
|
||||
status: 'active' as const,
|
||||
} as any,
|
||||
});
|
||||
expect(presenter.getResponseModel()).toBeDefined();
|
||||
|
||||
presenter.reset();
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResponseModel', () => {
|
||||
it('should return null before present()', () => {
|
||||
expect(presenter.getResponseModel()).toBeNull();
|
||||
});
|
||||
|
||||
it('should return model after present()', () => {
|
||||
presenter.present({
|
||||
driverId: 'driver-123',
|
||||
team: {
|
||||
id: 'team-456',
|
||||
name: { toString: () => 'Team' } as any,
|
||||
tag: { toString: () => 'T' } as any,
|
||||
description: { toString: () => '' } as any,
|
||||
ownerId: { toString: () => 'driver-123' } as any,
|
||||
leagues: [] as any[],
|
||||
isRecruiting: false,
|
||||
createdAt: { toDate: () => new Date('2024-01-01') } as any,
|
||||
} as any,
|
||||
membership: {
|
||||
role: 'owner' as const,
|
||||
joinedAt: new Date('2024-01-01'),
|
||||
status: 'active' as const,
|
||||
} as any,
|
||||
});
|
||||
expect(presenter.getResponseModel()).not.toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user