import { describe, it, expect } from 'vitest'; import { DashboardViewDataBuilder } from '../builders/view-data/DashboardViewDataBuilder'; import { DashboardDateDisplay } from './DashboardDateDisplay'; import { DashboardCountDisplay } from './DashboardCountDisplay'; import { DashboardRankDisplay } from './DashboardRankDisplay'; import { DashboardConsistencyDisplay } from './DashboardConsistencyDisplay'; import { DashboardLeaguePositionDisplay } from './DashboardLeaguePositionDisplay'; import { RatingDisplay } from './RatingDisplay'; import type { DashboardOverviewDTO } from '@/lib/types/generated/DashboardOverviewDTO'; describe('Dashboard View Data - Cross-Component Consistency', () => { describe('common patterns', () => { it('should all use consistent formatting for numeric values', () => { const dashboardDTO: DashboardOverviewDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', rating: 1234.56, globalRank: 42, totalRaces: 150, wins: 25, podiums: 60, consistency: 85, }, myUpcomingRaces: [], otherUpcomingRaces: [], upcomingRaces: [], activeLeaguesCount: 3, nextRace: null, recentResults: [], leagueStandingsSummaries: [ { leagueId: 'league-1', leagueName: 'Test League', position: 5, totalDrivers: 50, points: 1250, }, ], feedSummary: { notificationCount: 0, items: [], }, friends: [ { id: 'friend-1', name: 'Alice', country: 'UK' }, { id: 'friend-2', name: 'Bob', country: 'Germany' }, ], }; const result = DashboardViewDataBuilder.build(dashboardDTO); // All numeric values should be formatted as strings expect(typeof result.currentDriver.rating).toBe('string'); expect(typeof result.currentDriver.rank).toBe('string'); expect(typeof result.currentDriver.totalRaces).toBe('string'); expect(typeof result.currentDriver.wins).toBe('string'); expect(typeof result.currentDriver.podiums).toBe('string'); expect(typeof result.currentDriver.consistency).toBe('string'); expect(typeof result.activeLeaguesCount).toBe('string'); expect(typeof result.friendCount).toBe('string'); expect(typeof result.leagueStandings[0].position).toBe('string'); expect(typeof result.leagueStandings[0].points).toBe('string'); expect(typeof result.leagueStandings[0].totalDrivers).toBe('string'); }); it('should all handle missing data gracefully', () => { const dashboardDTO: DashboardOverviewDTO = { myUpcomingRaces: [], otherUpcomingRaces: [], upcomingRaces: [], activeLeaguesCount: 0, nextRace: null, recentResults: [], leagueStandingsSummaries: [], feedSummary: { notificationCount: 0, items: [], }, friends: [], }; const result = DashboardViewDataBuilder.build(dashboardDTO); // All fields should have safe defaults expect(result.currentDriver.name).toBe(''); expect(result.currentDriver.avatarUrl).toBe(''); expect(result.currentDriver.country).toBe(''); expect(result.currentDriver.rating).toBe('0.0'); expect(result.currentDriver.rank).toBe('0'); expect(result.currentDriver.totalRaces).toBe('0'); expect(result.currentDriver.wins).toBe('0'); expect(result.currentDriver.podiums).toBe('0'); expect(result.currentDriver.consistency).toBe('0%'); expect(result.nextRace).toBeNull(); expect(result.upcomingRaces).toEqual([]); expect(result.leagueStandings).toEqual([]); expect(result.feedItems).toEqual([]); expect(result.friends).toEqual([]); expect(result.activeLeaguesCount).toBe('0'); expect(result.friendCount).toBe('0'); }); it('should all preserve ISO timestamps for serialization', () => { const now = new Date(); const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); const feedTimestamp = new Date(now.getTime() - 30 * 60 * 1000); const dashboardDTO: DashboardOverviewDTO = { myUpcomingRaces: [], otherUpcomingRaces: [], upcomingRaces: [], activeLeaguesCount: 1, nextRace: { id: 'race-1', track: 'Spa', car: 'Porsche', scheduledAt: futureDate.toISOString(), status: 'scheduled', isMyLeague: true, }, recentResults: [], leagueStandingsSummaries: [], feedSummary: { notificationCount: 1, items: [ { id: 'feed-1', type: 'notification', headline: 'Test', timestamp: feedTimestamp.toISOString(), }, ], }, friends: [], }; const result = DashboardViewDataBuilder.build(dashboardDTO); // All timestamps should be preserved as ISO strings expect(result.nextRace?.scheduledAt).toBe(futureDate.toISOString()); expect(result.feedItems[0].timestamp).toBe(feedTimestamp.toISOString()); }); it('should all handle boolean flags correctly', () => { const dashboardDTO: DashboardOverviewDTO = { myUpcomingRaces: [], otherUpcomingRaces: [], upcomingRaces: [ { id: 'race-1', track: 'Spa', car: 'Porsche', scheduledAt: new Date().toISOString(), status: 'scheduled', isMyLeague: true, }, { id: 'race-2', track: 'Monza', car: 'Ferrari', scheduledAt: new Date().toISOString(), status: 'scheduled', isMyLeague: false, }, ], activeLeaguesCount: 1, nextRace: null, recentResults: [], leagueStandingsSummaries: [], feedSummary: { notificationCount: 0, items: [], }, friends: [], }; const result = DashboardViewDataBuilder.build(dashboardDTO); expect(result.upcomingRaces[0].isMyLeague).toBe(true); expect(result.upcomingRaces[1].isMyLeague).toBe(false); }); }); describe('data integrity', () => { it('should maintain data consistency across transformations', () => { const dashboardDTO: DashboardOverviewDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', rating: 1234.56, globalRank: 42, totalRaces: 150, wins: 25, podiums: 60, consistency: 85, }, myUpcomingRaces: [], otherUpcomingRaces: [], upcomingRaces: [], activeLeaguesCount: 3, nextRace: null, recentResults: [], leagueStandingsSummaries: [], feedSummary: { notificationCount: 5, items: [], }, friends: [ { id: 'friend-1', name: 'Alice', country: 'UK' }, { id: 'friend-2', name: 'Bob', country: 'Germany' }, ], }; const result = DashboardViewDataBuilder.build(dashboardDTO); // Verify derived fields match their source data expect(result.friendCount).toBe(dashboardDTO.friends.length.toString()); expect(result.activeLeaguesCount).toBe(dashboardDTO.activeLeaguesCount.toString()); expect(result.hasFriends).toBe(dashboardDTO.friends.length > 0); expect(result.hasUpcomingRaces).toBe(dashboardDTO.upcomingRaces.length > 0); expect(result.hasLeagueStandings).toBe(dashboardDTO.leagueStandingsSummaries.length > 0); expect(result.hasFeedItems).toBe(dashboardDTO.feedSummary.items.length > 0); }); it('should handle complex real-world scenarios', () => { const now = new Date(); const race1Date = new Date(now.getTime() + 2 * 24 * 60 * 60 * 1000); const race2Date = new Date(now.getTime() + 5 * 24 * 60 * 60 * 1000); const feedTimestamp = new Date(now.getTime() - 60 * 60 * 1000); const dashboardDTO: DashboardOverviewDTO = { currentDriver: { id: 'driver-123', name: 'John Doe', country: 'USA', avatarUrl: 'https://example.com/avatar.jpg', rating: 2456.78, globalRank: 15, totalRaces: 250, wins: 45, podiums: 120, consistency: 92.5, }, myUpcomingRaces: [], otherUpcomingRaces: [], upcomingRaces: [ { id: 'race-1', leagueId: 'league-1', leagueName: 'Pro League', track: 'Spa', car: 'Porsche 911 GT3', scheduledAt: race1Date.toISOString(), status: 'scheduled', isMyLeague: true, }, { id: 'race-2', track: 'Monza', car: 'Ferrari 488 GT3', scheduledAt: race2Date.toISOString(), status: 'scheduled', isMyLeague: false, }, ], activeLeaguesCount: 2, nextRace: { id: 'race-1', leagueId: 'league-1', leagueName: 'Pro League', track: 'Spa', car: 'Porsche 911 GT3', scheduledAt: race1Date.toISOString(), status: 'scheduled', isMyLeague: true, }, recentResults: [], leagueStandingsSummaries: [ { leagueId: 'league-1', leagueName: 'Pro League', position: 3, totalDrivers: 100, points: 2450, }, { leagueId: 'league-2', leagueName: 'Rookie League', position: 1, totalDrivers: 50, points: 1800, }, ], feedSummary: { notificationCount: 3, items: [ { id: 'feed-1', type: 'race_result', headline: 'Race completed', body: 'You finished 3rd in the Pro League race', timestamp: feedTimestamp.toISOString(), ctaLabel: 'View Results', ctaHref: '/races/123', }, { id: 'feed-2', type: 'league_update', headline: 'League standings updated', body: 'You moved up 2 positions', timestamp: feedTimestamp.toISOString(), }, ], }, 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' }, ], }; const result = DashboardViewDataBuilder.build(dashboardDTO); // Verify all transformations expect(result.currentDriver.name).toBe('John Doe'); expect(result.currentDriver.rating).toBe('2,457'); expect(result.currentDriver.rank).toBe('15'); expect(result.currentDriver.totalRaces).toBe('250'); expect(result.currentDriver.wins).toBe('45'); expect(result.currentDriver.podiums).toBe('120'); expect(result.currentDriver.consistency).toBe('92.5%'); expect(result.nextRace).not.toBeNull(); expect(result.nextRace?.id).toBe('race-1'); expect(result.nextRace?.track).toBe('Spa'); expect(result.nextRace?.isMyLeague).toBe(true); expect(result.upcomingRaces).toHaveLength(2); expect(result.upcomingRaces[0].isMyLeague).toBe(true); expect(result.upcomingRaces[1].isMyLeague).toBe(false); expect(result.leagueStandings).toHaveLength(2); expect(result.leagueStandings[0].position).toBe('#3'); expect(result.leagueStandings[0].points).toBe('2450'); expect(result.leagueStandings[1].position).toBe('#1'); expect(result.leagueStandings[1].points).toBe('1800'); expect(result.feedItems).toHaveLength(2); expect(result.feedItems[0].type).toBe('race_result'); expect(result.feedItems[0].ctaLabel).toBe('View Results'); expect(result.feedItems[1].type).toBe('league_update'); expect(result.feedItems[1].ctaLabel).toBeUndefined(); expect(result.friends).toHaveLength(3); expect(result.friends[0].avatarUrl).toBe('https://example.com/alice.jpg'); expect(result.friends[1].avatarUrl).toBe(''); expect(result.friends[2].avatarUrl).toBe('https://example.com/charlie.jpg'); expect(result.activeLeaguesCount).toBe('2'); expect(result.friendCount).toBe('3'); expect(result.hasUpcomingRaces).toBe(true); expect(result.hasLeagueStandings).toBe(true); expect(result.hasFeedItems).toBe(true); expect(result.hasFriends).toBe(true); }); }); });