Files
gridpilot.gg/apps/website/lib/view-models/DashboardOverviewViewModel.test.ts
2025-12-20 00:31:31 +01:00

147 lines
4.5 KiB
TypeScript

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);
});
});