1197 lines
35 KiB
TypeScript
1197 lines
35 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { DriverProfileViewDataBuilder } from './DriverProfileViewDataBuilder';
|
|
import type { GetDriverProfileOutputDTO } from '@/lib/types/generated/GetDriverProfileOutputDTO';
|
|
|
|
describe('DriverProfileViewDataBuilder', () => {
|
|
describe('happy paths', () => {
|
|
it('should transform GetDriverProfileOutputDTO to DriverProfileViewData correctly', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
avatarUrl: 'https://example.com/avatar.jpg',
|
|
iracingId: '12345',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
rating: 1234.56,
|
|
globalRank: 42,
|
|
consistency: 85,
|
|
bio: 'Professional sim racer with 5 years of experience.',
|
|
totalDrivers: 1000,
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
avgFinish: 5.4,
|
|
bestFinish: 1,
|
|
worstFinish: 25,
|
|
finishRate: 0.933,
|
|
winRate: 0.167,
|
|
podiumRate: 0.4,
|
|
percentile: 95,
|
|
rating: 1234.56,
|
|
consistency: 85,
|
|
overallRank: 42,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [
|
|
{
|
|
teamId: 'team-1',
|
|
teamName: 'Elite Racing',
|
|
teamTag: 'ER',
|
|
role: 'Driver',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
isCurrent: true,
|
|
},
|
|
],
|
|
socialSummary: {
|
|
friendsCount: 50,
|
|
friends: [
|
|
{
|
|
id: 'friend-1',
|
|
name: 'Jane Smith',
|
|
country: 'Canada',
|
|
avatarUrl: 'https://example.com/jane.jpg',
|
|
},
|
|
],
|
|
},
|
|
extendedProfile: {
|
|
socialHandles: [
|
|
{
|
|
platform: 'Twitter',
|
|
handle: '@johndoe',
|
|
url: 'https://twitter.com/johndoe',
|
|
},
|
|
],
|
|
achievements: [
|
|
{
|
|
id: 'ach-1',
|
|
title: 'Champion',
|
|
description: 'Won the championship',
|
|
icon: 'trophy',
|
|
rarity: 'Legendary',
|
|
earnedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
],
|
|
racingStyle: 'Aggressive',
|
|
favoriteTrack: 'Spa',
|
|
favoriteCar: 'Porsche 911 GT3',
|
|
timezone: 'America/New_York',
|
|
availableHours: 'Evenings',
|
|
lookingForTeam: false,
|
|
openToRequests: true,
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
// Current driver
|
|
expect(result.currentDriver).not.toBeNull();
|
|
expect(result.currentDriver?.id).toBe('driver-123');
|
|
expect(result.currentDriver?.name).toBe('John Doe');
|
|
expect(result.currentDriver?.country).toBe('USA');
|
|
expect(result.currentDriver?.avatarUrl).toBe('https://example.com/avatar.jpg');
|
|
expect(result.currentDriver?.iracingId).toBe(12345);
|
|
expect(result.currentDriver?.joinedAt).toBe('2024-01-15T00:00:00Z');
|
|
expect(result.currentDriver?.joinedAtLabel).toBe('Jan 2024');
|
|
expect(result.currentDriver?.rating).toBe(1234.56);
|
|
expect(result.currentDriver?.ratingLabel).toBe('1,235');
|
|
expect(result.currentDriver?.globalRank).toBe(42);
|
|
expect(result.currentDriver?.globalRankLabel).toBe('#42');
|
|
expect(result.currentDriver?.consistency).toBe(85);
|
|
expect(result.currentDriver?.bio).toBe('Professional sim racer with 5 years of experience.');
|
|
expect(result.currentDriver?.totalDrivers).toBe(1000);
|
|
|
|
// Stats
|
|
expect(result.stats).not.toBeNull();
|
|
expect(result.stats?.totalRaces).toBe(150);
|
|
expect(result.stats?.totalRacesLabel).toBe('150');
|
|
expect(result.stats?.wins).toBe(25);
|
|
expect(result.stats?.winsLabel).toBe('25');
|
|
expect(result.stats?.podiums).toBe(60);
|
|
expect(result.stats?.podiumsLabel).toBe('60');
|
|
expect(result.stats?.dnfs).toBe(10);
|
|
expect(result.stats?.dnfsLabel).toBe('10');
|
|
expect(result.stats?.avgFinish).toBe(5.4);
|
|
expect(result.stats?.avgFinishLabel).toBe('P5.4');
|
|
expect(result.stats?.bestFinish).toBe(1);
|
|
expect(result.stats?.bestFinishLabel).toBe('P1');
|
|
expect(result.stats?.worstFinish).toBe(25);
|
|
expect(result.stats?.worstFinishLabel).toBe('P25');
|
|
expect(result.stats?.finishRate).toBe(0.933);
|
|
expect(result.stats?.winRate).toBe(0.167);
|
|
expect(result.stats?.podiumRate).toBe(0.4);
|
|
expect(result.stats?.percentile).toBe(95);
|
|
expect(result.stats?.rating).toBe(1234.56);
|
|
expect(result.stats?.ratingLabel).toBe('1,235');
|
|
expect(result.stats?.consistency).toBe(85);
|
|
expect(result.stats?.consistencyLabel).toBe('85%');
|
|
expect(result.stats?.overallRank).toBe(42);
|
|
|
|
// Finish distribution
|
|
expect(result.finishDistribution).not.toBeNull();
|
|
expect(result.finishDistribution?.totalRaces).toBe(150);
|
|
expect(result.finishDistribution?.wins).toBe(25);
|
|
expect(result.finishDistribution?.podiums).toBe(60);
|
|
expect(result.finishDistribution?.topTen).toBe(100);
|
|
expect(result.finishDistribution?.dnfs).toBe(10);
|
|
expect(result.finishDistribution?.other).toBe(55);
|
|
|
|
// Team memberships
|
|
expect(result.teamMemberships).toHaveLength(1);
|
|
expect(result.teamMemberships[0].teamId).toBe('team-1');
|
|
expect(result.teamMemberships[0].teamName).toBe('Elite Racing');
|
|
expect(result.teamMemberships[0].teamTag).toBe('ER');
|
|
expect(result.teamMemberships[0].role).toBe('Driver');
|
|
expect(result.teamMemberships[0].joinedAt).toBe('2024-01-15T00:00:00Z');
|
|
expect(result.teamMemberships[0].joinedAtLabel).toBe('Jan 2024');
|
|
expect(result.teamMemberships[0].isCurrent).toBe(true);
|
|
|
|
// Social summary
|
|
expect(result.socialSummary.friendsCount).toBe(50);
|
|
expect(result.socialSummary.friends).toHaveLength(1);
|
|
expect(result.socialSummary.friends[0].id).toBe('friend-1');
|
|
expect(result.socialSummary.friends[0].name).toBe('Jane Smith');
|
|
expect(result.socialSummary.friends[0].country).toBe('Canada');
|
|
expect(result.socialSummary.friends[0].avatarUrl).toBe('https://example.com/jane.jpg');
|
|
|
|
// Extended profile
|
|
expect(result.extendedProfile).not.toBeNull();
|
|
expect(result.extendedProfile?.socialHandles).toHaveLength(1);
|
|
expect(result.extendedProfile?.socialHandles[0].platform).toBe('Twitter');
|
|
expect(result.extendedProfile?.socialHandles[0].handle).toBe('@johndoe');
|
|
expect(result.extendedProfile?.socialHandles[0].url).toBe('https://twitter.com/johndoe');
|
|
expect(result.extendedProfile?.achievements).toHaveLength(1);
|
|
expect(result.extendedProfile?.achievements[0].id).toBe('ach-1');
|
|
expect(result.extendedProfile?.achievements[0].title).toBe('Champion');
|
|
expect(result.extendedProfile?.achievements[0].description).toBe('Won the championship');
|
|
expect(result.extendedProfile?.achievements[0].icon).toBe('trophy');
|
|
expect(result.extendedProfile?.achievements[0].rarity).toBe('Legendary');
|
|
expect(result.extendedProfile?.achievements[0].rarityLabel).toBe('Legendary');
|
|
expect(result.extendedProfile?.achievements[0].earnedAt).toBe('2024-01-15T00:00:00Z');
|
|
expect(result.extendedProfile?.achievements[0].earnedAtLabel).toBe('Jan 15, 2024');
|
|
expect(result.extendedProfile?.racingStyle).toBe('Aggressive');
|
|
expect(result.extendedProfile?.favoriteTrack).toBe('Spa');
|
|
expect(result.extendedProfile?.favoriteCar).toBe('Porsche 911 GT3');
|
|
expect(result.extendedProfile?.timezone).toBe('America/New_York');
|
|
expect(result.extendedProfile?.availableHours).toBe('Evenings');
|
|
expect(result.extendedProfile?.lookingForTeam).toBe(false);
|
|
expect(result.extendedProfile?.openToRequests).toBe(true);
|
|
});
|
|
|
|
it('should handle missing currentDriver gracefully', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver).toBeNull();
|
|
expect(result.stats).not.toBeNull();
|
|
expect(result.finishDistribution).not.toBeNull();
|
|
});
|
|
|
|
it('should handle missing stats gracefully', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver).not.toBeNull();
|
|
expect(result.stats).toBeNull();
|
|
expect(result.finishDistribution).not.toBeNull();
|
|
});
|
|
|
|
it('should handle missing finishDistribution gracefully', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver).not.toBeNull();
|
|
expect(result.stats).not.toBeNull();
|
|
expect(result.finishDistribution).toBeNull();
|
|
});
|
|
|
|
it('should handle missing extendedProfile gracefully', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver).not.toBeNull();
|
|
expect(result.stats).not.toBeNull();
|
|
expect(result.finishDistribution).not.toBeNull();
|
|
expect(result.extendedProfile).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('data transformation', () => {
|
|
it('should preserve all DTO fields in the output', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
avatarUrl: 'https://example.com/avatar.jpg',
|
|
iracingId: '12345',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
rating: 1234.56,
|
|
globalRank: 42,
|
|
consistency: 85,
|
|
bio: 'Professional sim racer.',
|
|
totalDrivers: 1000,
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
avgFinish: 5.4,
|
|
bestFinish: 1,
|
|
worstFinish: 25,
|
|
finishRate: 0.933,
|
|
winRate: 0.167,
|
|
podiumRate: 0.4,
|
|
percentile: 95,
|
|
rating: 1234.56,
|
|
consistency: 85,
|
|
overallRank: 42,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [
|
|
{
|
|
teamId: 'team-1',
|
|
teamName: 'Elite Racing',
|
|
teamTag: 'ER',
|
|
role: 'Driver',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
isCurrent: true,
|
|
},
|
|
],
|
|
socialSummary: {
|
|
friendsCount: 50,
|
|
friends: [
|
|
{
|
|
id: 'friend-1',
|
|
name: 'Jane Smith',
|
|
country: 'Canada',
|
|
avatarUrl: 'https://example.com/jane.jpg',
|
|
},
|
|
],
|
|
},
|
|
extendedProfile: {
|
|
socialHandles: [
|
|
{
|
|
platform: 'Twitter',
|
|
handle: '@johndoe',
|
|
url: 'https://twitter.com/johndoe',
|
|
},
|
|
],
|
|
achievements: [
|
|
{
|
|
id: 'ach-1',
|
|
title: 'Champion',
|
|
description: 'Won the championship',
|
|
icon: 'trophy',
|
|
rarity: 'Legendary',
|
|
earnedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
],
|
|
racingStyle: 'Aggressive',
|
|
favoriteTrack: 'Spa',
|
|
favoriteCar: 'Porsche 911 GT3',
|
|
timezone: 'America/New_York',
|
|
availableHours: 'Evenings',
|
|
lookingForTeam: false,
|
|
openToRequests: true,
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver?.name).toBe(profileDTO.currentDriver?.name);
|
|
expect(result.currentDriver?.country).toBe(profileDTO.currentDriver?.country);
|
|
expect(result.currentDriver?.avatarUrl).toBe(profileDTO.currentDriver?.avatarUrl);
|
|
expect(result.currentDriver?.iracingId).toBe(12345);
|
|
expect(result.currentDriver?.joinedAt).toBe(profileDTO.currentDriver?.joinedAt);
|
|
expect(result.currentDriver?.bio).toBe(profileDTO.currentDriver?.bio);
|
|
expect(result.currentDriver?.totalDrivers).toBe(profileDTO.currentDriver?.totalDrivers);
|
|
});
|
|
|
|
it('should not modify the input DTO', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
avatarUrl: 'https://example.com/avatar.jpg',
|
|
iracingId: '12345',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
rating: 1234.56,
|
|
globalRank: 42,
|
|
consistency: 85,
|
|
bio: 'Professional sim racer.',
|
|
totalDrivers: 1000,
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const originalDTO = JSON.parse(JSON.stringify(profileDTO));
|
|
DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(profileDTO).toEqual(originalDTO);
|
|
});
|
|
|
|
it('should transform all numeric fields to formatted strings where appropriate', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
rating: 1234.56,
|
|
globalRank: 42,
|
|
consistency: 85,
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
avgFinish: 5.4,
|
|
bestFinish: 1,
|
|
worstFinish: 25,
|
|
finishRate: 0.933,
|
|
winRate: 0.167,
|
|
podiumRate: 0.4,
|
|
percentile: 95,
|
|
rating: 1234.56,
|
|
consistency: 85,
|
|
overallRank: 42,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
// Rating labels should be formatted strings
|
|
expect(typeof result.currentDriver?.ratingLabel).toBe('string');
|
|
expect(result.currentDriver?.ratingLabel).toBe('1,235');
|
|
expect(typeof result.stats?.ratingLabel).toBe('string');
|
|
expect(result.stats?.ratingLabel).toBe('1,235');
|
|
|
|
// Rank labels should be formatted strings
|
|
expect(typeof result.currentDriver?.globalRankLabel).toBe('string');
|
|
expect(result.currentDriver?.globalRankLabel).toBe('#42');
|
|
|
|
// Count labels should be formatted strings
|
|
expect(typeof result.stats?.totalRacesLabel).toBe('string');
|
|
expect(result.stats?.totalRacesLabel).toBe('150');
|
|
expect(typeof result.stats?.winsLabel).toBe('string');
|
|
expect(result.stats?.winsLabel).toBe('25');
|
|
expect(typeof result.stats?.podiumsLabel).toBe('string');
|
|
expect(result.stats?.podiumsLabel).toBe('60');
|
|
expect(typeof result.stats?.dnfsLabel).toBe('string');
|
|
expect(result.stats?.dnfsLabel).toBe('10');
|
|
|
|
// Finish labels should be formatted strings
|
|
expect(typeof result.stats?.avgFinishLabel).toBe('string');
|
|
expect(result.stats?.avgFinishLabel).toBe('P5.4');
|
|
expect(typeof result.stats?.bestFinishLabel).toBe('string');
|
|
expect(result.stats?.bestFinishLabel).toBe('P1');
|
|
expect(typeof result.stats?.worstFinishLabel).toBe('string');
|
|
expect(result.stats?.worstFinishLabel).toBe('P25');
|
|
|
|
// Consistency label should be formatted string
|
|
expect(typeof result.stats?.consistencyLabel).toBe('string');
|
|
expect(result.stats?.consistencyLabel).toBe('85%');
|
|
});
|
|
|
|
it('should handle iracingId as string and convert to number', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
iracingId: '12345',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver?.iracingId).toBe(12345);
|
|
});
|
|
|
|
it('should handle iracingId as number', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
iracingId: 12345,
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver?.iracingId).toBe(12345);
|
|
});
|
|
|
|
it('should handle missing iracingId', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver?.iracingId).toBeNull();
|
|
});
|
|
|
|
it('should handle empty avatarUrl', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
avatarUrl: '',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver?.avatarUrl).toBe('');
|
|
});
|
|
|
|
it('should handle missing avatarUrl', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver?.avatarUrl).toBe('');
|
|
});
|
|
|
|
it('should handle missing avatarUrl in friends', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 1,
|
|
friends: [
|
|
{
|
|
id: 'friend-1',
|
|
name: 'Jane Smith',
|
|
country: 'Canada',
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.socialSummary.friends[0].avatarUrl).toBe('');
|
|
});
|
|
|
|
it('should handle missing teamTag', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [
|
|
{
|
|
teamId: 'team-1',
|
|
teamName: 'Elite Racing',
|
|
role: 'Driver',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
isCurrent: true,
|
|
},
|
|
],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.teamMemberships[0].teamTag).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('edge cases', () => {
|
|
it('should handle null/undefined rating in currentDriver', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
rating: null,
|
|
globalRank: null,
|
|
consistency: null,
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.currentDriver?.rating).toBeNull();
|
|
expect(result.currentDriver?.ratingLabel).toBe('—');
|
|
expect(result.currentDriver?.globalRank).toBeNull();
|
|
expect(result.currentDriver?.globalRankLabel).toBe('—');
|
|
expect(result.currentDriver?.consistency).toBeNull();
|
|
});
|
|
|
|
it('should handle null/undefined rating in stats', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
rating: null,
|
|
consistency: null,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.stats?.rating).toBeNull();
|
|
expect(result.stats?.ratingLabel).toBe('—');
|
|
expect(result.stats?.consistency).toBeNull();
|
|
expect(result.stats?.consistencyLabel).toBe('0%');
|
|
});
|
|
|
|
it('should handle null/undefined finish positions', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
avgFinish: null,
|
|
bestFinish: null,
|
|
worstFinish: null,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.stats?.avgFinish).toBeNull();
|
|
expect(result.stats?.avgFinishLabel).toBe('—');
|
|
expect(result.stats?.bestFinish).toBeNull();
|
|
expect(result.stats?.bestFinishLabel).toBe('—');
|
|
expect(result.stats?.worstFinish).toBeNull();
|
|
expect(result.stats?.worstFinishLabel).toBe('—');
|
|
});
|
|
|
|
it('should handle null/undefined rates', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
finishRate: null,
|
|
winRate: null,
|
|
podiumRate: null,
|
|
percentile: null,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.stats?.finishRate).toBeNull();
|
|
expect(result.stats?.winRate).toBeNull();
|
|
expect(result.stats?.podiumRate).toBeNull();
|
|
expect(result.stats?.percentile).toBeNull();
|
|
});
|
|
|
|
it('should handle empty teamMemberships array', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.teamMemberships).toEqual([]);
|
|
});
|
|
|
|
it('should handle empty friends array', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.socialSummary.friends).toEqual([]);
|
|
expect(result.socialSummary.friendsCount).toBe(0);
|
|
});
|
|
|
|
it('should handle empty socialHandles array', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
extendedProfile: {
|
|
socialHandles: [],
|
|
achievements: [],
|
|
racingStyle: 'Aggressive',
|
|
favoriteTrack: 'Spa',
|
|
favoriteCar: 'Porsche 911 GT3',
|
|
timezone: 'America/New_York',
|
|
availableHours: 'Evenings',
|
|
lookingForTeam: false,
|
|
openToRequests: true,
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.extendedProfile?.socialHandles).toEqual([]);
|
|
});
|
|
|
|
it('should handle empty achievements array', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
extendedProfile: {
|
|
socialHandles: [],
|
|
achievements: [],
|
|
racingStyle: 'Aggressive',
|
|
favoriteTrack: 'Spa',
|
|
favoriteCar: 'Porsche 911 GT3',
|
|
timezone: 'America/New_York',
|
|
availableHours: 'Evenings',
|
|
lookingForTeam: false,
|
|
openToRequests: true,
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.extendedProfile?.achievements).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('derived fields', () => {
|
|
it('should correctly calculate finish distribution totals', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 0,
|
|
friends: [],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
// Verify that finish distribution totals match the stats
|
|
expect(result.finishDistribution?.totalRaces).toBe(150);
|
|
expect(result.finishDistribution?.wins).toBe(25);
|
|
expect(result.finishDistribution?.podiums).toBe(60);
|
|
expect(result.finishDistribution?.dnfs).toBe(10);
|
|
});
|
|
|
|
it('should correctly calculate friend count', () => {
|
|
const profileDTO: GetDriverProfileOutputDTO = {
|
|
currentDriver: {
|
|
id: 'driver-123',
|
|
name: 'John Doe',
|
|
country: 'USA',
|
|
joinedAt: '2024-01-15T00:00:00Z',
|
|
},
|
|
stats: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
dnfs: 10,
|
|
},
|
|
finishDistribution: {
|
|
totalRaces: 150,
|
|
wins: 25,
|
|
podiums: 60,
|
|
topTen: 100,
|
|
dnfs: 10,
|
|
other: 55,
|
|
},
|
|
teamMemberships: [],
|
|
socialSummary: {
|
|
friendsCount: 5,
|
|
friends: [
|
|
{ id: 'friend-1', name: 'Alice', country: 'UK' },
|
|
{ id: 'friend-2', name: 'Bob', country: 'Germany' },
|
|
{ id: 'friend-3', name: 'Charlie', country: 'France' },
|
|
{ id: 'friend-4', name: 'Diana', country: 'USA' },
|
|
{ id: 'friend-5', name: 'Eve', country: 'Canada' },
|
|
],
|
|
},
|
|
};
|
|
|
|
const result = DriverProfileViewDataBuilder.build(profileDTO);
|
|
|
|
expect(result.socialSummary.friendsCount).toBe(5);
|
|
expect(result.socialSummary.friends).toHaveLength(5);
|
|
});
|
|
});
|
|
});
|