/** * View Data Layer Tests - Drivers Functionality * * This test file covers the view data layer for drivers functionality. * * The view data layer is responsible for: * - DTO → UI model mapping * - Formatting, sorting, and grouping * - Derived fields and defaults * - UI-specific semantics * * This layer isolates the UI from API churn by providing a stable interface * between the API layer and the presentation layer. * * Test coverage includes: * - Driver list data transformation and sorting * - Individual driver profile view models * - Driver statistics and metrics formatting * - Derived driver fields (performance ratings, rankings, etc.) * - Default values and fallbacks for driver views * - Driver-specific formatting (lap times, points, positions, etc.) * - Data grouping and categorization for driver components * - Driver search and filtering view models * - Driver comparison data transformation */ import { DriversViewDataBuilder } from '@/lib/builders/view-data/DriversViewDataBuilder'; import { DriverProfileViewDataBuilder } from '@/lib/builders/view-data/DriverProfileViewDataBuilder'; import { RatingDisplay } from '@/lib/display-objects/RatingDisplay'; import { NumberDisplay } from '@/lib/display-objects/NumberDisplay'; import { DateDisplay } from '@/lib/display-objects/DateDisplay'; import { FinishDisplay } from '@/lib/display-objects/FinishDisplay'; import { PercentDisplay } from '@/lib/display-objects/PercentDisplay'; import type { DriversLeaderboardDTO } from '@/lib/types/generated/DriversLeaderboardDTO'; import type { DriverLeaderboardItemDTO } from '@/lib/types/generated/DriverLeaderboardItemDTO'; import type { GetDriverProfileOutputDTO } from '@/lib/types/generated/GetDriverProfileOutputDTO'; import type { DriverProfileDriverSummaryDTO } from '@/lib/types/generated/DriverProfileDriverSummaryDTO'; import type { DriverProfileStatsDTO } from '@/lib/types/generated/DriverProfileStatsDTO'; import type { DriverProfileFinishDistributionDTO } from '@/lib/types/generated/DriverProfileFinishDistributionDTO'; import type { DriverProfileTeamMembershipDTO } from '@/lib/types/generated/DriverProfileTeamMembershipDTO'; import type { DriverProfileSocialSummaryDTO } from '@/lib/types/generated/DriverProfileSocialSummaryDTO'; import type { DriverProfileExtendedProfileDTO } from '@/lib/types/generated/DriverProfileExtendedProfileDTO'; describe('DriversViewDataBuilder', () => { describe('happy paths', () => { it('should transform DriversLeaderboardDTO to DriversViewData correctly', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 1234.56, skillLevel: 'Pro', category: 'Elite', nationality: 'USA', racesCompleted: 150, wins: 25, podiums: 60, isActive: true, rank: 1, avatarUrl: 'https://example.com/john.jpg', }, { id: 'driver-2', name: 'Jane Smith', rating: 1100.75, skillLevel: 'Advanced', category: 'Pro', nationality: 'Canada', racesCompleted: 120, wins: 15, podiums: 45, isActive: true, rank: 2, avatarUrl: 'https://example.com/jane.jpg', }, ], totalRaces: 270, totalWins: 40, activeCount: 2, }; const result = DriversViewDataBuilder.build(driversDTO); expect(result.drivers).toHaveLength(2); expect(result.drivers[0].id).toBe('driver-1'); expect(result.drivers[0].name).toBe('John Doe'); expect(result.drivers[0].rating).toBe(1234.56); expect(result.drivers[0].ratingLabel).toBe('1,235'); expect(result.drivers[0].skillLevel).toBe('Pro'); expect(result.drivers[0].category).toBe('Elite'); expect(result.drivers[0].nationality).toBe('USA'); expect(result.drivers[0].racesCompleted).toBe(150); expect(result.drivers[0].wins).toBe(25); expect(result.drivers[0].podiums).toBe(60); expect(result.drivers[0].isActive).toBe(true); expect(result.drivers[0].rank).toBe(1); expect(result.drivers[0].avatarUrl).toBe('https://example.com/john.jpg'); expect(result.drivers[1].id).toBe('driver-2'); expect(result.drivers[1].name).toBe('Jane Smith'); expect(result.drivers[1].rating).toBe(1100.75); expect(result.drivers[1].ratingLabel).toBe('1,101'); expect(result.drivers[1].skillLevel).toBe('Advanced'); expect(result.drivers[1].category).toBe('Pro'); expect(result.drivers[1].nationality).toBe('Canada'); expect(result.drivers[1].racesCompleted).toBe(120); expect(result.drivers[1].wins).toBe(15); expect(result.drivers[1].podiums).toBe(45); expect(result.drivers[1].isActive).toBe(true); expect(result.drivers[1].rank).toBe(2); expect(result.drivers[1].avatarUrl).toBe('https://example.com/jane.jpg'); expect(result.totalRaces).toBe(270); expect(result.totalRacesLabel).toBe('270'); expect(result.totalWins).toBe(40); expect(result.totalWinsLabel).toBe('40'); expect(result.activeCount).toBe(2); expect(result.activeCountLabel).toBe('2'); expect(result.totalDriversLabel).toBe('2'); }); it('should handle drivers with missing optional fields', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 1234.56, skillLevel: 'Pro', nationality: 'USA', racesCompleted: 150, wins: 25, podiums: 60, isActive: true, rank: 1, }, ], totalRaces: 150, totalWins: 25, activeCount: 1, }; const result = DriversViewDataBuilder.build(driversDTO); expect(result.drivers[0].category).toBeUndefined(); expect(result.drivers[0].avatarUrl).toBeUndefined(); }); it('should handle empty drivers array', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [], totalRaces: 0, totalWins: 0, activeCount: 0, }; const result = DriversViewDataBuilder.build(driversDTO); expect(result.drivers).toEqual([]); expect(result.totalRaces).toBe(0); expect(result.totalRacesLabel).toBe('0'); expect(result.totalWins).toBe(0); expect(result.totalWinsLabel).toBe('0'); expect(result.activeCount).toBe(0); expect(result.activeCountLabel).toBe('0'); expect(result.totalDriversLabel).toBe('0'); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 1234.56, skillLevel: 'Pro', category: 'Elite', nationality: 'USA', racesCompleted: 150, wins: 25, podiums: 60, isActive: true, rank: 1, avatarUrl: 'https://example.com/john.jpg', }, ], totalRaces: 150, totalWins: 25, activeCount: 1, }; const result = DriversViewDataBuilder.build(driversDTO); expect(result.drivers[0].name).toBe(driversDTO.drivers[0].name); expect(result.drivers[0].nationality).toBe(driversDTO.drivers[0].nationality); expect(result.drivers[0].skillLevel).toBe(driversDTO.drivers[0].skillLevel); expect(result.totalRaces).toBe(driversDTO.totalRaces); expect(result.totalWins).toBe(driversDTO.totalWins); expect(result.activeCount).toBe(driversDTO.activeCount); }); it('should not modify the input DTO', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 1234.56, skillLevel: 'Pro', category: 'Elite', nationality: 'USA', racesCompleted: 150, wins: 25, podiums: 60, isActive: true, rank: 1, avatarUrl: 'https://example.com/john.jpg', }, ], totalRaces: 150, totalWins: 25, activeCount: 1, }; const originalDTO = JSON.parse(JSON.stringify(driversDTO)); DriversViewDataBuilder.build(driversDTO); expect(driversDTO).toEqual(originalDTO); }); it('should transform all numeric fields to formatted strings where appropriate', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 1234.56, skillLevel: 'Pro', nationality: 'USA', racesCompleted: 150, wins: 25, podiums: 60, isActive: true, rank: 1, }, ], totalRaces: 150, totalWins: 25, activeCount: 1, }; const result = DriversViewDataBuilder.build(driversDTO); // Rating label should be a formatted string expect(typeof result.drivers[0].ratingLabel).toBe('string'); expect(result.drivers[0].ratingLabel).toBe('1,235'); // Total counts should be formatted strings expect(typeof result.totalRacesLabel).toBe('string'); expect(result.totalRacesLabel).toBe('150'); expect(typeof result.totalWinsLabel).toBe('string'); expect(result.totalWinsLabel).toBe('25'); expect(typeof result.activeCountLabel).toBe('string'); expect(result.activeCountLabel).toBe('1'); expect(typeof result.totalDriversLabel).toBe('string'); expect(result.totalDriversLabel).toBe('1'); }); it('should handle large numbers correctly', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 999999.99, skillLevel: 'Pro', nationality: 'USA', racesCompleted: 10000, wins: 2500, podiums: 5000, isActive: true, rank: 1, }, ], totalRaces: 10000, totalWins: 2500, activeCount: 1, }; const result = DriversViewDataBuilder.build(driversDTO); expect(result.drivers[0].ratingLabel).toBe('1,000,000'); expect(result.totalRacesLabel).toBe('10,000'); expect(result.totalWinsLabel).toBe('2,500'); expect(result.activeCountLabel).toBe('1'); expect(result.totalDriversLabel).toBe('1'); }); }); describe('edge cases', () => { it('should handle null/undefined rating', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 0, skillLevel: 'Pro', nationality: 'USA', racesCompleted: 150, wins: 25, podiums: 60, isActive: true, rank: 1, }, ], totalRaces: 150, totalWins: 25, activeCount: 1, }; const result = DriversViewDataBuilder.build(driversDTO); expect(result.drivers[0].ratingLabel).toBe('0'); }); it('should handle drivers with no category', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 1234.56, skillLevel: 'Pro', nationality: 'USA', racesCompleted: 150, wins: 25, podiums: 60, isActive: true, rank: 1, }, ], totalRaces: 150, totalWins: 25, activeCount: 1, }; const result = DriversViewDataBuilder.build(driversDTO); expect(result.drivers[0].category).toBeUndefined(); }); it('should handle inactive drivers', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 1234.56, skillLevel: 'Pro', nationality: 'USA', racesCompleted: 150, wins: 25, podiums: 60, isActive: false, rank: 1, }, ], totalRaces: 150, totalWins: 25, activeCount: 0, }; const result = DriversViewDataBuilder.build(driversDTO); expect(result.drivers[0].isActive).toBe(false); expect(result.activeCount).toBe(0); expect(result.activeCountLabel).toBe('0'); }); }); describe('derived fields', () => { it('should correctly calculate total drivers label', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 1234.56, skillLevel: 'Pro', nationality: 'USA', racesCompleted: 150, wins: 25, podiums: 60, isActive: true, rank: 1 }, { id: 'driver-2', name: 'Jane Smith', rating: 1100.75, skillLevel: 'Advanced', nationality: 'Canada', racesCompleted: 120, wins: 15, podiums: 45, isActive: true, rank: 2 }, { id: 'driver-3', name: 'Bob Wilson', rating: 950.25, skillLevel: 'Intermediate', nationality: 'UK', racesCompleted: 80, wins: 5, podiums: 20, isActive: false, rank: 3 }, ], totalRaces: 350, totalWins: 45, activeCount: 2, }; const result = DriversViewDataBuilder.build(driversDTO); expect(result.totalDriversLabel).toBe('3'); }); it('should correctly calculate active count', () => { const driversDTO: DriversLeaderboardDTO = { drivers: [ { id: 'driver-1', name: 'John Doe', rating: 1234.56, skillLevel: 'Pro', nationality: 'USA', racesCompleted: 150, wins: 25, podiums: 60, isActive: true, rank: 1 }, { id: 'driver-2', name: 'Jane Smith', rating: 1100.75, skillLevel: 'Advanced', nationality: 'Canada', racesCompleted: 120, wins: 15, podiums: 45, isActive: true, rank: 2 }, { id: 'driver-3', name: 'Bob Wilson', rating: 950.25, skillLevel: 'Intermediate', nationality: 'UK', racesCompleted: 80, wins: 5, podiums: 20, isActive: false, rank: 3 }, ], totalRaces: 350, totalWins: 45, activeCount: 2, }; const result = DriversViewDataBuilder.build(driversDTO); expect(result.activeCount).toBe(2); expect(result.activeCountLabel).toBe('2'); }); }); describe('rating formatting', () => { it('should format ratings with thousands separators', () => { expect(RatingDisplay.format(1234.56)).toBe('1,235'); expect(RatingDisplay.format(9999.99)).toBe('10,000'); expect(RatingDisplay.format(100000.5)).toBe('100,001'); }); it('should handle null/undefined ratings', () => { expect(RatingDisplay.format(null)).toBe('—'); expect(RatingDisplay.format(undefined)).toBe('—'); }); it('should round ratings correctly', () => { expect(RatingDisplay.format(1234.4)).toBe('1,234'); expect(RatingDisplay.format(1234.6)).toBe('1,235'); expect(RatingDisplay.format(1234.5)).toBe('1,235'); }); }); describe('number formatting', () => { it('should format numbers with thousands separators', () => { expect(NumberDisplay.format(1234567)).toBe('1,234,567'); expect(NumberDisplay.format(1000)).toBe('1,000'); expect(NumberDisplay.format(999)).toBe('999'); }); it('should handle decimal numbers', () => { expect(NumberDisplay.format(1234.567)).toBe('1,234.567'); expect(NumberDisplay.format(1000.5)).toBe('1,000.5'); }); }); }); describe('DriverProfileViewDataBuilder', () => { describe('happy paths', () => { it('should transform GetDriverProfileOutputDTO to DriverProfileViewData correctly', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', avatarUrl: 'https://example.com/avatar.jpg', iracingId: '12345', joinedAt: '2024-01-15T00:00:00Z', rating: 1234.56, globalRank: 42, consistency: 85, bio: 'Professional sim racer with 5 years of experience.', totalDrivers: 1000, }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, avgFinish: 5.4, bestFinish: 1, worstFinish: 25, finishRate: 0.933, winRate: 0.167, podiumRate: 0.4, percentile: 95, rating: 1234.56, consistency: 85, overallRank: 42, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [ { teamId: 'team-1', teamName: 'Elite Racing', teamTag: 'ER', role: 'Driver', joinedAt: '2024-01-15T00:00:00Z', isCurrent: true, }, ], socialSummary: { friendsCount: 50, friends: [ { id: 'friend-1', name: 'Jane Smith', country: 'Canada', avatarUrl: 'https://example.com/jane.jpg', }, ], }, extendedProfile: { socialHandles: [ { platform: 'Twitter', handle: '@johndoe', url: 'https://twitter.com/johndoe', }, ], achievements: [ { id: 'ach-1', title: 'Champion', description: 'Won the championship', icon: 'trophy', rarity: 'Legendary', earnedAt: '2024-01-15T00:00:00Z', }, ], racingStyle: 'Aggressive', favoriteTrack: 'Spa', favoriteCar: 'Porsche 911 GT3', timezone: 'America/New_York', availableHours: 'Evenings', lookingForTeam: false, openToRequests: true, }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); // Current driver expect(result.currentDriver).not.toBeNull(); expect(result.currentDriver?.id).toBe('driver-123'); expect(result.currentDriver?.name).toBe('John Doe'); expect(result.currentDriver?.country).toBe('USA'); expect(result.currentDriver?.avatarUrl).toBe('https://example.com/avatar.jpg'); expect(result.currentDriver?.iracingId).toBe(12345); expect(result.currentDriver?.joinedAt).toBe('2024-01-15T00:00:00Z'); expect(result.currentDriver?.joinedAtLabel).toBe('Jan 2024'); expect(result.currentDriver?.rating).toBe(1234.56); expect(result.currentDriver?.ratingLabel).toBe('1,235'); expect(result.currentDriver?.globalRank).toBe(42); expect(result.currentDriver?.globalRankLabel).toBe('#42'); expect(result.currentDriver?.consistency).toBe(85); expect(result.currentDriver?.bio).toBe('Professional sim racer with 5 years of experience.'); expect(result.currentDriver?.totalDrivers).toBe(1000); // Stats expect(result.stats).not.toBeNull(); expect(result.stats?.totalRaces).toBe(150); expect(result.stats?.totalRacesLabel).toBe('150'); expect(result.stats?.wins).toBe(25); expect(result.stats?.winsLabel).toBe('25'); expect(result.stats?.podiums).toBe(60); expect(result.stats?.podiumsLabel).toBe('60'); expect(result.stats?.dnfs).toBe(10); expect(result.stats?.dnfsLabel).toBe('10'); expect(result.stats?.avgFinish).toBe(5.4); expect(result.stats?.avgFinishLabel).toBe('P5.4'); expect(result.stats?.bestFinish).toBe(1); expect(result.stats?.bestFinishLabel).toBe('P1'); expect(result.stats?.worstFinish).toBe(25); expect(result.stats?.worstFinishLabel).toBe('P25'); expect(result.stats?.finishRate).toBe(0.933); expect(result.stats?.winRate).toBe(0.167); expect(result.stats?.podiumRate).toBe(0.4); expect(result.stats?.percentile).toBe(95); expect(result.stats?.rating).toBe(1234.56); expect(result.stats?.ratingLabel).toBe('1,235'); expect(result.stats?.consistency).toBe(85); expect(result.stats?.consistencyLabel).toBe('85%'); expect(result.stats?.overallRank).toBe(42); // Finish distribution expect(result.finishDistribution).not.toBeNull(); expect(result.finishDistribution?.totalRaces).toBe(150); expect(result.finishDistribution?.wins).toBe(25); expect(result.finishDistribution?.podiums).toBe(60); expect(result.finishDistribution?.topTen).toBe(100); expect(result.finishDistribution?.dnfs).toBe(10); expect(result.finishDistribution?.other).toBe(55); // Team memberships expect(result.teamMemberships).toHaveLength(1); expect(result.teamMemberships[0].teamId).toBe('team-1'); expect(result.teamMemberships[0].teamName).toBe('Elite Racing'); expect(result.teamMemberships[0].teamTag).toBe('ER'); expect(result.teamMemberships[0].role).toBe('Driver'); expect(result.teamMemberships[0].joinedAt).toBe('2024-01-15T00:00:00Z'); expect(result.teamMemberships[0].joinedAtLabel).toBe('Jan 2024'); expect(result.teamMemberships[0].isCurrent).toBe(true); // Social summary expect(result.socialSummary.friendsCount).toBe(50); expect(result.socialSummary.friends).toHaveLength(1); expect(result.socialSummary.friends[0].id).toBe('friend-1'); expect(result.socialSummary.friends[0].name).toBe('Jane Smith'); expect(result.socialSummary.friends[0].country).toBe('Canada'); expect(result.socialSummary.friends[0].avatarUrl).toBe('https://example.com/jane.jpg'); // Extended profile expect(result.extendedProfile).not.toBeNull(); expect(result.extendedProfile?.socialHandles).toHaveLength(1); expect(result.extendedProfile?.socialHandles[0].platform).toBe('Twitter'); expect(result.extendedProfile?.socialHandles[0].handle).toBe('@johndoe'); expect(result.extendedProfile?.socialHandles[0].url).toBe('https://twitter.com/johndoe'); expect(result.extendedProfile?.achievements).toHaveLength(1); expect(result.extendedProfile?.achievements[0].id).toBe('ach-1'); expect(result.extendedProfile?.achievements[0].title).toBe('Champion'); expect(result.extendedProfile?.achievements[0].description).toBe('Won the championship'); expect(result.extendedProfile?.achievements[0].icon).toBe('trophy'); expect(result.extendedProfile?.achievements[0].rarity).toBe('Legendary'); expect(result.extendedProfile?.achievements[0].rarityLabel).toBe('Legendary'); expect(result.extendedProfile?.achievements[0].earnedAt).toBe('2024-01-15T00:00:00Z'); expect(result.extendedProfile?.achievements[0].earnedAtLabel).toBe('Jan 15, 2024'); expect(result.extendedProfile?.racingStyle).toBe('Aggressive'); expect(result.extendedProfile?.favoriteTrack).toBe('Spa'); expect(result.extendedProfile?.favoriteCar).toBe('Porsche 911 GT3'); expect(result.extendedProfile?.timezone).toBe('America/New_York'); expect(result.extendedProfile?.availableHours).toBe('Evenings'); expect(result.extendedProfile?.lookingForTeam).toBe(false); expect(result.extendedProfile?.openToRequests).toBe(true); }); it('should handle missing currentDriver gracefully', () => { const profileDTO: GetDriverProfileOutputDTO = { stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver).toBeNull(); expect(result.stats).not.toBeNull(); expect(result.finishDistribution).not.toBeNull(); }); it('should handle missing stats gracefully', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver).not.toBeNull(); expect(result.stats).toBeNull(); expect(result.finishDistribution).not.toBeNull(); }); it('should handle missing finishDistribution gracefully', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver).not.toBeNull(); expect(result.stats).not.toBeNull(); expect(result.finishDistribution).toBeNull(); }); it('should handle missing extendedProfile gracefully', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver).not.toBeNull(); expect(result.stats).not.toBeNull(); expect(result.finishDistribution).not.toBeNull(); expect(result.extendedProfile).toBeNull(); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', avatarUrl: 'https://example.com/avatar.jpg', iracingId: '12345', joinedAt: '2024-01-15T00:00:00Z', rating: 1234.56, globalRank: 42, consistency: 85, bio: 'Professional sim racer.', totalDrivers: 1000, }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, avgFinish: 5.4, bestFinish: 1, worstFinish: 25, finishRate: 0.933, winRate: 0.167, podiumRate: 0.4, percentile: 95, rating: 1234.56, consistency: 85, overallRank: 42, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [ { teamId: 'team-1', teamName: 'Elite Racing', teamTag: 'ER', role: 'Driver', joinedAt: '2024-01-15T00:00:00Z', isCurrent: true, }, ], socialSummary: { friendsCount: 50, friends: [ { id: 'friend-1', name: 'Jane Smith', country: 'Canada', avatarUrl: 'https://example.com/jane.jpg', }, ], }, extendedProfile: { socialHandles: [ { platform: 'Twitter', handle: '@johndoe', url: 'https://twitter.com/johndoe', }, ], achievements: [ { id: 'ach-1', title: 'Champion', description: 'Won the championship', icon: 'trophy', rarity: 'Legendary', earnedAt: '2024-01-15T00:00:00Z', }, ], racingStyle: 'Aggressive', favoriteTrack: 'Spa', favoriteCar: 'Porsche 911 GT3', timezone: 'America/New_York', availableHours: 'Evenings', lookingForTeam: false, openToRequests: true, }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver?.name).toBe(profileDTO.currentDriver?.name); expect(result.currentDriver?.country).toBe(profileDTO.currentDriver?.country); expect(result.currentDriver?.avatarUrl).toBe(profileDTO.currentDriver?.avatarUrl); expect(result.currentDriver?.iracingId).toBe(12345); expect(result.currentDriver?.joinedAt).toBe(profileDTO.currentDriver?.joinedAt); expect(result.currentDriver?.bio).toBe(profileDTO.currentDriver?.bio); expect(result.currentDriver?.totalDrivers).toBe(profileDTO.currentDriver?.totalDrivers); }); it('should not modify the input DTO', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', avatarUrl: 'https://example.com/avatar.jpg', iracingId: '12345', joinedAt: '2024-01-15T00:00:00Z', rating: 1234.56, globalRank: 42, consistency: 85, bio: 'Professional sim racer.', totalDrivers: 1000, }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const originalDTO = JSON.parse(JSON.stringify(profileDTO)); DriverProfileViewDataBuilder.build(profileDTO); expect(profileDTO).toEqual(originalDTO); }); it('should transform all numeric fields to formatted strings where appropriate', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', rating: 1234.56, globalRank: 42, consistency: 85, }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, avgFinish: 5.4, bestFinish: 1, worstFinish: 25, finishRate: 0.933, winRate: 0.167, podiumRate: 0.4, percentile: 95, rating: 1234.56, consistency: 85, overallRank: 42, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); // Rating labels should be formatted strings expect(typeof result.currentDriver?.ratingLabel).toBe('string'); expect(result.currentDriver?.ratingLabel).toBe('1,235'); expect(typeof result.stats?.ratingLabel).toBe('string'); expect(result.stats?.ratingLabel).toBe('1,235'); // Rank labels should be formatted strings expect(typeof result.currentDriver?.globalRankLabel).toBe('string'); expect(result.currentDriver?.globalRankLabel).toBe('#42'); // Count labels should be formatted strings expect(typeof result.stats?.totalRacesLabel).toBe('string'); expect(result.stats?.totalRacesLabel).toBe('150'); expect(typeof result.stats?.winsLabel).toBe('string'); expect(result.stats?.winsLabel).toBe('25'); expect(typeof result.stats?.podiumsLabel).toBe('string'); expect(result.stats?.podiumsLabel).toBe('60'); expect(typeof result.stats?.dnfsLabel).toBe('string'); expect(result.stats?.dnfsLabel).toBe('10'); // Finish labels should be formatted strings expect(typeof result.stats?.avgFinishLabel).toBe('string'); expect(result.stats?.avgFinishLabel).toBe('P5.4'); expect(typeof result.stats?.bestFinishLabel).toBe('string'); expect(result.stats?.bestFinishLabel).toBe('P1'); expect(typeof result.stats?.worstFinishLabel).toBe('string'); expect(result.stats?.worstFinishLabel).toBe('P25'); // Consistency label should be formatted string expect(typeof result.stats?.consistencyLabel).toBe('string'); expect(result.stats?.consistencyLabel).toBe('85%'); }); it('should handle iracingId as string and convert to number', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', iracingId: '12345', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver?.iracingId).toBe(12345); }); it('should handle iracingId as number', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', iracingId: 12345, }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver?.iracingId).toBe(12345); }); it('should handle missing iracingId', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver?.iracingId).toBeNull(); }); it('should handle empty avatarUrl', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', avatarUrl: '', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver?.avatarUrl).toBe(''); }); it('should handle missing avatarUrl', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver?.avatarUrl).toBe(''); }); it('should handle missing avatarUrl in friends', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 1, friends: [ { id: 'friend-1', name: 'Jane Smith', country: 'Canada', }, ], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.socialSummary.friends[0].avatarUrl).toBe(''); }); it('should handle missing teamTag', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [ { teamId: 'team-1', teamName: 'Elite Racing', role: 'Driver', joinedAt: '2024-01-15T00:00:00Z', isCurrent: true, }, ], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.teamMemberships[0].teamTag).toBeNull(); }); }); describe('edge cases', () => { it('should handle null/undefined rating in currentDriver', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', rating: null, globalRank: null, consistency: null, }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.currentDriver?.rating).toBeNull(); expect(result.currentDriver?.ratingLabel).toBe('—'); expect(result.currentDriver?.globalRank).toBeNull(); expect(result.currentDriver?.globalRankLabel).toBe('—'); expect(result.currentDriver?.consistency).toBeNull(); }); it('should handle null/undefined rating in stats', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, rating: null, consistency: null, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.stats?.rating).toBeNull(); expect(result.stats?.ratingLabel).toBe('—'); expect(result.stats?.consistency).toBeNull(); expect(result.stats?.consistencyLabel).toBe('0%'); }); it('should handle null/undefined finish positions', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, avgFinish: null, bestFinish: null, worstFinish: null, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.stats?.avgFinish).toBeNull(); expect(result.stats?.avgFinishLabel).toBe('—'); expect(result.stats?.bestFinish).toBeNull(); expect(result.stats?.bestFinishLabel).toBe('—'); expect(result.stats?.worstFinish).toBeNull(); expect(result.stats?.worstFinishLabel).toBe('—'); }); it('should handle null/undefined rates', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, finishRate: null, winRate: null, podiumRate: null, percentile: null, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.stats?.finishRate).toBeNull(); expect(result.stats?.winRate).toBeNull(); expect(result.stats?.podiumRate).toBeNull(); expect(result.stats?.percentile).toBeNull(); }); it('should handle empty teamMemberships array', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.teamMemberships).toEqual([]); }); it('should handle empty friends array', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.socialSummary.friends).toEqual([]); expect(result.socialSummary.friendsCount).toBe(0); }); it('should handle empty socialHandles array', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, extendedProfile: { socialHandles: [], achievements: [], racingStyle: 'Aggressive', favoriteTrack: 'Spa', favoriteCar: 'Porsche 911 GT3', timezone: 'America/New_York', availableHours: 'Evenings', lookingForTeam: false, openToRequests: true, }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.extendedProfile?.socialHandles).toEqual([]); }); it('should handle empty achievements array', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, extendedProfile: { socialHandles: [], achievements: [], racingStyle: 'Aggressive', favoriteTrack: 'Spa', favoriteCar: 'Porsche 911 GT3', timezone: 'America/New_York', availableHours: 'Evenings', lookingForTeam: false, openToRequests: true, }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.extendedProfile?.achievements).toEqual([]); }); }); describe('derived fields', () => { it('should correctly calculate finish distribution totals', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); // Verify that finish distribution totals match the stats expect(result.finishDistribution?.totalRaces).toBe(150); expect(result.finishDistribution?.wins).toBe(25); expect(result.finishDistribution?.podiums).toBe(60); expect(result.finishDistribution?.dnfs).toBe(10); }); it('should correctly calculate friend count', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 5, friends: [ { id: 'friend-1', name: 'Alice', country: 'UK' }, { id: 'friend-2', name: 'Bob', country: 'Germany' }, { id: 'friend-3', name: 'Charlie', country: 'France' }, { id: 'friend-4', name: 'Diana', country: 'USA' }, { id: 'friend-5', name: 'Eve', country: 'Canada' }, ], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.socialSummary.friendsCount).toBe(5); expect(result.socialSummary.friends).toHaveLength(5); }); }); describe('date formatting', () => { it('should format dates correctly', () => { expect(DateDisplay.formatShort('2024-01-15T00:00:00Z')).toBe('Jan 15, 2024'); expect(DateDisplay.formatMonthYear('2024-01-15T00:00:00Z')).toBe('Jan 2024'); expect(DateDisplay.formatShort('2024-12-25T00:00:00Z')).toBe('Dec 25, 2024'); expect(DateDisplay.formatMonthYear('2024-12-25T00:00:00Z')).toBe('Dec 2024'); }); }); describe('finish position formatting', () => { it('should format finish positions correctly', () => { expect(FinishDisplay.format(1)).toBe('P1'); expect(FinishDisplay.format(5)).toBe('P5'); expect(FinishDisplay.format(10)).toBe('P10'); expect(FinishDisplay.format(100)).toBe('P100'); }); it('should handle null/undefined finish positions', () => { expect(FinishDisplay.format(null)).toBe('—'); expect(FinishDisplay.format(undefined)).toBe('—'); }); it('should format average finish positions correctly', () => { expect(FinishDisplay.formatAverage(5.4)).toBe('P5.4'); expect(FinishDisplay.formatAverage(1.5)).toBe('P1.5'); expect(FinishDisplay.formatAverage(10.0)).toBe('P10.0'); }); it('should handle null/undefined average finish positions', () => { expect(FinishDisplay.formatAverage(null)).toBe('—'); expect(FinishDisplay.formatAverage(undefined)).toBe('—'); }); }); describe('percentage formatting', () => { it('should format percentages correctly', () => { expect(PercentDisplay.format(0.1234)).toBe('12.3%'); expect(PercentDisplay.format(0.5)).toBe('50.0%'); expect(PercentDisplay.format(1.0)).toBe('100.0%'); }); it('should handle null/undefined percentages', () => { expect(PercentDisplay.format(null)).toBe('0.0%'); expect(PercentDisplay.format(undefined)).toBe('0.0%'); }); it('should format whole percentages correctly', () => { expect(PercentDisplay.formatWhole(85)).toBe('85%'); expect(PercentDisplay.formatWhole(50)).toBe('50%'); expect(PercentDisplay.formatWhole(100)).toBe('100%'); }); it('should handle null/undefined whole percentages', () => { expect(PercentDisplay.formatWhole(null)).toBe('0%'); expect(PercentDisplay.formatWhole(undefined)).toBe('0%'); }); }); describe('cross-component consistency', () => { it('should all use consistent formatting for numeric values', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', rating: 1234.56, globalRank: 42, consistency: 85, }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, avgFinish: 5.4, bestFinish: 1, worstFinish: 25, finishRate: 0.933, winRate: 0.167, podiumRate: 0.4, percentile: 95, rating: 1234.56, consistency: 85, overallRank: 42, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); // All numeric values should be formatted as strings expect(typeof result.currentDriver?.ratingLabel).toBe('string'); expect(typeof result.currentDriver?.globalRankLabel).toBe('string'); expect(typeof result.stats?.totalRacesLabel).toBe('string'); expect(typeof result.stats?.winsLabel).toBe('string'); expect(typeof result.stats?.podiumsLabel).toBe('string'); expect(typeof result.stats?.dnfsLabel).toBe('string'); expect(typeof result.stats?.avgFinishLabel).toBe('string'); expect(typeof result.stats?.bestFinishLabel).toBe('string'); expect(typeof result.stats?.worstFinishLabel).toBe('string'); expect(typeof result.stats?.ratingLabel).toBe('string'); expect(typeof result.stats?.consistencyLabel).toBe('string'); }); it('should all handle missing data gracefully', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 0, wins: 0, podiums: 0, dnfs: 0, }, finishDistribution: { totalRaces: 0, wins: 0, podiums: 0, topTen: 0, dnfs: 0, other: 0, }, teamMemberships: [], socialSummary: { friendsCount: 0, friends: [], }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); // All fields should have safe defaults expect(result.currentDriver?.avatarUrl).toBe(''); expect(result.currentDriver?.iracingId).toBeNull(); expect(result.currentDriver?.rating).toBeNull(); expect(result.currentDriver?.ratingLabel).toBe('—'); expect(result.currentDriver?.globalRank).toBeNull(); expect(result.currentDriver?.globalRankLabel).toBe('—'); expect(result.currentDriver?.consistency).toBeNull(); expect(result.currentDriver?.bio).toBeNull(); expect(result.currentDriver?.totalDrivers).toBeNull(); expect(result.stats?.avgFinish).toBeNull(); expect(result.stats?.avgFinishLabel).toBe('—'); expect(result.stats?.bestFinish).toBeNull(); expect(result.stats?.bestFinishLabel).toBe('—'); expect(result.stats?.worstFinish).toBeNull(); expect(result.stats?.worstFinishLabel).toBe('—'); expect(result.stats?.finishRate).toBeNull(); expect(result.stats?.winRate).toBeNull(); expect(result.stats?.podiumRate).toBeNull(); expect(result.stats?.percentile).toBeNull(); expect(result.stats?.rating).toBeNull(); expect(result.stats?.ratingLabel).toBe('—'); expect(result.stats?.consistency).toBeNull(); expect(result.stats?.consistencyLabel).toBe('0%'); expect(result.stats?.overallRank).toBeNull(); expect(result.finishDistribution).not.toBeNull(); expect(result.teamMemberships).toEqual([]); expect(result.socialSummary.friends).toEqual([]); expect(result.extendedProfile).toBeNull(); }); it('should all preserve ISO timestamps for serialization', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [ { teamId: 'team-1', teamName: 'Elite Racing', teamTag: 'ER', role: 'Driver', joinedAt: '2024-01-15T00:00:00Z', isCurrent: true, }, ], socialSummary: { friendsCount: 0, friends: [], }, extendedProfile: { socialHandles: [], achievements: [ { id: 'ach-1', title: 'Champion', description: 'Won the championship', icon: 'trophy', rarity: 'Legendary', earnedAt: '2024-01-15T00:00:00Z', }, ], racingStyle: 'Aggressive', favoriteTrack: 'Spa', favoriteCar: 'Porsche 911 GT3', timezone: 'America/New_York', availableHours: 'Evenings', lookingForTeam: false, openToRequests: true, }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); // All timestamps should be preserved as ISO strings expect(result.currentDriver?.joinedAt).toBe('2024-01-15T00:00:00Z'); expect(result.teamMemberships[0].joinedAt).toBe('2024-01-15T00:00:00Z'); expect(result.extendedProfile?.achievements[0].earnedAt).toBe('2024-01-15T00:00:00Z'); }); it('should all handle boolean flags correctly', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', joinedAt: '2024-01-15T00:00:00Z', }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [ { teamId: 'team-1', teamName: 'Elite Racing', teamTag: 'ER', role: 'Driver', joinedAt: '2024-01-15T00:00:00Z', isCurrent: true, }, { teamId: 'team-2', teamName: 'Old Team', teamTag: 'OT', role: 'Driver', joinedAt: '2023-01-15T00:00:00Z', isCurrent: false, }, ], socialSummary: { friendsCount: 0, friends: [], }, extendedProfile: { socialHandles: [], achievements: [], racingStyle: 'Aggressive', favoriteTrack: 'Spa', favoriteCar: 'Porsche 911 GT3', timezone: 'America/New_York', availableHours: 'Evenings', lookingForTeam: true, openToRequests: false, }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); expect(result.teamMemberships[0].isCurrent).toBe(true); expect(result.teamMemberships[1].isCurrent).toBe(false); expect(result.extendedProfile?.lookingForTeam).toBe(true); expect(result.extendedProfile?.openToRequests).toBe(false); }); }); describe('data integrity', () => { it('should maintain data consistency across transformations', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', avatarUrl: 'https://example.com/avatar.jpg', iracingId: '12345', joinedAt: '2024-01-15T00:00:00Z', rating: 1234.56, globalRank: 42, consistency: 85, bio: 'Professional sim racer.', totalDrivers: 1000, }, stats: { totalRaces: 150, wins: 25, podiums: 60, dnfs: 10, avgFinish: 5.4, bestFinish: 1, worstFinish: 25, finishRate: 0.933, winRate: 0.167, podiumRate: 0.4, percentile: 95, rating: 1234.56, consistency: 85, overallRank: 42, }, finishDistribution: { totalRaces: 150, wins: 25, podiums: 60, topTen: 100, dnfs: 10, other: 55, }, teamMemberships: [ { teamId: 'team-1', teamName: 'Elite Racing', teamTag: 'ER', role: 'Driver', joinedAt: '2024-01-15T00:00:00Z', isCurrent: true, }, ], socialSummary: { friendsCount: 2, friends: [ { id: 'friend-1', name: 'Alice', country: 'UK', avatarUrl: 'https://example.com/alice.jpg' }, { id: 'friend-2', name: 'Bob', country: 'Germany' }, ], }, extendedProfile: { socialHandles: [ { platform: 'Twitter', handle: '@johndoe', url: 'https://twitter.com/johndoe' }, ], achievements: [ { id: 'ach-1', title: 'Champion', description: 'Won the championship', icon: 'trophy', rarity: 'Legendary', earnedAt: '2024-01-15T00:00:00Z' }, ], racingStyle: 'Aggressive', favoriteTrack: 'Spa', favoriteCar: 'Porsche 911 GT3', timezone: 'America/New_York', availableHours: 'Evenings', lookingForTeam: false, openToRequests: true, }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); // Verify derived fields match their source data expect(result.socialSummary.friendsCount).toBe(profileDTO.socialSummary.friends.length); expect(result.teamMemberships.length).toBe(profileDTO.teamMemberships.length); expect(result.extendedProfile?.achievements.length).toBe(profileDTO.extendedProfile?.achievements.length); }); it('should handle complex real-world scenarios', () => { const profileDTO: GetDriverProfileOutputDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', avatarUrl: 'https://example.com/avatar.jpg', iracingId: '12345', joinedAt: '2024-01-15T00:00:00Z', rating: 2456.78, globalRank: 15, consistency: 92.5, bio: 'Professional sim racer with 5 years of experience. Specializes in GT3 racing.', totalDrivers: 1000, }, stats: { totalRaces: 250, wins: 45, podiums: 120, dnfs: 15, avgFinish: 4.2, bestFinish: 1, worstFinish: 30, finishRate: 0.94, winRate: 0.18, podiumRate: 0.48, percentile: 98, rating: 2456.78, consistency: 92.5, overallRank: 15, }, finishDistribution: { totalRaces: 250, wins: 45, podiums: 120, topTen: 180, dnfs: 15, other: 55, }, teamMemberships: [ { teamId: 'team-1', teamName: 'Elite Racing', teamTag: 'ER', role: 'Driver', joinedAt: '2024-01-15T00:00:00Z', isCurrent: true, }, { teamId: 'team-2', teamName: 'Pro Team', teamTag: 'PT', role: 'Reserve Driver', joinedAt: '2023-06-15T00:00:00Z', isCurrent: false, }, ], socialSummary: { friendsCount: 50, friends: [ { id: 'friend-1', name: 'Alice', country: 'UK', avatarUrl: 'https://example.com/alice.jpg' }, { id: 'friend-2', name: 'Bob', country: 'Germany' }, { id: 'friend-3', name: 'Charlie', country: 'France', avatarUrl: 'https://example.com/charlie.jpg' }, ], }, extendedProfile: { socialHandles: [ { platform: 'Twitter', handle: '@johndoe', url: 'https://twitter.com/johndoe' }, { platform: 'Discord', handle: 'johndoe#1234', url: '' }, ], achievements: [ { id: 'ach-1', title: 'Champion', description: 'Won the championship', icon: 'trophy', rarity: 'Legendary', earnedAt: '2024-01-15T00:00:00Z' }, { id: 'ach-2', title: 'Podium Finisher', description: 'Finished on podium 100 times', icon: 'medal', rarity: 'Rare', earnedAt: '2023-12-01T00:00:00Z' }, ], racingStyle: 'Aggressive', favoriteTrack: 'Spa', favoriteCar: 'Porsche 911 GT3', timezone: 'America/New_York', availableHours: 'Evenings and Weekends', lookingForTeam: false, openToRequests: true, }, }; const result = DriverProfileViewDataBuilder.build(profileDTO); // Verify all transformations expect(result.currentDriver?.name).toBe('John Doe'); expect(result.currentDriver?.ratingLabel).toBe('2,457'); expect(result.currentDriver?.globalRankLabel).toBe('#15'); expect(result.currentDriver?.consistency).toBe(92.5); expect(result.currentDriver?.bio).toBe('Professional sim racer with 5 years of experience. Specializes in GT3 racing.'); expect(result.stats?.totalRacesLabel).toBe('250'); expect(result.stats?.winsLabel).toBe('45'); expect(result.stats?.podiumsLabel).toBe('120'); expect(result.stats?.dnfsLabel).toBe('15'); expect(result.stats?.avgFinishLabel).toBe('P4.2'); expect(result.stats?.bestFinishLabel).toBe('P1'); expect(result.stats?.worstFinishLabel).toBe('P30'); expect(result.stats?.finishRate).toBe(0.94); expect(result.stats?.winRate).toBe(0.18); expect(result.stats?.podiumRate).toBe(0.48); expect(result.stats?.percentile).toBe(98); expect(result.stats?.ratingLabel).toBe('2,457'); expect(result.stats?.consistencyLabel).toBe('93%'); expect(result.stats?.overallRank).toBe(15); expect(result.finishDistribution?.totalRaces).toBe(250); expect(result.finishDistribution?.wins).toBe(45); expect(result.finishDistribution?.podiums).toBe(120); expect(result.finishDistribution?.topTen).toBe(180); expect(result.finishDistribution?.dnfs).toBe(15); expect(result.finishDistribution?.other).toBe(55); expect(result.teamMemberships).toHaveLength(2); expect(result.teamMemberships[0].isCurrent).toBe(true); expect(result.teamMemberships[1].isCurrent).toBe(false); expect(result.socialSummary.friendsCount).toBe(50); expect(result.socialSummary.friends).toHaveLength(3); expect(result.socialSummary.friends[0].avatarUrl).toBe('https://example.com/alice.jpg'); expect(result.socialSummary.friends[1].avatarUrl).toBe(''); expect(result.socialSummary.friends[2].avatarUrl).toBe('https://example.com/charlie.jpg'); expect(result.extendedProfile?.socialHandles).toHaveLength(2); expect(result.extendedProfile?.achievements).toHaveLength(2); expect(result.extendedProfile?.achievements[0].rarityLabel).toBe('Legendary'); expect(result.extendedProfile?.achievements[1].rarityLabel).toBe('Rare'); expect(result.extendedProfile?.lookingForTeam).toBe(false); expect(result.extendedProfile?.openToRequests).toBe(true); }); }); });