867 lines
26 KiB
TypeScript
867 lines
26 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { DashboardViewDataBuilder } from './DashboardViewDataBuilder';
|
|
import type { DashboardOverviewDTO } from '@/lib/types/generated/DashboardOverviewDTO';
|
|
|
|
describe('DashboardViewDataBuilder', () => {
|
|
describe('happy paths', () => {
|
|
it('should transform DashboardOverviewDTO to DashboardViewData correctly', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
avatarUrl: 'https://example.com/avatar.jpg',
|
|
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: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.currentDriver).toEqual({
|
|
name: 'John Doe',
|
|
avatarUrl: 'https://example.com/avatar.jpg',
|
|
country: 'USA',
|
|
rating: '1,235',
|
|
rank: '42',
|
|
totalRaces: '150',
|
|
wins: '25',
|
|
podiums: '60',
|
|
consistency: '85%',
|
|
});
|
|
expect(result.nextRace).toBeNull();
|
|
expect(result.upcomingRaces).toEqual([]);
|
|
expect(result.leagueStandings).toEqual([]);
|
|
expect(result.feedItems).toEqual([]);
|
|
expect(result.friends).toEqual([]);
|
|
expect(result.activeLeaguesCount).toBe('3');
|
|
expect(result.friendCount).toBe('0');
|
|
expect(result.hasUpcomingRaces).toBe(false);
|
|
expect(result.hasLeagueStandings).toBe(false);
|
|
expect(result.hasFeedItems).toBe(false);
|
|
expect(result.hasFriends).toBe(false);
|
|
});
|
|
|
|
it('should handle missing currentDriver gracefully', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 0,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.currentDriver).toEqual({
|
|
name: '',
|
|
avatarUrl: '',
|
|
country: '',
|
|
rating: '0.0',
|
|
rank: '0',
|
|
totalRaces: '0',
|
|
wins: '0',
|
|
podiums: '0',
|
|
consistency: '0%',
|
|
});
|
|
});
|
|
|
|
it('should handle null/undefined driver fields', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'Jane Smith',
|
|
country: 'Canada',
|
|
rating: null,
|
|
globalRank: null,
|
|
totalRaces: 0,
|
|
wins: 0,
|
|
podiums: 0,
|
|
consistency: null,
|
|
},
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 0,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.currentDriver.rating).toBe('0');
|
|
expect(result.currentDriver.rank).toBe('0');
|
|
expect(result.currentDriver.consistency).toBe('0%');
|
|
});
|
|
|
|
it('should handle nextRace with all fields', () => {
|
|
const now = new Date();
|
|
const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); // 24 hours from now
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: {
|
|
id: 'race-456',
|
|
leagueId: 'league-789',
|
|
leagueName: 'Pro League',
|
|
track: 'Monza',
|
|
car: 'Ferrari 488 GT3',
|
|
scheduledAt: futureDate.toISOString(),
|
|
status: 'scheduled',
|
|
isMyLeague: true,
|
|
},
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.nextRace).not.toBeNull();
|
|
expect(result.nextRace?.id).toBe('race-456');
|
|
expect(result.nextRace?.track).toBe('Monza');
|
|
expect(result.nextRace?.car).toBe('Ferrari 488 GT3');
|
|
expect(result.nextRace?.scheduledAt).toBe(futureDate.toISOString());
|
|
expect(result.nextRace?.isMyLeague).toBe(true);
|
|
expect(result.nextRace?.formattedDate).toBeDefined();
|
|
expect(result.nextRace?.formattedTime).toBeDefined();
|
|
expect(result.nextRace?.timeUntil).toBeDefined();
|
|
});
|
|
|
|
it('should handle upcomingRaces with multiple races', () => {
|
|
const now = new Date();
|
|
const race1Date = new Date(now.getTime() + 2 * 24 * 60 * 60 * 1000); // 2 days from now
|
|
const race2Date = new Date(now.getTime() + 5 * 24 * 60 * 60 * 1000); // 5 days from now
|
|
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [
|
|
{
|
|
id: 'race-1',
|
|
track: 'Spa',
|
|
car: 'Porsche 911 GT3',
|
|
scheduledAt: race1Date.toISOString(),
|
|
status: 'scheduled',
|
|
isMyLeague: true,
|
|
},
|
|
{
|
|
id: 'race-2',
|
|
track: 'Nürburgring',
|
|
car: 'Audi R8 LMS',
|
|
scheduledAt: race2Date.toISOString(),
|
|
status: 'scheduled',
|
|
isMyLeague: false,
|
|
},
|
|
],
|
|
activeLeaguesCount: 2,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.upcomingRaces).toHaveLength(2);
|
|
expect(result.upcomingRaces[0].id).toBe('race-1');
|
|
expect(result.upcomingRaces[0].track).toBe('Spa');
|
|
expect(result.upcomingRaces[0].isMyLeague).toBe(true);
|
|
expect(result.upcomingRaces[1].id).toBe('race-2');
|
|
expect(result.upcomingRaces[1].track).toBe('Nürburgring');
|
|
expect(result.upcomingRaces[1].isMyLeague).toBe(false);
|
|
expect(result.hasUpcomingRaces).toBe(true);
|
|
});
|
|
|
|
it('should handle leagueStandings with multiple leagues', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 2,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [
|
|
{
|
|
leagueId: 'league-1',
|
|
leagueName: 'Rookie League',
|
|
position: 5,
|
|
totalDrivers: 50,
|
|
points: 1250,
|
|
},
|
|
{
|
|
leagueId: 'league-2',
|
|
leagueName: 'Pro League',
|
|
position: 12,
|
|
totalDrivers: 100,
|
|
points: 890,
|
|
},
|
|
],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.leagueStandings).toHaveLength(2);
|
|
expect(result.leagueStandings[0].leagueId).toBe('league-1');
|
|
expect(result.leagueStandings[0].leagueName).toBe('Rookie League');
|
|
expect(result.leagueStandings[0].position).toBe('#5');
|
|
expect(result.leagueStandings[0].points).toBe('1250');
|
|
expect(result.leagueStandings[0].totalDrivers).toBe('50');
|
|
expect(result.leagueStandings[1].leagueId).toBe('league-2');
|
|
expect(result.leagueStandings[1].leagueName).toBe('Pro League');
|
|
expect(result.leagueStandings[1].position).toBe('#12');
|
|
expect(result.leagueStandings[1].points).toBe('890');
|
|
expect(result.leagueStandings[1].totalDrivers).toBe('100');
|
|
expect(result.hasLeagueStandings).toBe(true);
|
|
});
|
|
|
|
it('should handle feedItems with all fields', () => {
|
|
const now = new Date();
|
|
const timestamp = new Date(now.getTime() - 30 * 60 * 1000); // 30 minutes ago
|
|
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 3,
|
|
items: [
|
|
{
|
|
id: 'feed-1',
|
|
type: 'race_result',
|
|
headline: 'Race completed',
|
|
body: 'You finished 3rd in the Pro League race',
|
|
timestamp: timestamp.toISOString(),
|
|
ctaLabel: 'View Results',
|
|
ctaHref: '/races/123',
|
|
},
|
|
{
|
|
id: 'feed-2',
|
|
type: 'league_update',
|
|
headline: 'League standings updated',
|
|
body: 'You moved up 2 positions',
|
|
timestamp: timestamp.toISOString(),
|
|
},
|
|
],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.feedItems).toHaveLength(2);
|
|
expect(result.feedItems[0].id).toBe('feed-1');
|
|
expect(result.feedItems[0].type).toBe('race_result');
|
|
expect(result.feedItems[0].headline).toBe('Race completed');
|
|
expect(result.feedItems[0].body).toBe('You finished 3rd in the Pro League race');
|
|
expect(result.feedItems[0].timestamp).toBe(timestamp.toISOString());
|
|
expect(result.feedItems[0].formattedTime).toBe('Past');
|
|
expect(result.feedItems[0].ctaLabel).toBe('View Results');
|
|
expect(result.feedItems[0].ctaHref).toBe('/races/123');
|
|
expect(result.feedItems[1].id).toBe('feed-2');
|
|
expect(result.feedItems[1].type).toBe('league_update');
|
|
expect(result.feedItems[1].headline).toBe('League standings updated');
|
|
expect(result.feedItems[1].body).toBe('You moved up 2 positions');
|
|
expect(result.feedItems[1].ctaLabel).toBeUndefined();
|
|
expect(result.feedItems[1].ctaHref).toBeUndefined();
|
|
expect(result.hasFeedItems).toBe(true);
|
|
});
|
|
|
|
it('should handle friends with avatar URLs', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [
|
|
{
|
|
id: 'friend-1',
|
|
name: 'Alice',
|
|
country: 'UK',
|
|
avatarUrl: 'https://example.com/alice.jpg',
|
|
},
|
|
{
|
|
id: 'friend-2',
|
|
name: 'Bob',
|
|
country: 'Germany',
|
|
avatarUrl: undefined,
|
|
},
|
|
],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.friends).toHaveLength(2);
|
|
expect(result.friends[0].id).toBe('friend-1');
|
|
expect(result.friends[0].name).toBe('Alice');
|
|
expect(result.friends[0].country).toBe('UK');
|
|
expect(result.friends[0].avatarUrl).toBe('https://example.com/alice.jpg');
|
|
expect(result.friends[1].id).toBe('friend-2');
|
|
expect(result.friends[1].name).toBe('Bob');
|
|
expect(result.friends[1].country).toBe('Germany');
|
|
expect(result.friends[1].avatarUrl).toBe('');
|
|
expect(result.friendCount).toBe('2');
|
|
expect(result.hasFriends).toBe(true);
|
|
});
|
|
|
|
it('should handle empty arrays and zero counts', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 0,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
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');
|
|
expect(result.hasUpcomingRaces).toBe(false);
|
|
expect(result.hasLeagueStandings).toBe(false);
|
|
expect(result.hasFeedItems).toBe(false);
|
|
expect(result.hasFriends).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('data transformation', () => {
|
|
it('should preserve all DTO fields in the output', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
avatarUrl: 'https://example.com/avatar.jpg',
|
|
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: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.currentDriver.name).toBe(dashboardDTO.currentDriver?.name);
|
|
expect(result.currentDriver.country).toBe(dashboardDTO.currentDriver?.country);
|
|
expect(result.currentDriver.avatarUrl).toBe(dashboardDTO.currentDriver?.avatarUrl);
|
|
expect(result.activeLeaguesCount).toBe(dashboardDTO.activeLeaguesCount.toString());
|
|
});
|
|
|
|
it('should not modify the input DTO', () => {
|
|
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: [],
|
|
};
|
|
|
|
const originalDTO = JSON.parse(JSON.stringify(dashboardDTO));
|
|
DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(dashboardDTO).toEqual(originalDTO);
|
|
});
|
|
|
|
it('should transform all numeric fields to formatted strings', () => {
|
|
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: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
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');
|
|
});
|
|
|
|
it('should handle large numbers correctly', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
rating: 999999.99,
|
|
globalRank: 1,
|
|
totalRaces: 10000,
|
|
wins: 2500,
|
|
podiums: 5000,
|
|
consistency: 99.9,
|
|
},
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 100,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.currentDriver.rating).toBe('1,000,000');
|
|
expect(result.currentDriver.totalRaces).toBe('10000');
|
|
expect(result.currentDriver.wins).toBe('2500');
|
|
expect(result.currentDriver.podiums).toBe('5000');
|
|
expect(result.currentDriver.consistency).toBe('99.9%');
|
|
expect(result.activeLeaguesCount).toBe('100');
|
|
});
|
|
});
|
|
|
|
describe('edge cases', () => {
|
|
it('should handle missing optional fields in driver', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
totalRaces: 100,
|
|
wins: 20,
|
|
podiums: 40,
|
|
},
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.currentDriver.avatarUrl).toBe('');
|
|
expect(result.currentDriver.rating).toBe('0');
|
|
expect(result.currentDriver.rank).toBe('0');
|
|
expect(result.currentDriver.consistency).toBe('0%');
|
|
});
|
|
|
|
it('should handle race with missing optional fields', () => {
|
|
const now = new Date();
|
|
const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000);
|
|
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: {
|
|
id: 'race-456',
|
|
track: 'Monza',
|
|
car: 'Ferrari 488 GT3',
|
|
scheduledAt: futureDate.toISOString(),
|
|
status: 'scheduled',
|
|
isMyLeague: true,
|
|
},
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.nextRace).not.toBeNull();
|
|
expect(result.nextRace?.leagueId).toBeUndefined();
|
|
expect(result.nextRace?.leagueName).toBeUndefined();
|
|
});
|
|
|
|
it('should handle feed item with missing optional fields', () => {
|
|
const now = new Date();
|
|
const timestamp = new Date(now.getTime() - 60 * 60 * 1000); // 1 hour ago
|
|
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 1,
|
|
items: [
|
|
{
|
|
id: 'feed-1',
|
|
type: 'notification',
|
|
headline: 'New notification',
|
|
timestamp: timestamp.toISOString(),
|
|
},
|
|
],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.feedItems[0].body).toBeUndefined();
|
|
expect(result.feedItems[0].ctaLabel).toBeUndefined();
|
|
expect(result.feedItems[0].ctaHref).toBeUndefined();
|
|
});
|
|
|
|
it('should handle friend with missing avatarUrl', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [
|
|
{
|
|
id: 'friend-1',
|
|
name: 'Alice',
|
|
country: 'UK',
|
|
},
|
|
],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.friends[0].avatarUrl).toBe('');
|
|
});
|
|
|
|
it('should handle league standing with null position', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [
|
|
{
|
|
leagueId: 'league-1',
|
|
leagueName: 'Test League',
|
|
position: null as any,
|
|
totalDrivers: 50,
|
|
points: 1000,
|
|
},
|
|
],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.leagueStandings[0].position).toBe('-');
|
|
});
|
|
|
|
it('should handle race with empty track and car', () => {
|
|
const now = new Date();
|
|
const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000);
|
|
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: {
|
|
id: 'race-456',
|
|
track: '',
|
|
car: '',
|
|
scheduledAt: futureDate.toISOString(),
|
|
status: 'scheduled',
|
|
isMyLeague: true,
|
|
},
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.nextRace?.track).toBe('');
|
|
expect(result.nextRace?.car).toBe('');
|
|
});
|
|
});
|
|
|
|
describe('derived fields', () => {
|
|
it('should correctly calculate hasUpcomingRaces', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [
|
|
{
|
|
id: 'race-1',
|
|
track: 'Spa',
|
|
car: 'Porsche',
|
|
scheduledAt: new Date().toISOString(),
|
|
status: 'scheduled',
|
|
isMyLeague: true,
|
|
},
|
|
],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.hasUpcomingRaces).toBe(true);
|
|
});
|
|
|
|
it('should correctly calculate hasLeagueStandings', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [
|
|
{
|
|
leagueId: 'league-1',
|
|
leagueName: 'Test League',
|
|
position: 5,
|
|
totalDrivers: 50,
|
|
points: 1000,
|
|
},
|
|
],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.hasLeagueStandings).toBe(true);
|
|
});
|
|
|
|
it('should correctly calculate hasFeedItems', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 1,
|
|
items: [
|
|
{
|
|
id: 'feed-1',
|
|
type: 'notification',
|
|
headline: 'Test',
|
|
timestamp: new Date().toISOString(),
|
|
},
|
|
],
|
|
},
|
|
friends: [],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.hasFeedItems).toBe(true);
|
|
});
|
|
|
|
it('should correctly calculate hasFriends', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [
|
|
{
|
|
id: 'friend-1',
|
|
name: 'Alice',
|
|
country: 'UK',
|
|
},
|
|
],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.hasFriends).toBe(true);
|
|
});
|
|
|
|
it('should correctly calculate friendCount', () => {
|
|
const dashboardDTO: DashboardOverviewDTO = {
|
|
myUpcomingRaces: [],
|
|
otherUpcomingRaces: [],
|
|
upcomingRaces: [],
|
|
activeLeaguesCount: 1,
|
|
nextRace: null,
|
|
recentResults: [],
|
|
leagueStandingsSummaries: [],
|
|
feedSummary: {
|
|
notificationCount: 0,
|
|
items: [],
|
|
},
|
|
friends: [
|
|
{ id: 'friend-1', name: 'Alice', country: 'UK' },
|
|
{ id: 'friend-2', name: 'Bob', country: 'Germany' },
|
|
{ id: 'friend-3', name: 'Charlie', country: 'France' },
|
|
],
|
|
};
|
|
|
|
const result = DashboardViewDataBuilder.build(dashboardDTO);
|
|
|
|
expect(result.friendCount).toBe('3');
|
|
});
|
|
});
|
|
});
|