import { describe, it, expect } from 'vitest'; import { RulebookViewDataBuilder } from './RulebookViewDataBuilder'; import type { RulebookApiDto } from '@/lib/types/tbd/RulebookApiDto'; describe('RulebookViewDataBuilder', () => { describe('happy paths', () => { it('should transform RulebookApiDto to RulebookViewData correctly', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-123', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, { sessionType: 'race', position: 2, points: 18 }, { sessionType: 'race', position: 3, points: 15 }, ], bonusSummary: [ { type: 'fastest_lap', points: 5, description: 'Fastest lap' }, ], }, ], dropPolicySummary: 'Drop 2 worst results', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result).toEqual({ leagueId: 'league-123', gameName: 'iRacing', scoringPresetName: 'Standard', championshipsCount: 1, sessionTypes: 'race', dropPolicySummary: 'Drop 2 worst results', hasActiveDropPolicy: true, positionPoints: [ { position: 1, points: 25 }, { position: 2, points: 18 }, { position: 3, points: 15 }, ], bonusPoints: [ { type: 'fastest_lap', points: 5, description: 'Fastest lap' }, ], hasBonusPoints: true, }); }); it('should handle championship without driver type', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-456', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'team', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [], }, ], dropPolicySummary: 'No drops', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.positionPoints).toEqual([{ position: 1, points: 25 }]); }); it('should handle multiple championships', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-789', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [], }, { type: 'team', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [], }, ], dropPolicySummary: 'No drops', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.championshipsCount).toBe(2); }); it('should handle empty bonus points', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-101', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [], }, ], dropPolicySummary: 'No drops', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.bonusPoints).toEqual([]); expect(result.hasBonusPoints).toBe(false); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-102', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [ { type: 'fastest_lap', points: 5, description: 'Fastest lap' }, ], }, ], dropPolicySummary: 'Drop 2 worst results', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.leagueId).toBe(rulebookApiDto.leagueId); expect(result.gameName).toBe(rulebookApiDto.scoringConfig.gameName); expect(result.scoringPresetName).toBe(rulebookApiDto.scoringConfig.scoringPresetName); expect(result.dropPolicySummary).toBe(rulebookApiDto.scoringConfig.dropPolicySummary); }); it('should not modify the input DTO', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-103', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [], }, ], dropPolicySummary: 'No drops', }, }; const originalDto = { ...rulebookApiDto }; RulebookViewDataBuilder.build(rulebookApiDto); expect(rulebookApiDto).toEqual(originalDto); }); }); describe('edge cases', () => { it('should handle empty drop policy', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-104', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [], }, ], dropPolicySummary: '', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.hasActiveDropPolicy).toBe(false); }); it('should handle drop policy with "All" keyword', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-105', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [], }, ], dropPolicySummary: 'Drop all results', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.hasActiveDropPolicy).toBe(false); }); it('should handle multiple session types', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-106', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race', 'qualifying', 'practice'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [], }, ], dropPolicySummary: 'No drops', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.sessionTypes).toBe('race, qualifying, practice'); }); it('should handle single session type', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-107', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [], }, ], dropPolicySummary: 'No drops', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.sessionTypes).toBe('race'); }); it('should handle empty points preview', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-108', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [], bonusSummary: [], }, ], dropPolicySummary: 'No drops', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.positionPoints).toEqual([]); }); it('should handle points preview with different session types', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-109', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, { sessionType: 'qualifying', position: 1, points: 10 }, ], bonusSummary: [], }, ], dropPolicySummary: 'No drops', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.positionPoints).toEqual([{ position: 1, points: 25 }]); }); it('should handle points preview with non-sequential positions', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-110', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, { sessionType: 'race', position: 3, points: 15 }, { sessionType: 'race', position: 2, points: 18 }, ], bonusSummary: [], }, ], dropPolicySummary: 'No drops', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.positionPoints).toEqual([ { position: 1, points: 25 }, { position: 2, points: 18 }, { position: 3, points: 15 }, ]); }); it('should handle multiple bonus points', () => { const rulebookApiDto: RulebookApiDto = { leagueId: 'league-111', scoringConfig: { gameName: 'iRacing', scoringPresetName: 'Standard', championships: [ { type: 'driver', sessionTypes: ['race'], pointsPreview: [ { sessionType: 'race', position: 1, points: 25 }, ], bonusSummary: [ { type: 'fastest_lap', points: 5, description: 'Fastest lap' }, { type: 'pole_position', points: 3, description: 'Pole position' }, { type: 'clean_race', points: 2, description: 'Clean race' }, ], }, ], dropPolicySummary: 'No drops', }, }; const result = RulebookViewDataBuilder.build(rulebookApiDto); expect(result.bonusPoints).toHaveLength(3); expect(result.hasBonusPoints).toBe(true); }); }); });