import { describe, it, expect } from 'vitest'; import { DashboardOverviewViewModel, DriverViewModel, RaceViewModel, LeagueStandingViewModel, DashboardFeedItemSummaryViewModel, FriendViewModel, } from './DashboardOverviewViewModel'; import type { DashboardOverviewDto } from '../api/dashboard/DashboardApiClient'; const createDashboardOverviewDto = (): DashboardOverviewDto => ({ currentDriver: { id: 'driver-1', name: 'Test Driver', avatarUrl: 'https://example.com/avatar.jpg', country: 'DE', totalRaces: 10, wins: 3, podiums: 5, rating: 2500, globalRank: 42, consistency: 88, }, nextRace: { id: 'race-1', track: 'Spa-Francorchamps', car: 'GT3', scheduledAt: '2025-01-01T12:00:00Z', isMyLeague: true, leagueName: 'Pro League', }, upcomingRaces: [ { id: 'race-2', track: 'Nürburgring', car: 'GT4', scheduledAt: '2025-01-02T12:00:00Z', isMyLeague: false, leagueName: undefined, }, ], leagueStandings: [ { leagueId: 'league-1', leagueName: 'Pro League', position: 1, points: 120, totalDrivers: 50, }, ], feedItems: [ { id: 'feed-1', type: 'news', headline: 'Big race announced', body: 'Details about the big race.', timestamp: '2025-01-01T10:00:00Z', ctaHref: '/races/race-1', ctaLabel: 'View race', }, ], friends: [ { id: 'friend-1', name: 'Racing Buddy', avatarUrl: 'https://example.com/friend.jpg', country: 'US', }, ], activeLeaguesCount: 3, }); describe('DashboardOverviewViewModel', () => { it('wraps the current driver DTO in a DriverViewModel', () => { const dto = createDashboardOverviewDto(); const viewModel = new DashboardOverviewViewModel(dto); const currentDriver = viewModel.currentDriver; expect(currentDriver).toBeInstanceOf(DriverViewModel); expect(currentDriver.id).toBe('driver-1'); expect(currentDriver.name).toBe('Test Driver'); expect(currentDriver.avatarUrl).toBe('https://example.com/avatar.jpg'); expect(currentDriver.country).toBe('DE'); expect(currentDriver.totalRaces).toBe(10); expect(currentDriver.wins).toBe(3); expect(currentDriver.podiums).toBe(5); expect(currentDriver.rating).toBe(2500); expect(currentDriver.globalRank).toBe(42); expect(currentDriver.consistency).toBe(88); }); it('wraps nextRace DTO into a RaceViewModel and returns null when absent', () => { const dtoWithRace = createDashboardOverviewDto(); const viewModelWithRace = new DashboardOverviewViewModel(dtoWithRace); const nextRace = viewModelWithRace.nextRace; expect(nextRace).toBeInstanceOf(RaceViewModel); expect(nextRace?.id).toBe('race-1'); expect(nextRace?.track).toBe('Spa-Francorchamps'); expect(nextRace?.car).toBe('GT3'); expect(nextRace?.isMyLeague).toBe(true); expect(nextRace?.leagueName).toBe('Pro League'); expect(nextRace?.scheduledAt).toBeInstanceOf(Date); const dtoWithoutRace: DashboardOverviewDto = { ...dtoWithRace, nextRace: null, }; const viewModelWithoutRace = new DashboardOverviewViewModel(dtoWithoutRace); expect(viewModelWithoutRace.nextRace).toBeNull(); }); it('maps upcoming races, league standings, feed items and friends into their respective view models', () => { const dto = createDashboardOverviewDto(); const viewModel = new DashboardOverviewViewModel(dto); expect(viewModel.upcomingRaces).toHaveLength(1); expect(viewModel.upcomingRaces[0]).toBeInstanceOf(RaceViewModel); expect(viewModel.upcomingRaces[0].id).toBe('race-2'); expect(viewModel.leagueStandings).toHaveLength(1); expect(viewModel.leagueStandings[0]).toBeInstanceOf(LeagueStandingViewModel); expect(viewModel.leagueStandings[0].leagueId).toBe('league-1'); expect(viewModel.feedItems).toHaveLength(1); expect(viewModel.feedItems[0]).toBeInstanceOf(DashboardFeedItemSummaryViewModel); expect(viewModel.feedItems[0].id).toBe('feed-1'); expect(viewModel.feedItems[0].timestamp).toBeInstanceOf(Date); expect(viewModel.friends).toHaveLength(1); expect(viewModel.friends[0]).toBeInstanceOf(FriendViewModel); expect(viewModel.friends[0].id).toBe('friend-1'); }); it('exposes the activeLeaguesCount from the DTO', () => { const dto = createDashboardOverviewDto(); const viewModel = new DashboardOverviewViewModel(dto); expect(viewModel.activeLeaguesCount).toBe(3); }); });