352 lines
12 KiB
TypeScript
352 lines
12 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { LeaguesViewDataBuilder } from './LeaguesViewDataBuilder';
|
|
import type { AllLeaguesWithCapacityAndScoringDTO } from '@/lib/types/generated/AllLeaguesWithCapacityAndScoringDTO';
|
|
|
|
describe('LeaguesViewDataBuilder', () => {
|
|
describe('happy paths', () => {
|
|
it('should transform AllLeaguesWithCapacityAndScoringDTO to LeaguesViewData correctly', () => {
|
|
const leaguesDTO: AllLeaguesWithCapacityAndScoringDTO = {
|
|
leagues: [
|
|
{
|
|
id: 'league-1',
|
|
name: 'Pro League',
|
|
description: 'A competitive league for experienced drivers',
|
|
ownerId: 'owner-1',
|
|
createdAt: '2024-01-01T00:00:00.000Z',
|
|
settings: {
|
|
maxDrivers: 32,
|
|
qualifyingFormat: 'Solo • 32 max',
|
|
},
|
|
usedSlots: 25,
|
|
category: 'competitive',
|
|
scoring: {
|
|
gameId: 'game-1',
|
|
gameName: 'iRacing',
|
|
primaryChampionshipType: 'Single Championship',
|
|
scoringPresetId: 'preset-1',
|
|
scoringPresetName: 'Standard',
|
|
dropPolicySummary: 'Drop 2 worst races',
|
|
scoringPatternSummary: 'Points based on finish position',
|
|
},
|
|
timingSummary: 'Weekly races on Sundays',
|
|
logoUrl: 'https://example.com/logo.png',
|
|
pendingJoinRequestsCount: 3,
|
|
pendingProtestsCount: 1,
|
|
walletBalance: 1000,
|
|
},
|
|
{
|
|
id: 'league-2',
|
|
name: 'Rookie League',
|
|
description: null,
|
|
ownerId: 'owner-2',
|
|
createdAt: '2024-02-01T00:00:00.000Z',
|
|
settings: {
|
|
maxDrivers: 16,
|
|
qualifyingFormat: 'Solo • 16 max',
|
|
},
|
|
usedSlots: 10,
|
|
category: 'rookie',
|
|
scoring: {
|
|
gameId: 'game-1',
|
|
gameName: 'iRacing',
|
|
primaryChampionshipType: 'Single Championship',
|
|
scoringPresetId: 'preset-2',
|
|
scoringPresetName: 'Rookie',
|
|
dropPolicySummary: 'No drops',
|
|
scoringPatternSummary: 'Points based on finish position',
|
|
},
|
|
timingSummary: 'Bi-weekly races',
|
|
logoUrl: null,
|
|
pendingJoinRequestsCount: 0,
|
|
pendingProtestsCount: 0,
|
|
walletBalance: 0,
|
|
},
|
|
],
|
|
totalCount: 2,
|
|
};
|
|
|
|
const result = LeaguesViewDataBuilder.build(leaguesDTO);
|
|
|
|
expect(result.leagues).toHaveLength(2);
|
|
expect(result.leagues[0]).toEqual({
|
|
id: 'league-1',
|
|
name: 'Pro League',
|
|
description: 'A competitive league for experienced drivers',
|
|
logoUrl: 'https://example.com/logo.png',
|
|
ownerId: 'owner-1',
|
|
createdAt: '2024-01-01T00:00:00.000Z',
|
|
maxDrivers: 32,
|
|
usedDriverSlots: 25,
|
|
activeDriversCount: undefined,
|
|
nextRaceAt: undefined,
|
|
maxTeams: undefined,
|
|
usedTeamSlots: undefined,
|
|
structureSummary: 'Solo • 32 max',
|
|
timingSummary: 'Weekly races on Sundays',
|
|
category: 'competitive',
|
|
scoring: {
|
|
gameId: 'game-1',
|
|
gameName: 'iRacing',
|
|
primaryChampionshipType: 'Single Championship',
|
|
scoringPresetId: 'preset-1',
|
|
scoringPresetName: 'Standard',
|
|
dropPolicySummary: 'Drop 2 worst races',
|
|
scoringPatternSummary: 'Points based on finish position',
|
|
},
|
|
});
|
|
expect(result.leagues[1]).toEqual({
|
|
id: 'league-2',
|
|
name: 'Rookie League',
|
|
description: null,
|
|
logoUrl: null,
|
|
ownerId: 'owner-2',
|
|
createdAt: '2024-02-01T00:00:00.000Z',
|
|
maxDrivers: 16,
|
|
usedDriverSlots: 10,
|
|
activeDriversCount: undefined,
|
|
nextRaceAt: undefined,
|
|
maxTeams: undefined,
|
|
usedTeamSlots: undefined,
|
|
structureSummary: 'Solo • 16 max',
|
|
timingSummary: 'Bi-weekly races',
|
|
category: 'rookie',
|
|
scoring: {
|
|
gameId: 'game-1',
|
|
gameName: 'iRacing',
|
|
primaryChampionshipType: 'Single Championship',
|
|
scoringPresetId: 'preset-2',
|
|
scoringPresetName: 'Rookie',
|
|
dropPolicySummary: 'No drops',
|
|
scoringPatternSummary: 'Points based on finish position',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should handle empty leagues list', () => {
|
|
const leaguesDTO: AllLeaguesWithCapacityAndScoringDTO = {
|
|
leagues: [],
|
|
totalCount: 0,
|
|
};
|
|
|
|
const result = LeaguesViewDataBuilder.build(leaguesDTO);
|
|
|
|
expect(result.leagues).toHaveLength(0);
|
|
});
|
|
|
|
it('should handle leagues with missing optional fields', () => {
|
|
const leaguesDTO: AllLeaguesWithCapacityAndScoringDTO = {
|
|
leagues: [
|
|
{
|
|
id: 'league-1',
|
|
name: 'Minimal League',
|
|
description: '',
|
|
ownerId: 'owner-1',
|
|
createdAt: '2024-01-01T00:00:00.000Z',
|
|
settings: {
|
|
maxDrivers: 20,
|
|
},
|
|
usedSlots: 5,
|
|
},
|
|
],
|
|
totalCount: 1,
|
|
};
|
|
|
|
const result = LeaguesViewDataBuilder.build(leaguesDTO);
|
|
|
|
expect(result.leagues[0].description).toBe(null);
|
|
expect(result.leagues[0].logoUrl).toBe(null);
|
|
expect(result.leagues[0].category).toBe(null);
|
|
expect(result.leagues[0].scoring).toBeUndefined();
|
|
expect(result.leagues[0].timingSummary).toBe('');
|
|
});
|
|
});
|
|
|
|
describe('data transformation', () => {
|
|
it('should preserve all DTO fields in the output', () => {
|
|
const leaguesDTO: AllLeaguesWithCapacityAndScoringDTO = {
|
|
leagues: [
|
|
{
|
|
id: 'league-1',
|
|
name: 'Test League',
|
|
description: 'Test description',
|
|
ownerId: 'owner-1',
|
|
createdAt: '2024-01-01T00:00:00.000Z',
|
|
settings: {
|
|
maxDrivers: 32,
|
|
qualifyingFormat: 'Solo • 32 max',
|
|
},
|
|
usedSlots: 20,
|
|
category: 'test',
|
|
scoring: {
|
|
gameId: 'game-1',
|
|
gameName: 'Test Game',
|
|
primaryChampionshipType: 'Test Type',
|
|
scoringPresetId: 'preset-1',
|
|
scoringPresetName: 'Test Preset',
|
|
dropPolicySummary: 'Test drop policy',
|
|
scoringPatternSummary: 'Test pattern',
|
|
},
|
|
timingSummary: 'Test timing',
|
|
logoUrl: 'https://example.com/test.png',
|
|
pendingJoinRequestsCount: 5,
|
|
pendingProtestsCount: 2,
|
|
walletBalance: 500,
|
|
},
|
|
],
|
|
totalCount: 1,
|
|
};
|
|
|
|
const result = LeaguesViewDataBuilder.build(leaguesDTO);
|
|
|
|
expect(result.leagues[0].id).toBe(leaguesDTO.leagues[0].id);
|
|
expect(result.leagues[0].name).toBe(leaguesDTO.leagues[0].name);
|
|
expect(result.leagues[0].description).toBe(leaguesDTO.leagues[0].description);
|
|
expect(result.leagues[0].logoUrl).toBe(leaguesDTO.leagues[0].logoUrl);
|
|
expect(result.leagues[0].ownerId).toBe(leaguesDTO.leagues[0].ownerId);
|
|
expect(result.leagues[0].createdAt).toBe(leaguesDTO.leagues[0].createdAt);
|
|
expect(result.leagues[0].maxDrivers).toBe(leaguesDTO.leagues[0].settings.maxDrivers);
|
|
expect(result.leagues[0].usedDriverSlots).toBe(leaguesDTO.leagues[0].usedSlots);
|
|
expect(result.leagues[0].structureSummary).toBe(leaguesDTO.leagues[0].settings.qualifyingFormat);
|
|
expect(result.leagues[0].timingSummary).toBe(leaguesDTO.leagues[0].timingSummary);
|
|
expect(result.leagues[0].category).toBe(leaguesDTO.leagues[0].category);
|
|
expect(result.leagues[0].scoring).toEqual(leaguesDTO.leagues[0].scoring);
|
|
});
|
|
|
|
it('should not modify the input DTO', () => {
|
|
const leaguesDTO: AllLeaguesWithCapacityAndScoringDTO = {
|
|
leagues: [
|
|
{
|
|
id: 'league-1',
|
|
name: 'Test League',
|
|
description: 'Test description',
|
|
ownerId: 'owner-1',
|
|
createdAt: '2024-01-01T00:00:00.000Z',
|
|
settings: {
|
|
maxDrivers: 32,
|
|
qualifyingFormat: 'Solo • 32 max',
|
|
},
|
|
usedSlots: 20,
|
|
category: 'test',
|
|
scoring: {
|
|
gameId: 'game-1',
|
|
gameName: 'Test Game',
|
|
primaryChampionshipType: 'Test Type',
|
|
scoringPresetId: 'preset-1',
|
|
scoringPresetName: 'Test Preset',
|
|
dropPolicySummary: 'Test drop policy',
|
|
scoringPatternSummary: 'Test pattern',
|
|
},
|
|
timingSummary: 'Test timing',
|
|
logoUrl: 'https://example.com/test.png',
|
|
pendingJoinRequestsCount: 5,
|
|
pendingProtestsCount: 2,
|
|
walletBalance: 500,
|
|
},
|
|
],
|
|
totalCount: 1,
|
|
};
|
|
|
|
const originalDTO = JSON.parse(JSON.stringify(leaguesDTO));
|
|
LeaguesViewDataBuilder.build(leaguesDTO);
|
|
|
|
expect(leaguesDTO).toEqual(originalDTO);
|
|
});
|
|
});
|
|
|
|
describe('edge cases', () => {
|
|
it('should handle leagues with very long descriptions', () => {
|
|
const longDescription = 'A'.repeat(1000);
|
|
const leaguesDTO: AllLeaguesWithCapacityAndScoringDTO = {
|
|
leagues: [
|
|
{
|
|
id: 'league-1',
|
|
name: 'Test League',
|
|
description: longDescription,
|
|
ownerId: 'owner-1',
|
|
createdAt: '2024-01-01T00:00:00.000Z',
|
|
settings: {
|
|
maxDrivers: 32,
|
|
},
|
|
usedSlots: 20,
|
|
},
|
|
],
|
|
totalCount: 1,
|
|
};
|
|
|
|
const result = LeaguesViewDataBuilder.build(leaguesDTO);
|
|
|
|
expect(result.leagues[0].description).toBe(longDescription);
|
|
});
|
|
|
|
it('should handle leagues with special characters in name', () => {
|
|
const leaguesDTO: AllLeaguesWithCapacityAndScoringDTO = {
|
|
leagues: [
|
|
{
|
|
id: 'league-1',
|
|
name: 'League & Co. (2024)',
|
|
description: 'Test league',
|
|
ownerId: 'owner-1',
|
|
createdAt: '2024-01-01T00:00:00.000Z',
|
|
settings: {
|
|
maxDrivers: 32,
|
|
},
|
|
usedSlots: 20,
|
|
},
|
|
],
|
|
totalCount: 1,
|
|
};
|
|
|
|
const result = LeaguesViewDataBuilder.build(leaguesDTO);
|
|
|
|
expect(result.leagues[0].name).toBe('League & Co. (2024)');
|
|
});
|
|
|
|
it('should handle leagues with zero used slots', () => {
|
|
const leaguesDTO: AllLeaguesWithCapacityAndScoringDTO = {
|
|
leagues: [
|
|
{
|
|
id: 'league-1',
|
|
name: 'Empty League',
|
|
description: 'No members yet',
|
|
ownerId: 'owner-1',
|
|
createdAt: '2024-01-01T00:00:00.000Z',
|
|
settings: {
|
|
maxDrivers: 32,
|
|
},
|
|
usedSlots: 0,
|
|
},
|
|
],
|
|
totalCount: 1,
|
|
};
|
|
|
|
const result = LeaguesViewDataBuilder.build(leaguesDTO);
|
|
|
|
expect(result.leagues[0].usedDriverSlots).toBe(0);
|
|
});
|
|
|
|
it('should handle leagues with maximum capacity', () => {
|
|
const leaguesDTO: AllLeaguesWithCapacityAndScoringDTO = {
|
|
leagues: [
|
|
{
|
|
id: 'league-1',
|
|
name: 'Full League',
|
|
description: 'At maximum capacity',
|
|
ownerId: 'owner-1',
|
|
createdAt: '2024-01-01T00:00:00.000Z',
|
|
settings: {
|
|
maxDrivers: 32,
|
|
},
|
|
usedSlots: 32,
|
|
},
|
|
],
|
|
totalCount: 1,
|
|
};
|
|
|
|
const result = LeaguesViewDataBuilder.build(leaguesDTO);
|
|
|
|
expect(result.leagues[0].usedDriverSlots).toBe(32);
|
|
expect(result.leagues[0].maxDrivers).toBe(32);
|
|
});
|
|
});
|
|
});
|