website refactor
This commit is contained in:
827
tests/unit/website/LeagueDetailViewDataBuilder.test.ts
Normal file
827
tests/unit/website/LeagueDetailViewDataBuilder.test.ts
Normal file
@@ -0,0 +1,827 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { LeagueDetailViewDataBuilder } from '../../../apps/website/lib/builders/view-data/LeagueDetailViewDataBuilder';
|
||||
import type { LeagueWithCapacityAndScoringDTO } from '../../../apps/website/lib/types/generated/LeagueWithCapacityAndScoringDTO';
|
||||
import type { LeagueMembershipsDTO } from '../../../apps/website/lib/types/generated/LeagueMembershipsDTO';
|
||||
import type { RaceDTO } from '../../../apps/website/lib/types/generated/RaceDTO';
|
||||
import type { GetDriverOutputDTO } from '../../../apps/website/lib/types/generated/GetDriverOutputDTO';
|
||||
import type { LeagueScoringConfigDTO } from '../../../apps/website/lib/types/generated/LeagueScoringConfigDTO';
|
||||
|
||||
describe('LeagueDetailViewDataBuilder', () => {
|
||||
const mockLeague: LeagueWithCapacityAndScoringDTO = {
|
||||
id: 'league-123',
|
||||
name: 'Test League',
|
||||
description: 'A test league description',
|
||||
ownerId: 'owner-456',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
socialLinks: {
|
||||
discordUrl: 'https://discord.gg/test',
|
||||
youtubeUrl: 'https://youtube.com/test',
|
||||
websiteUrl: 'https://test.com',
|
||||
},
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
logoUrl: 'https://logo.com/test.png',
|
||||
pendingJoinRequestsCount: 3,
|
||||
pendingProtestsCount: 1,
|
||||
walletBalance: 1000,
|
||||
};
|
||||
|
||||
const mockOwner: GetDriverOutputDTO = {
|
||||
id: 'owner-456',
|
||||
iracingId: '12345',
|
||||
name: 'John Doe',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
avatarUrl: 'https://avatar.com/john.png',
|
||||
rating: 850,
|
||||
};
|
||||
|
||||
const mockScoringConfig: LeagueScoringConfigDTO = {
|
||||
leagueId: 'league-123',
|
||||
seasonId: 'season-1',
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
championships: [],
|
||||
};
|
||||
|
||||
const mockMemberships: LeagueMembershipsDTO = {
|
||||
members: [
|
||||
{
|
||||
driverId: 'owner-456',
|
||||
driver: {
|
||||
id: 'owner-456',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
role: 'owner',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
driverId: 'admin-789',
|
||||
driver: {
|
||||
id: 'admin-789',
|
||||
name: 'Jane Smith',
|
||||
iracingId: '67890',
|
||||
country: 'UK',
|
||||
joinedAt: '2024-01-02T00:00:00Z',
|
||||
},
|
||||
role: 'admin',
|
||||
joinedAt: '2024-01-02T00:00:00Z',
|
||||
},
|
||||
{
|
||||
driverId: 'steward-101',
|
||||
driver: {
|
||||
id: 'steward-101',
|
||||
name: 'Bob Wilson',
|
||||
iracingId: '11111',
|
||||
country: 'CA',
|
||||
joinedAt: '2024-01-03T00:00:00Z',
|
||||
},
|
||||
role: 'steward',
|
||||
joinedAt: '2024-01-03T00:00:00Z',
|
||||
},
|
||||
{
|
||||
driverId: 'member-202',
|
||||
driver: {
|
||||
id: 'member-202',
|
||||
name: 'Alice Brown',
|
||||
iracingId: '22222',
|
||||
country: 'AU',
|
||||
joinedAt: '2024-01-04T00:00:00Z',
|
||||
},
|
||||
role: 'member',
|
||||
joinedAt: '2024-01-04T00:00:00Z',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const mockSponsors = [
|
||||
{
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
tier: 'main' as const,
|
||||
logoUrl: 'https://sponsor.com/logo.png',
|
||||
websiteUrl: 'https://sponsor.com',
|
||||
tagline: 'Best sponsor ever',
|
||||
},
|
||||
];
|
||||
|
||||
describe('build()', () => {
|
||||
it('should transform all input data correctly', () => {
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-2',
|
||||
name: 'Race 2',
|
||||
date: '2024-02-08T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.leagueId).toBe('league-123');
|
||||
expect(result.name).toBe('Test League');
|
||||
expect(result.description).toBe('A test league description');
|
||||
expect(result.logoUrl).toBe('https://logo.com/test.png');
|
||||
expect(result.walletBalance).toBe(1000);
|
||||
expect(result.pendingProtestsCount).toBe(1);
|
||||
expect(result.pendingJoinRequestsCount).toBe(3);
|
||||
|
||||
// Check info data
|
||||
expect(result.info.name).toBe('Test League');
|
||||
expect(result.info.description).toBe('A test league description');
|
||||
expect(result.info.membersCount).toBe(4);
|
||||
expect(result.info.racesCount).toBe(2);
|
||||
expect(result.info.avgSOF).toBeNull();
|
||||
expect(result.info.structure).toBe('Solo • 32 max');
|
||||
expect(result.info.scoring).toBe('preset-1');
|
||||
expect(result.info.createdAt).toBe('2024-01-01T00:00:00Z');
|
||||
expect(result.info.discordUrl).toBe('https://discord.gg/test');
|
||||
expect(result.info.youtubeUrl).toBe('https://youtube.com/test');
|
||||
expect(result.info.websiteUrl).toBe('https://test.com');
|
||||
|
||||
// Check owner summary
|
||||
expect(result.ownerSummary).not.toBeNull();
|
||||
expect(result.ownerSummary?.driverId).toBe('owner-456');
|
||||
expect(result.ownerSummary?.driverName).toBe('John Doe');
|
||||
expect(result.ownerSummary?.avatarUrl).toBe('https://avatar.com/john.png');
|
||||
expect(result.ownerSummary?.roleBadgeText).toBe('Owner');
|
||||
expect(result.ownerSummary?.profileUrl).toBe('/drivers/owner-456');
|
||||
|
||||
// Check admin summaries
|
||||
expect(result.adminSummaries).toHaveLength(1);
|
||||
expect(result.adminSummaries[0].driverId).toBe('admin-789');
|
||||
expect(result.adminSummaries[0].roleBadgeText).toBe('Admin');
|
||||
|
||||
// Check steward summaries
|
||||
expect(result.stewardSummaries).toHaveLength(1);
|
||||
expect(result.stewardSummaries[0].driverId).toBe('steward-101');
|
||||
expect(result.stewardSummaries[0].roleBadgeText).toBe('Steward');
|
||||
|
||||
// Check member summaries
|
||||
expect(result.memberSummaries).toHaveLength(1);
|
||||
expect(result.memberSummaries[0].driverId).toBe('member-202');
|
||||
expect(result.memberSummaries[0].roleBadgeText).toBe('Member');
|
||||
|
||||
// Check sponsors
|
||||
expect(result.sponsors).toHaveLength(1);
|
||||
expect(result.sponsors[0].id).toBe('sponsor-1');
|
||||
expect(result.sponsors[0].name).toBe('Test Sponsor');
|
||||
expect(result.sponsors[0].tier).toBe('main');
|
||||
|
||||
// Check running races (empty in this case)
|
||||
expect(result.runningRaces).toEqual([]);
|
||||
});
|
||||
|
||||
it('should calculate next race correctly', () => {
|
||||
const now = new Date();
|
||||
const futureDate = new Date(now.getTime() + 86400000).toISOString(); // 1 day from now
|
||||
const pastDate = new Date(now.getTime() - 86400000).toISOString(); // 1 day ago
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-past',
|
||||
name: 'Past Race',
|
||||
date: pastDate,
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-future-1',
|
||||
name: 'Future Race 1',
|
||||
date: futureDate,
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-future-2',
|
||||
name: 'Future Race 2',
|
||||
date: new Date(now.getTime() + 172800000).toISOString(), // 2 days from now
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.nextRace).toBeDefined();
|
||||
expect(result.nextRace?.id).toBe('race-future-1');
|
||||
expect(result.nextRace?.name).toBe('Future Race 1');
|
||||
expect(result.nextRace?.date).toBe(futureDate);
|
||||
});
|
||||
|
||||
it('should handle no upcoming races', () => {
|
||||
const pastDate = new Date(Date.now() - 86400000).toISOString();
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-past-1',
|
||||
name: 'Past Race 1',
|
||||
date: pastDate,
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-past-2',
|
||||
name: 'Past Race 2',
|
||||
date: new Date(Date.now() - 172800000).toISOString(),
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.nextRace).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should calculate season progress correctly', () => {
|
||||
const now = new Date();
|
||||
const pastDate = new Date(now.getTime() - 86400000).toISOString();
|
||||
const futureDate = new Date(now.getTime() + 86400000).toISOString();
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-past-1',
|
||||
name: 'Past Race 1',
|
||||
date: pastDate,
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-past-2',
|
||||
name: 'Past Race 2',
|
||||
date: new Date(now.getTime() - 172800000).toISOString(),
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-future-1',
|
||||
name: 'Future Race 1',
|
||||
date: futureDate,
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-future-2',
|
||||
name: 'Future Race 2',
|
||||
date: new Date(now.getTime() + 172800000).toISOString(),
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.seasonProgress).toBeDefined();
|
||||
expect(result.seasonProgress?.completedRaces).toBe(2);
|
||||
expect(result.seasonProgress?.totalRaces).toBe(4);
|
||||
expect(result.seasonProgress?.percentage).toBe(50);
|
||||
});
|
||||
|
||||
it('should handle no races for season progress', () => {
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races: [],
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.seasonProgress).toBeDefined();
|
||||
expect(result.seasonProgress?.completedRaces).toBe(0);
|
||||
expect(result.seasonProgress?.totalRaces).toBe(0);
|
||||
expect(result.seasonProgress?.percentage).toBe(0);
|
||||
});
|
||||
|
||||
it('should extract recent results from last completed race', () => {
|
||||
const now = new Date();
|
||||
const pastDate = new Date(now.getTime() - 86400000).toISOString();
|
||||
const futureDate = new Date(now.getTime() + 86400000).toISOString();
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-past-1',
|
||||
name: 'Past Race 1',
|
||||
date: pastDate,
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-past-2',
|
||||
name: 'Past Race 2',
|
||||
date: new Date(now.getTime() - 172800000).toISOString(),
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-future-1',
|
||||
name: 'Future Race 1',
|
||||
date: futureDate,
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.recentResults).toBeDefined();
|
||||
expect(result.recentResults?.length).toBe(2);
|
||||
expect(result.recentResults?.[0].raceId).toBe('race-past-1');
|
||||
expect(result.recentResults?.[0].raceName).toBe('Past Race 1');
|
||||
expect(result.recentResults?.[1].raceId).toBe('race-past-2');
|
||||
});
|
||||
|
||||
it('should handle no completed races for recent results', () => {
|
||||
const futureDate = new Date(Date.now() + 86400000).toISOString();
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-future-1',
|
||||
name: 'Future Race 1',
|
||||
date: futureDate,
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.recentResults).toBeDefined();
|
||||
expect(result.recentResults?.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle null owner', () => {
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: null,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.ownerSummary).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle null scoring config', () => {
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: null,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.info.scoring).toBe('Standard');
|
||||
});
|
||||
|
||||
it('should handle empty memberships', () => {
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: { members: [] },
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.info.membersCount).toBe(0);
|
||||
expect(result.adminSummaries).toHaveLength(0);
|
||||
expect(result.stewardSummaries).toHaveLength(0);
|
||||
expect(result.memberSummaries).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should calculate avgSOF from races with strengthOfField', () => {
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-2',
|
||||
name: 'Race 2',
|
||||
date: '2024-02-08T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
// Add strengthOfField to races
|
||||
(races[0] as any).strengthOfField = 1500;
|
||||
(races[1] as any).strengthOfField = 1800;
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.info.avgSOF).toBe(1650);
|
||||
});
|
||||
|
||||
it('should ignore races with zero or null strengthOfField', () => {
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-2',
|
||||
name: 'Race 2',
|
||||
date: '2024-02-08T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
// Add strengthOfField to races
|
||||
(races[0] as any).strengthOfField = 0;
|
||||
(races[1] as any).strengthOfField = null;
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.info.avgSOF).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle empty races array', () => {
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races: [],
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.info.racesCount).toBe(0);
|
||||
expect(result.info.avgSOF).toBeNull();
|
||||
expect(result.nextRace).toBeUndefined();
|
||||
expect(result.seasonProgress?.completedRaces).toBe(0);
|
||||
expect(result.seasonProgress?.totalRaces).toBe(0);
|
||||
expect(result.recentResults?.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle empty sponsors array', () => {
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: [],
|
||||
});
|
||||
|
||||
expect(result.sponsors).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should handle missing social links', () => {
|
||||
const leagueWithoutSocialLinks: LeagueWithCapacityAndScoringDTO = {
|
||||
...mockLeague,
|
||||
socialLinks: undefined,
|
||||
};
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: leagueWithoutSocialLinks,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.info.discordUrl).toBeUndefined();
|
||||
expect(result.info.youtubeUrl).toBeUndefined();
|
||||
expect(result.info.websiteUrl).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle missing category', () => {
|
||||
const leagueWithoutCategory: LeagueWithCapacityAndScoringDTO = {
|
||||
...mockLeague,
|
||||
category: undefined,
|
||||
};
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: leagueWithoutCategory,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.info).toBeDefined();
|
||||
});
|
||||
|
||||
it('should handle missing description', () => {
|
||||
const leagueWithoutDescription: LeagueWithCapacityAndScoringDTO = {
|
||||
...mockLeague,
|
||||
description: '',
|
||||
};
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: leagueWithoutDescription,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.description).toBe('');
|
||||
expect(result.info.description).toBe('');
|
||||
});
|
||||
|
||||
it('should handle missing logoUrl', () => {
|
||||
const leagueWithoutLogo: LeagueWithCapacityAndScoringDTO = {
|
||||
...mockLeague,
|
||||
logoUrl: undefined,
|
||||
};
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: leagueWithoutLogo,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.logoUrl).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle missing admin fields', () => {
|
||||
const leagueWithoutAdminFields: LeagueWithCapacityAndScoringDTO = {
|
||||
...mockLeague,
|
||||
pendingJoinRequestsCount: undefined,
|
||||
pendingProtestsCount: undefined,
|
||||
walletBalance: undefined,
|
||||
};
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: leagueWithoutAdminFields,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.walletBalance).toBeUndefined();
|
||||
expect(result.pendingProtestsCount).toBeUndefined();
|
||||
expect(result.pendingJoinRequestsCount).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should extract running races correctly', () => {
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Running Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-2',
|
||||
name: 'Past Race',
|
||||
date: '2024-01-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-3',
|
||||
name: 'Running Race 2',
|
||||
date: '2024-02-08T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.runningRaces).toHaveLength(2);
|
||||
expect(result.runningRaces[0].id).toBe('race-1');
|
||||
expect(result.runningRaces[0].name).toBe('Running Race 1');
|
||||
expect(result.runningRaces[0].date).toBe('2024-02-01T18:00:00Z');
|
||||
expect(result.runningRaces[1].id).toBe('race-3');
|
||||
expect(result.runningRaces[1].name).toBe('Running Race 2');
|
||||
});
|
||||
|
||||
it('should handle no running races', () => {
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Past Race 1',
|
||||
date: '2024-01-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-2',
|
||||
name: 'Past Race 2',
|
||||
date: '2024-01-08T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.runningRaces).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle races with "Running" in different positions', () => {
|
||||
const races: RaceDTO[] = [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race Running',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-2',
|
||||
name: 'Running',
|
||||
date: '2024-02-08T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
{
|
||||
id: 'race-3',
|
||||
name: 'Completed Race',
|
||||
date: '2024-02-15T18:00:00Z',
|
||||
leagueName: 'Test League',
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueDetailViewDataBuilder.build({
|
||||
league: mockLeague,
|
||||
owner: mockOwner,
|
||||
scoringConfig: mockScoringConfig,
|
||||
memberships: mockMemberships,
|
||||
races,
|
||||
sponsors: mockSponsors,
|
||||
});
|
||||
|
||||
expect(result.runningRaces).toHaveLength(2);
|
||||
expect(result.runningRaces[0].id).toBe('race-1');
|
||||
expect(result.runningRaces[1].id).toBe('race-2');
|
||||
});
|
||||
});
|
||||
});
|
||||
386
tests/unit/website/LeagueScheduleViewDataBuilder.test.ts
Normal file
386
tests/unit/website/LeagueScheduleViewDataBuilder.test.ts
Normal file
@@ -0,0 +1,386 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { LeagueScheduleViewDataBuilder } from '../../../apps/website/lib/builders/view-data/LeagueScheduleViewDataBuilder';
|
||||
import type { LeagueScheduleApiDto } from '../../../apps/website/lib/types/tbd/LeagueScheduleApiDto';
|
||||
|
||||
describe('LeagueScheduleViewDataBuilder', () => {
|
||||
const mockApiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
sessionType: 'Qualifying',
|
||||
},
|
||||
{
|
||||
id: 'race-2',
|
||||
name: 'Race 2',
|
||||
date: '2024-02-08T18:00:00Z',
|
||||
track: 'Track B',
|
||||
car: 'Car B',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
{
|
||||
id: 'race-3',
|
||||
name: 'Race 3',
|
||||
date: '2024-02-15T18:00:00Z',
|
||||
track: 'Track C',
|
||||
car: 'Car C',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe('build()', () => {
|
||||
it('should transform all races correctly', () => {
|
||||
const result = LeagueScheduleViewDataBuilder.build(mockApiDto);
|
||||
|
||||
expect(result.leagueId).toBe('league-123');
|
||||
expect(result.races).toHaveLength(3);
|
||||
|
||||
// Check first race
|
||||
expect(result.races[0].id).toBe('race-1');
|
||||
expect(result.races[0].name).toBe('Race 1');
|
||||
expect(result.races[0].scheduledAt).toBe('2024-02-01T18:00:00Z');
|
||||
expect(result.races[0].track).toBe('Track A');
|
||||
expect(result.races[0].car).toBe('Car A');
|
||||
expect(result.races[0].sessionType).toBe('Qualifying');
|
||||
});
|
||||
|
||||
it('should mark past races correctly', () => {
|
||||
const now = new Date();
|
||||
const pastDate = new Date(now.getTime() - 86400000).toISOString(); // 1 day ago
|
||||
const futureDate = new Date(now.getTime() + 86400000).toISOString(); // 1 day from now
|
||||
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-past',
|
||||
name: 'Past Race',
|
||||
date: pastDate,
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
{
|
||||
id: 'race-future',
|
||||
name: 'Future Race',
|
||||
date: futureDate,
|
||||
track: 'Track B',
|
||||
car: 'Car B',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.races[0].isPast).toBe(true);
|
||||
expect(result.races[0].isUpcoming).toBe(false);
|
||||
expect(result.races[0].status).toBe('completed');
|
||||
|
||||
expect(result.races[1].isPast).toBe(false);
|
||||
expect(result.races[1].isUpcoming).toBe(true);
|
||||
expect(result.races[1].status).toBe('scheduled');
|
||||
});
|
||||
|
||||
it('should mark upcoming races correctly', () => {
|
||||
const now = new Date();
|
||||
const futureDate = new Date(now.getTime() + 86400000).toISOString(); // 1 day from now
|
||||
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-future',
|
||||
name: 'Future Race',
|
||||
date: futureDate,
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.races[0].isPast).toBe(false);
|
||||
expect(result.races[0].isUpcoming).toBe(true);
|
||||
expect(result.races[0].status).toBe('scheduled');
|
||||
});
|
||||
|
||||
it('should handle empty schedule', () => {
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagueId).toBe('league-123');
|
||||
expect(result.races).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should handle races with missing optional fields', () => {
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
track: undefined,
|
||||
car: undefined,
|
||||
sessionType: undefined,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.races[0].track).toBeUndefined();
|
||||
expect(result.races[0].car).toBeUndefined();
|
||||
expect(result.races[0].sessionType).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle current driver ID parameter', () => {
|
||||
const result = LeagueScheduleViewDataBuilder.build(mockApiDto, 'driver-456');
|
||||
|
||||
expect(result.currentDriverId).toBe('driver-456');
|
||||
});
|
||||
|
||||
it('should handle admin permission parameter', () => {
|
||||
const result = LeagueScheduleViewDataBuilder.build(mockApiDto, 'driver-456', true);
|
||||
|
||||
expect(result.isAdmin).toBe(true);
|
||||
expect(result.races[0].canEdit).toBe(true);
|
||||
expect(result.races[0].canReschedule).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle non-admin permission parameter', () => {
|
||||
const result = LeagueScheduleViewDataBuilder.build(mockApiDto, 'driver-456', false);
|
||||
|
||||
expect(result.isAdmin).toBe(false);
|
||||
expect(result.races[0].canEdit).toBe(false);
|
||||
expect(result.races[0].canReschedule).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle default admin parameter as false', () => {
|
||||
const result = LeagueScheduleViewDataBuilder.build(mockApiDto, 'driver-456');
|
||||
|
||||
expect(result.isAdmin).toBe(false);
|
||||
expect(result.races[0].canEdit).toBe(false);
|
||||
expect(result.races[0].canReschedule).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle registration status for upcoming races', () => {
|
||||
const now = new Date();
|
||||
const futureDate = new Date(now.getTime() + 86400000).toISOString();
|
||||
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-future',
|
||||
name: 'Future Race',
|
||||
date: futureDate,
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.races[0].isUserRegistered).toBe(false);
|
||||
expect(result.races[0].canRegister).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle registration status for past races', () => {
|
||||
const now = new Date();
|
||||
const pastDate = new Date(now.getTime() - 86400000).toISOString();
|
||||
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-past',
|
||||
name: 'Past Race',
|
||||
date: pastDate,
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.races[0].isUserRegistered).toBe(false);
|
||||
expect(result.races[0].canRegister).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle races exactly at current time', () => {
|
||||
const now = new Date();
|
||||
const exactDate = now.toISOString();
|
||||
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-exact',
|
||||
name: 'Exact Race',
|
||||
date: exactDate,
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
// Race at exact current time is considered upcoming (not past)
|
||||
// because the comparison uses < (strictly less than)
|
||||
expect(result.races[0].isPast).toBe(false);
|
||||
expect(result.races[0].isUpcoming).toBe(true);
|
||||
expect(result.races[0].status).toBe('scheduled');
|
||||
});
|
||||
|
||||
it('should handle races with different session types', () => {
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-qualifying',
|
||||
name: 'Qualifying',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
sessionType: 'Qualifying',
|
||||
},
|
||||
{
|
||||
id: 'race-practice',
|
||||
name: 'Practice',
|
||||
date: '2024-02-02T18:00:00Z',
|
||||
track: 'Track B',
|
||||
car: 'Car B',
|
||||
sessionType: 'Practice',
|
||||
},
|
||||
{
|
||||
id: 'race-race',
|
||||
name: 'Race',
|
||||
date: '2024-02-03T18:00:00Z',
|
||||
track: 'Track C',
|
||||
car: 'Car C',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.races[0].sessionType).toBe('Qualifying');
|
||||
expect(result.races[1].sessionType).toBe('Practice');
|
||||
expect(result.races[2].sessionType).toBe('Race');
|
||||
});
|
||||
|
||||
it('should handle races without session type', () => {
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.races[0].sessionType).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle races with empty track and car', () => {
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-1',
|
||||
name: 'Race 1',
|
||||
date: '2024-02-01T18:00:00Z',
|
||||
track: '',
|
||||
car: '',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.races[0].track).toBe('');
|
||||
expect(result.races[0].car).toBe('');
|
||||
});
|
||||
|
||||
it('should handle multiple races with mixed dates', () => {
|
||||
const now = new Date();
|
||||
const pastDate1 = new Date(now.getTime() - 172800000).toISOString(); // 2 days ago
|
||||
const pastDate2 = new Date(now.getTime() - 86400000).toISOString(); // 1 day ago
|
||||
const futureDate1 = new Date(now.getTime() + 86400000).toISOString(); // 1 day from now
|
||||
const futureDate2 = new Date(now.getTime() + 172800000).toISOString(); // 2 days from now
|
||||
|
||||
const apiDto: LeagueScheduleApiDto = {
|
||||
leagueId: 'league-123',
|
||||
races: [
|
||||
{
|
||||
id: 'race-past-2',
|
||||
name: 'Past Race 2',
|
||||
date: pastDate1,
|
||||
track: 'Track A',
|
||||
car: 'Car A',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
{
|
||||
id: 'race-past-1',
|
||||
name: 'Past Race 1',
|
||||
date: pastDate2,
|
||||
track: 'Track B',
|
||||
car: 'Car B',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
{
|
||||
id: 'race-future-1',
|
||||
name: 'Future Race 1',
|
||||
date: futureDate1,
|
||||
track: 'Track C',
|
||||
car: 'Car C',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
{
|
||||
id: 'race-future-2',
|
||||
name: 'Future Race 2',
|
||||
date: futureDate2,
|
||||
track: 'Track D',
|
||||
car: 'Car D',
|
||||
sessionType: 'Race',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = LeagueScheduleViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.races).toHaveLength(4);
|
||||
expect(result.races[0].isPast).toBe(true);
|
||||
expect(result.races[1].isPast).toBe(true);
|
||||
expect(result.races[2].isPast).toBe(false);
|
||||
expect(result.races[3].isPast).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
541
tests/unit/website/LeagueStandingsViewDataBuilder.test.ts
Normal file
541
tests/unit/website/LeagueStandingsViewDataBuilder.test.ts
Normal file
@@ -0,0 +1,541 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { LeagueStandingsViewDataBuilder } from '../../../apps/website/lib/builders/view-data/LeagueStandingsViewDataBuilder';
|
||||
import type { LeagueStandingDTO } from '../../../apps/website/lib/types/generated/LeagueStandingDTO';
|
||||
import type { LeagueMemberDTO } from '../../../apps/website/lib/types/generated/LeagueMemberDTO';
|
||||
|
||||
describe('LeagueStandingsViewDataBuilder', () => {
|
||||
const mockStandings: LeagueStandingDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
points: 150,
|
||||
position: 1,
|
||||
wins: 3,
|
||||
podiums: 5,
|
||||
races: 10,
|
||||
positionChange: 0,
|
||||
lastRacePoints: 25,
|
||||
droppedRaceIds: ['race-1', 'race-2'],
|
||||
},
|
||||
{
|
||||
driverId: 'driver-2',
|
||||
driver: {
|
||||
id: 'driver-2',
|
||||
name: 'Jane Smith',
|
||||
iracingId: '67890',
|
||||
country: 'UK',
|
||||
joinedAt: '2024-01-02T00:00:00Z',
|
||||
},
|
||||
points: 120,
|
||||
position: 2,
|
||||
wins: 2,
|
||||
podiums: 4,
|
||||
races: 10,
|
||||
positionChange: 1,
|
||||
lastRacePoints: 18,
|
||||
droppedRaceIds: ['race-3'],
|
||||
},
|
||||
{
|
||||
driverId: 'driver-3',
|
||||
driver: {
|
||||
id: 'driver-3',
|
||||
name: 'Bob Wilson',
|
||||
iracingId: '11111',
|
||||
country: 'CA',
|
||||
joinedAt: '2024-01-03T00:00:00Z',
|
||||
},
|
||||
points: 90,
|
||||
position: 3,
|
||||
wins: 1,
|
||||
podiums: 3,
|
||||
races: 10,
|
||||
positionChange: -1,
|
||||
lastRacePoints: 12,
|
||||
droppedRaceIds: [],
|
||||
},
|
||||
];
|
||||
|
||||
const mockMemberships: LeagueMemberDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
role: 'member',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
driverId: 'driver-2',
|
||||
driver: {
|
||||
id: 'driver-2',
|
||||
name: 'Jane Smith',
|
||||
iracingId: '67890',
|
||||
country: 'UK',
|
||||
joinedAt: '2024-01-02T00:00:00Z',
|
||||
},
|
||||
role: 'member',
|
||||
joinedAt: '2024-01-02T00:00:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
describe('build()', () => {
|
||||
it('should transform standings correctly', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: mockStandings },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.leagueId).toBe('league-123');
|
||||
expect(result.standings).toHaveLength(3);
|
||||
|
||||
// Check first standing
|
||||
expect(result.standings[0].driverId).toBe('driver-1');
|
||||
expect(result.standings[0].position).toBe(1);
|
||||
expect(result.standings[0].totalPoints).toBe(150);
|
||||
expect(result.standings[0].racesFinished).toBe(10);
|
||||
expect(result.standings[0].racesStarted).toBe(10);
|
||||
expect(result.standings[0].positionChange).toBe(0);
|
||||
expect(result.standings[0].lastRacePoints).toBe(25);
|
||||
expect(result.standings[0].droppedRaceIds).toEqual(['race-1', 'race-2']);
|
||||
expect(result.standings[0].wins).toBe(3);
|
||||
expect(result.standings[0].podiums).toBe(5);
|
||||
});
|
||||
|
||||
it('should calculate position change correctly', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: mockStandings },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].positionChange).toBe(0); // No change
|
||||
expect(result.standings[1].positionChange).toBe(1); // Moved up
|
||||
expect(result.standings[2].positionChange).toBe(-1); // Moved down
|
||||
});
|
||||
|
||||
it('should map last race points correctly', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: mockStandings },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].lastRacePoints).toBe(25);
|
||||
expect(result.standings[1].lastRacePoints).toBe(18);
|
||||
expect(result.standings[2].lastRacePoints).toBe(12);
|
||||
});
|
||||
|
||||
it('should handle dropped race IDs correctly', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: mockStandings },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].droppedRaceIds).toEqual(['race-1', 'race-2']);
|
||||
expect(result.standings[1].droppedRaceIds).toEqual(['race-3']);
|
||||
expect(result.standings[2].droppedRaceIds).toEqual([]);
|
||||
});
|
||||
|
||||
it('should calculate championship stats (wins, podiums)', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: mockStandings },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].wins).toBe(3);
|
||||
expect(result.standings[0].podiums).toBe(5);
|
||||
expect(result.standings[1].wins).toBe(2);
|
||||
expect(result.standings[1].podiums).toBe(4);
|
||||
expect(result.standings[2].wins).toBe(1);
|
||||
expect(result.standings[2].podiums).toBe(3);
|
||||
});
|
||||
|
||||
it('should extract driver metadata correctly', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: mockStandings },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.drivers).toHaveLength(3);
|
||||
|
||||
// Check first driver
|
||||
expect(result.drivers[0].id).toBe('driver-1');
|
||||
expect(result.drivers[0].name).toBe('John Doe');
|
||||
expect(result.drivers[0].iracingId).toBe('12345');
|
||||
expect(result.drivers[0].country).toBe('US');
|
||||
});
|
||||
|
||||
it('should convert memberships correctly', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: mockStandings },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.memberships).toHaveLength(2);
|
||||
|
||||
// Check first membership
|
||||
expect(result.memberships[0].driverId).toBe('driver-1');
|
||||
expect(result.memberships[0].leagueId).toBe('league-123');
|
||||
expect(result.memberships[0].role).toBe('member');
|
||||
expect(result.memberships[0].status).toBe('active');
|
||||
});
|
||||
|
||||
it('should handle empty standings', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: [] },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings).toHaveLength(0);
|
||||
expect(result.drivers).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should handle empty memberships', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: mockStandings },
|
||||
{ members: [] },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.memberships).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should handle missing driver objects in standings', () => {
|
||||
const standingsWithMissingDriver: LeagueStandingDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
points: 150,
|
||||
position: 1,
|
||||
wins: 3,
|
||||
podiums: 5,
|
||||
races: 10,
|
||||
positionChange: 0,
|
||||
lastRacePoints: 25,
|
||||
droppedRaceIds: [],
|
||||
},
|
||||
{
|
||||
driverId: 'driver-2',
|
||||
driver: {
|
||||
id: 'driver-2',
|
||||
name: 'Jane Smith',
|
||||
iracingId: '67890',
|
||||
country: 'UK',
|
||||
joinedAt: '2024-01-02T00:00:00Z',
|
||||
},
|
||||
points: 120,
|
||||
position: 2,
|
||||
wins: 2,
|
||||
podiums: 4,
|
||||
races: 10,
|
||||
positionChange: 1,
|
||||
lastRacePoints: 18,
|
||||
droppedRaceIds: [],
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: standingsWithMissingDriver },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.drivers).toHaveLength(2);
|
||||
expect(result.drivers[0].id).toBe('driver-1');
|
||||
expect(result.drivers[1].id).toBe('driver-2');
|
||||
});
|
||||
|
||||
it('should handle standings with missing positionChange', () => {
|
||||
const standingsWithoutPositionChange: LeagueStandingDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
points: 150,
|
||||
position: 1,
|
||||
wins: 3,
|
||||
podiums: 5,
|
||||
races: 10,
|
||||
positionChange: undefined as any,
|
||||
lastRacePoints: 25,
|
||||
droppedRaceIds: [],
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: standingsWithoutPositionChange },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].positionChange).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle standings with missing lastRacePoints', () => {
|
||||
const standingsWithoutLastRacePoints: LeagueStandingDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
points: 150,
|
||||
position: 1,
|
||||
wins: 3,
|
||||
podiums: 5,
|
||||
races: 10,
|
||||
positionChange: 0,
|
||||
lastRacePoints: undefined as any,
|
||||
droppedRaceIds: [],
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: standingsWithoutLastRacePoints },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].lastRacePoints).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle standings with missing droppedRaceIds', () => {
|
||||
const standingsWithoutDroppedRaceIds: LeagueStandingDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
points: 150,
|
||||
position: 1,
|
||||
wins: 3,
|
||||
podiums: 5,
|
||||
races: 10,
|
||||
positionChange: 0,
|
||||
lastRacePoints: 25,
|
||||
droppedRaceIds: undefined as any,
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: standingsWithoutDroppedRaceIds },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].droppedRaceIds).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle standings with missing wins', () => {
|
||||
const standingsWithoutWins: LeagueStandingDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
points: 150,
|
||||
position: 1,
|
||||
wins: undefined as any,
|
||||
podiums: 5,
|
||||
races: 10,
|
||||
positionChange: 0,
|
||||
lastRacePoints: 25,
|
||||
droppedRaceIds: [],
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: standingsWithoutWins },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].wins).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle standings with missing podiums', () => {
|
||||
const standingsWithoutPodiums: LeagueStandingDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
points: 150,
|
||||
position: 1,
|
||||
wins: 3,
|
||||
podiums: undefined as any,
|
||||
races: 10,
|
||||
positionChange: 0,
|
||||
lastRacePoints: 25,
|
||||
droppedRaceIds: [],
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: standingsWithoutPodiums },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].podiums).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle team championship mode', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: mockStandings },
|
||||
{ members: mockMemberships },
|
||||
'league-123',
|
||||
true
|
||||
);
|
||||
|
||||
expect(result.isTeamChampionship).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle non-team championship mode by default', () => {
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: mockStandings },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.isTeamChampionship).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle standings with zero points', () => {
|
||||
const standingsWithZeroPoints: LeagueStandingDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
points: 0,
|
||||
position: 1,
|
||||
wins: 0,
|
||||
podiums: 0,
|
||||
races: 10,
|
||||
positionChange: 0,
|
||||
lastRacePoints: 0,
|
||||
droppedRaceIds: [],
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: standingsWithZeroPoints },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].totalPoints).toBe(0);
|
||||
expect(result.standings[0].wins).toBe(0);
|
||||
expect(result.standings[0].podiums).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle standings with negative position change', () => {
|
||||
const standingsWithNegativeChange: LeagueStandingDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
points: 150,
|
||||
position: 1,
|
||||
wins: 3,
|
||||
podiums: 5,
|
||||
races: 10,
|
||||
positionChange: -2,
|
||||
lastRacePoints: 25,
|
||||
droppedRaceIds: [],
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: standingsWithNegativeChange },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].positionChange).toBe(-2);
|
||||
});
|
||||
|
||||
it('should handle standings with positive position change', () => {
|
||||
const standingsWithPositiveChange: LeagueStandingDTO[] = [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'John Doe',
|
||||
iracingId: '12345',
|
||||
country: 'US',
|
||||
joinedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
points: 150,
|
||||
position: 1,
|
||||
wins: 3,
|
||||
podiums: 5,
|
||||
races: 10,
|
||||
positionChange: 3,
|
||||
lastRacePoints: 25,
|
||||
droppedRaceIds: [],
|
||||
},
|
||||
];
|
||||
|
||||
const result = LeagueStandingsViewDataBuilder.build(
|
||||
{ standings: standingsWithPositiveChange },
|
||||
{ members: mockMemberships },
|
||||
'league-123'
|
||||
);
|
||||
|
||||
expect(result.standings[0].positionChange).toBe(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
932
tests/unit/website/LeaguesViewDataBuilder.test.ts
Normal file
932
tests/unit/website/LeaguesViewDataBuilder.test.ts
Normal file
@@ -0,0 +1,932 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { LeaguesViewDataBuilder } from '../../../apps/website/lib/builders/view-data/LeaguesViewDataBuilder';
|
||||
import type { AllLeaguesWithCapacityAndScoringDTO } from '../../../apps/website/lib/types/generated/AllLeaguesWithCapacityAndScoringDTO';
|
||||
import type { LeagueWithCapacityAndScoringDTO } from '../../../apps/website/lib/types/generated/LeagueWithCapacityAndScoringDTO';
|
||||
|
||||
describe('LeaguesViewDataBuilder', () => {
|
||||
const mockLeagues: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Test League 1',
|
||||
description: 'A test league description',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
socialLinks: {
|
||||
discordUrl: 'https://discord.gg/test1',
|
||||
youtubeUrl: 'https://youtube.com/test1',
|
||||
websiteUrl: 'https://test1.com',
|
||||
},
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game 1',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
logoUrl: 'https://logo.com/test1.png',
|
||||
pendingJoinRequestsCount: 3,
|
||||
pendingProtestsCount: 1,
|
||||
walletBalance: 1000,
|
||||
},
|
||||
{
|
||||
id: 'league-2',
|
||||
name: 'Test League 2',
|
||||
description: 'Another test league',
|
||||
ownerId: 'owner-2',
|
||||
createdAt: '2024-01-02T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 16,
|
||||
qualifyingFormat: 'Team',
|
||||
},
|
||||
usedSlots: 8,
|
||||
category: 'Oval',
|
||||
socialLinks: {
|
||||
discordUrl: 'https://discord.gg/test2',
|
||||
},
|
||||
scoring: {
|
||||
gameId: 'game-2',
|
||||
gameName: 'Test Game 2',
|
||||
primaryChampionshipType: 'Team',
|
||||
scoringPresetId: 'preset-2',
|
||||
scoringPresetName: 'Advanced',
|
||||
dropPolicySummary: 'Drop 1 worst race',
|
||||
scoringPatternSummary: 'Points based on finish position with bonuses',
|
||||
},
|
||||
timingSummary: 'Every Saturday at 7 PM',
|
||||
logoUrl: 'https://logo.com/test2.png',
|
||||
},
|
||||
{
|
||||
id: 'league-3',
|
||||
name: 'Test League 3',
|
||||
description: 'A third test league',
|
||||
ownerId: 'owner-3',
|
||||
createdAt: '2024-01-03T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 24,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 24,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-3',
|
||||
gameName: 'Test Game 3',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-3',
|
||||
scoringPresetName: 'Custom',
|
||||
dropPolicySummary: 'No drops',
|
||||
scoringPatternSummary: 'Fixed points per position',
|
||||
},
|
||||
timingSummary: 'Every Friday at 9 PM',
|
||||
},
|
||||
];
|
||||
|
||||
describe('build()', () => {
|
||||
it('should transform all leagues correctly', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues).toHaveLength(3);
|
||||
|
||||
// Check first league
|
||||
expect(result.leagues[0].id).toBe('league-1');
|
||||
expect(result.leagues[0].name).toBe('Test League 1');
|
||||
expect(result.leagues[0].description).toBe('A test league description');
|
||||
expect(result.leagues[0].logoUrl).toBe('https://logo.com/test1.png');
|
||||
expect(result.leagues[0].ownerId).toBe('owner-1');
|
||||
expect(result.leagues[0].createdAt).toBe('2024-01-01T00:00:00Z');
|
||||
expect(result.leagues[0].maxDrivers).toBe(32);
|
||||
expect(result.leagues[0].usedDriverSlots).toBe(15);
|
||||
expect(result.leagues[0].structureSummary).toBe('Solo');
|
||||
expect(result.leagues[0].timingSummary).toBe('Every Sunday at 8 PM');
|
||||
expect(result.leagues[0].category).toBe('Road');
|
||||
|
||||
// Check scoring
|
||||
expect(result.leagues[0].scoring).toBeDefined();
|
||||
expect(result.leagues[0].scoring?.gameId).toBe('game-1');
|
||||
expect(result.leagues[0].scoring?.gameName).toBe('Test Game 1');
|
||||
expect(result.leagues[0].scoring?.primaryChampionshipType).toBe('Solo');
|
||||
expect(result.leagues[0].scoring?.scoringPresetId).toBe('preset-1');
|
||||
expect(result.leagues[0].scoring?.scoringPresetName).toBe('Standard');
|
||||
expect(result.leagues[0].scoring?.dropPolicySummary).toBe('Drop 2 worst races');
|
||||
expect(result.leagues[0].scoring?.scoringPatternSummary).toBe('Points based on finish position');
|
||||
});
|
||||
|
||||
it('should handle leagues with missing description', () => {
|
||||
const leaguesWithoutDescription: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: '',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
];
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithoutDescription,
|
||||
totalCount: 1,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].description).toBe(null);
|
||||
});
|
||||
|
||||
it('should handle leagues with missing logoUrl', () => {
|
||||
const leaguesWithoutLogo: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
];
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithoutLogo,
|
||||
totalCount: 1,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].logoUrl).toBe(null);
|
||||
});
|
||||
|
||||
it('should handle leagues with missing category', () => {
|
||||
const leaguesWithoutCategory: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
];
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithoutCategory,
|
||||
totalCount: 1,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].category).toBe(null);
|
||||
});
|
||||
|
||||
it('should handle leagues with missing scoring', () => {
|
||||
const leaguesWithoutScoring: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
];
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithoutScoring,
|
||||
totalCount: 1,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].scoring).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle leagues with missing social links', () => {
|
||||
const leaguesWithoutSocialLinks: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
];
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithoutSocialLinks,
|
||||
totalCount: 1,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0]).toBeDefined();
|
||||
});
|
||||
|
||||
it('should handle leagues with missing timingSummary', () => {
|
||||
const leaguesWithoutTimingSummary: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithoutTimingSummary,
|
||||
totalCount: 1,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].timingSummary).toBe('');
|
||||
});
|
||||
|
||||
it('should handle empty leagues array', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: [],
|
||||
totalCount: 0,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should handle leagues with different categories', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].category).toBe('Road');
|
||||
expect(result.leagues[1].category).toBe('Oval');
|
||||
expect(result.leagues[2].category).toBe('Road');
|
||||
});
|
||||
|
||||
it('should handle leagues with different structures', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].structureSummary).toBe('Solo');
|
||||
expect(result.leagues[1].structureSummary).toBe('Team');
|
||||
expect(result.leagues[2].structureSummary).toBe('Solo');
|
||||
});
|
||||
|
||||
it('should handle leagues with different scoring presets', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].scoring?.scoringPresetName).toBe('Standard');
|
||||
expect(result.leagues[1].scoring?.scoringPresetName).toBe('Advanced');
|
||||
expect(result.leagues[2].scoring?.scoringPresetName).toBe('Custom');
|
||||
});
|
||||
|
||||
it('should handle leagues with different drop policies', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].scoring?.dropPolicySummary).toBe('Drop 2 worst races');
|
||||
expect(result.leagues[1].scoring?.dropPolicySummary).toBe('Drop 1 worst race');
|
||||
expect(result.leagues[2].scoring?.dropPolicySummary).toBe('No drops');
|
||||
});
|
||||
|
||||
it('should handle leagues with different scoring patterns', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].scoring?.scoringPatternSummary).toBe('Points based on finish position');
|
||||
expect(result.leagues[1].scoring?.scoringPatternSummary).toBe('Points based on finish position with bonuses');
|
||||
expect(result.leagues[2].scoring?.scoringPatternSummary).toBe('Fixed points per position');
|
||||
});
|
||||
|
||||
it('should handle leagues with different primary championship types', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].scoring?.primaryChampionshipType).toBe('Solo');
|
||||
expect(result.leagues[1].scoring?.primaryChampionshipType).toBe('Team');
|
||||
expect(result.leagues[2].scoring?.primaryChampionshipType).toBe('Solo');
|
||||
});
|
||||
|
||||
it('should handle leagues with different game names', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].scoring?.gameName).toBe('Test Game 1');
|
||||
expect(result.leagues[1].scoring?.gameName).toBe('Test Game 2');
|
||||
expect(result.leagues[2].scoring?.gameName).toBe('Test Game 3');
|
||||
});
|
||||
|
||||
it('should handle leagues with different game IDs', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].scoring?.gameId).toBe('game-1');
|
||||
expect(result.leagues[1].scoring?.gameId).toBe('game-2');
|
||||
expect(result.leagues[2].scoring?.gameId).toBe('game-3');
|
||||
});
|
||||
|
||||
it('should handle leagues with different max drivers', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].maxDrivers).toBe(32);
|
||||
expect(result.leagues[1].maxDrivers).toBe(16);
|
||||
expect(result.leagues[2].maxDrivers).toBe(24);
|
||||
});
|
||||
|
||||
it('should handle leagues with different used slots', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].usedDriverSlots).toBe(15);
|
||||
expect(result.leagues[1].usedDriverSlots).toBe(8);
|
||||
expect(result.leagues[2].usedDriverSlots).toBe(24);
|
||||
});
|
||||
|
||||
it('should handle leagues with different owners', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].ownerId).toBe('owner-1');
|
||||
expect(result.leagues[1].ownerId).toBe('owner-2');
|
||||
expect(result.leagues[2].ownerId).toBe('owner-3');
|
||||
});
|
||||
|
||||
it('should handle leagues with different creation dates', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].createdAt).toBe('2024-01-01T00:00:00Z');
|
||||
expect(result.leagues[1].createdAt).toBe('2024-01-02T00:00:00Z');
|
||||
expect(result.leagues[2].createdAt).toBe('2024-01-03T00:00:00Z');
|
||||
});
|
||||
|
||||
it('should handle leagues with different timing summaries', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].timingSummary).toBe('Every Sunday at 8 PM');
|
||||
expect(result.leagues[1].timingSummary).toBe('Every Saturday at 7 PM');
|
||||
expect(result.leagues[2].timingSummary).toBe('Every Friday at 9 PM');
|
||||
});
|
||||
|
||||
it('should handle leagues with different names', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].name).toBe('Test League 1');
|
||||
expect(result.leagues[1].name).toBe('Test League 2');
|
||||
expect(result.leagues[2].name).toBe('Test League 3');
|
||||
});
|
||||
|
||||
it('should handle leagues with different descriptions', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].description).toBe('A test league description');
|
||||
expect(result.leagues[1].description).toBe('Another test league');
|
||||
expect(result.leagues[2].description).toBe('A third test league');
|
||||
});
|
||||
|
||||
it('should handle leagues with different logo URLs', () => {
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: mockLeagues,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].logoUrl).toBe('https://logo.com/test1.png');
|
||||
expect(result.leagues[1].logoUrl).toBe('https://logo.com/test2.png');
|
||||
expect(result.leagues[2].logoUrl).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle leagues with activeDriversCount', () => {
|
||||
const leaguesWithActiveDrivers: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
];
|
||||
|
||||
// Add activeDriversCount to the league
|
||||
(leaguesWithActiveDrivers[0] as any).activeDriversCount = 12;
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithActiveDrivers,
|
||||
totalCount: 1,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].activeDriversCount).toBe(12);
|
||||
});
|
||||
|
||||
it('should handle leagues with nextRaceAt', () => {
|
||||
const leaguesWithNextRace: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
];
|
||||
|
||||
// Add nextRaceAt to the league
|
||||
(leaguesWithNextRace[0] as any).nextRaceAt = '2024-02-01T18:00:00Z';
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithNextRace,
|
||||
totalCount: 1,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].nextRaceAt).toBe('2024-02-01T18:00:00Z');
|
||||
});
|
||||
|
||||
it('should handle leagues without activeDriversCount and nextRaceAt', () => {
|
||||
const leaguesWithoutMetadata: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
];
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithoutMetadata,
|
||||
totalCount: 1,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.leagues[0].activeDriversCount).toBeUndefined();
|
||||
expect(result.leagues[0].nextRaceAt).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle leagues with different usedDriverSlots for featured leagues', () => {
|
||||
const leaguesWithDifferentSlots: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Small League',
|
||||
description: 'A small league',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 16,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 8,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
{
|
||||
id: 'league-2',
|
||||
name: 'Large League',
|
||||
description: 'A large league',
|
||||
ownerId: 'owner-2',
|
||||
createdAt: '2024-01-02T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 25,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-2',
|
||||
gameName: 'Test Game 2',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-2',
|
||||
scoringPresetName: 'Advanced',
|
||||
dropPolicySummary: 'Drop 1 worst race',
|
||||
scoringPatternSummary: 'Points based on finish position with bonuses',
|
||||
},
|
||||
timingSummary: 'Every Saturday at 7 PM',
|
||||
},
|
||||
{
|
||||
id: 'league-3',
|
||||
name: 'Medium League',
|
||||
description: 'A medium league',
|
||||
ownerId: 'owner-3',
|
||||
createdAt: '2024-01-03T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 24,
|
||||
qualifyingFormat: 'Team',
|
||||
},
|
||||
usedSlots: 20,
|
||||
category: 'Oval',
|
||||
scoring: {
|
||||
gameId: 'game-3',
|
||||
gameName: 'Test Game 3',
|
||||
primaryChampionshipType: 'Team',
|
||||
scoringPresetId: 'preset-3',
|
||||
scoringPresetName: 'Custom',
|
||||
dropPolicySummary: 'No drops',
|
||||
scoringPatternSummary: 'Fixed points per position',
|
||||
},
|
||||
timingSummary: 'Every Friday at 9 PM',
|
||||
},
|
||||
];
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithDifferentSlots,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
// Verify that usedDriverSlots is correctly mapped
|
||||
expect(result.leagues[0].usedDriverSlots).toBe(8);
|
||||
expect(result.leagues[1].usedDriverSlots).toBe(25);
|
||||
expect(result.leagues[2].usedDriverSlots).toBe(20);
|
||||
|
||||
// Verify that leagues can be filtered for featured leagues (usedDriverSlots > 20)
|
||||
const featuredLeagues = result.leagues.filter(l => (l.usedDriverSlots ?? 0) > 20);
|
||||
expect(featuredLeagues).toHaveLength(1);
|
||||
expect(featuredLeagues[0].id).toBe('league-2');
|
||||
});
|
||||
|
||||
it('should handle leagues with different categories for filtering', () => {
|
||||
const leaguesWithDifferentCategories: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'Road League 1',
|
||||
description: 'A road league',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
{
|
||||
id: 'league-2',
|
||||
name: 'Oval League 1',
|
||||
description: 'An oval league',
|
||||
ownerId: 'owner-2',
|
||||
createdAt: '2024-01-02T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 16,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 8,
|
||||
category: 'Oval',
|
||||
scoring: {
|
||||
gameId: 'game-2',
|
||||
gameName: 'Test Game 2',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-2',
|
||||
scoringPresetName: 'Advanced',
|
||||
dropPolicySummary: 'Drop 1 worst race',
|
||||
scoringPatternSummary: 'Points based on finish position with bonuses',
|
||||
},
|
||||
timingSummary: 'Every Saturday at 7 PM',
|
||||
},
|
||||
{
|
||||
id: 'league-3',
|
||||
name: 'Road League 2',
|
||||
description: 'Another road league',
|
||||
ownerId: 'owner-3',
|
||||
createdAt: '2024-01-03T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 24,
|
||||
qualifyingFormat: 'Team',
|
||||
},
|
||||
usedSlots: 20,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-3',
|
||||
gameName: 'Test Game 3',
|
||||
primaryChampionshipType: 'Team',
|
||||
scoringPresetId: 'preset-3',
|
||||
scoringPresetName: 'Custom',
|
||||
dropPolicySummary: 'No drops',
|
||||
scoringPatternSummary: 'Fixed points per position',
|
||||
},
|
||||
timingSummary: 'Every Friday at 9 PM',
|
||||
},
|
||||
];
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithDifferentCategories,
|
||||
totalCount: 3,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
// Verify that category is correctly mapped
|
||||
expect(result.leagues[0].category).toBe('Road');
|
||||
expect(result.leagues[1].category).toBe('Oval');
|
||||
expect(result.leagues[2].category).toBe('Road');
|
||||
|
||||
// Verify that leagues can be filtered by category
|
||||
const roadLeagues = result.leagues.filter(l => l.category === 'Road');
|
||||
expect(roadLeagues).toHaveLength(2);
|
||||
expect(roadLeagues[0].id).toBe('league-1');
|
||||
expect(roadLeagues[1].id).toBe('league-3');
|
||||
|
||||
const ovalLeagues = result.leagues.filter(l => l.category === 'Oval');
|
||||
expect(ovalLeagues).toHaveLength(1);
|
||||
expect(ovalLeagues[0].id).toBe('league-2');
|
||||
});
|
||||
|
||||
it('should handle leagues with null category for filtering', () => {
|
||||
const leaguesWithNullCategory: LeagueWithCapacityAndScoringDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'League with Category',
|
||||
description: 'A league with category',
|
||||
ownerId: 'owner-1',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 32,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 15,
|
||||
category: 'Road',
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Standard',
|
||||
dropPolicySummary: 'Drop 2 worst races',
|
||||
scoringPatternSummary: 'Points based on finish position',
|
||||
},
|
||||
timingSummary: 'Every Sunday at 8 PM',
|
||||
},
|
||||
{
|
||||
id: 'league-2',
|
||||
name: 'League without Category',
|
||||
description: 'A league without category',
|
||||
ownerId: 'owner-2',
|
||||
createdAt: '2024-01-02T00:00:00Z',
|
||||
settings: {
|
||||
maxDrivers: 16,
|
||||
qualifyingFormat: 'Solo',
|
||||
},
|
||||
usedSlots: 8,
|
||||
scoring: {
|
||||
gameId: 'game-2',
|
||||
gameName: 'Test Game 2',
|
||||
primaryChampionshipType: 'Solo',
|
||||
scoringPresetId: 'preset-2',
|
||||
scoringPresetName: 'Advanced',
|
||||
dropPolicySummary: 'Drop 1 worst race',
|
||||
scoringPatternSummary: 'Points based on finish position with bonuses',
|
||||
},
|
||||
timingSummary: 'Every Saturday at 7 PM',
|
||||
},
|
||||
];
|
||||
|
||||
const apiDto: AllLeaguesWithCapacityAndScoringDTO = {
|
||||
leagues: leaguesWithNullCategory,
|
||||
totalCount: 2,
|
||||
};
|
||||
|
||||
const result = LeaguesViewDataBuilder.build(apiDto);
|
||||
|
||||
// Verify that null category is handled correctly
|
||||
expect(result.leagues[0].category).toBe('Road');
|
||||
expect(result.leagues[1].category).toBe(null);
|
||||
|
||||
// Verify that leagues can be filtered by category (null category should be filterable)
|
||||
const roadLeagues = result.leagues.filter(l => l.category === 'Road');
|
||||
expect(roadLeagues).toHaveLength(1);
|
||||
expect(roadLeagues[0].id).toBe('league-1');
|
||||
|
||||
const noCategoryLeagues = result.leagues.filter(l => l.category === null);
|
||||
expect(noCategoryLeagues).toHaveLength(1);
|
||||
expect(noCategoryLeagues[0].id).toBe('league-2');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user