view models
This commit is contained in:
146
apps/website/lib/view-models/DashboardOverviewViewModel.test.ts
Normal file
146
apps/website/lib/view-models/DashboardOverviewViewModel.test.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user