view data tests
This commit is contained in:
@@ -0,0 +1,499 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ProfileViewDataBuilder } from './ProfileViewDataBuilder';
|
||||
import type { GetDriverProfileOutputDTO } from '@/lib/types/generated/GetDriverProfileOutputDTO';
|
||||
|
||||
describe('ProfileViewDataBuilder', () => {
|
||||
describe('happy paths', () => {
|
||||
it('should transform GetDriverProfileOutputDTO to ProfileViewData correctly', () => {
|
||||
const profileDto: GetDriverProfileOutputDTO = {
|
||||
currentDriver: {
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
bio: 'Test bio',
|
||||
iracingId: 12345,
|
||||
joinedAt: '2024-01-01',
|
||||
globalRank: 100,
|
||||
},
|
||||
stats: {
|
||||
totalRaces: 50,
|
||||
wins: 10,
|
||||
podiums: 20,
|
||||
dnfs: 5,
|
||||
avgFinish: 5.5,
|
||||
bestFinish: 1,
|
||||
worstFinish: 20,
|
||||
finishRate: 90,
|
||||
winRate: 20,
|
||||
podiumRate: 40,
|
||||
percentile: 95,
|
||||
rating: 1500,
|
||||
consistency: 85,
|
||||
overallRank: 100,
|
||||
},
|
||||
finishDistribution: {
|
||||
totalRaces: 50,
|
||||
wins: 10,
|
||||
podiums: 20,
|
||||
topTen: 30,
|
||||
dnfs: 5,
|
||||
other: 15,
|
||||
},
|
||||
teamMemberships: [
|
||||
{
|
||||
teamId: 'team-1',
|
||||
teamName: 'Test Team',
|
||||
teamTag: 'TT',
|
||||
role: 'driver',
|
||||
joinedAt: '2024-01-01',
|
||||
isCurrent: true,
|
||||
},
|
||||
],
|
||||
socialSummary: {
|
||||
friendsCount: 10,
|
||||
friends: [
|
||||
{
|
||||
id: 'friend-1',
|
||||
name: 'Friend 1',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
},
|
||||
],
|
||||
},
|
||||
extendedProfile: {
|
||||
socialHandles: [
|
||||
{
|
||||
platform: 'twitter',
|
||||
handle: '@test',
|
||||
url: 'https://twitter.com/test',
|
||||
},
|
||||
],
|
||||
achievements: [
|
||||
{
|
||||
id: 'ach-1',
|
||||
title: 'Achievement',
|
||||
description: 'Test achievement',
|
||||
icon: 'trophy',
|
||||
rarity: 'rare',
|
||||
earnedAt: '2024-01-01',
|
||||
},
|
||||
],
|
||||
racingStyle: 'Aggressive',
|
||||
favoriteTrack: 'Test Track',
|
||||
favoriteCar: 'Test Car',
|
||||
timezone: 'UTC',
|
||||
availableHours: 10,
|
||||
lookingForTeam: true,
|
||||
openToRequests: true,
|
||||
},
|
||||
};
|
||||
|
||||
const result = ProfileViewDataBuilder.build(profileDto);
|
||||
|
||||
expect(result.driver.id).toBe('driver-123');
|
||||
expect(result.driver.name).toBe('Test Driver');
|
||||
expect(result.driver.countryCode).toBe('US');
|
||||
expect(result.driver.bio).toBe('Test bio');
|
||||
expect(result.driver.iracingId).toBe('12345');
|
||||
expect(result.stats).not.toBeNull();
|
||||
expect(result.stats?.ratingLabel).toBe('1500');
|
||||
expect(result.teamMemberships).toHaveLength(1);
|
||||
expect(result.extendedProfile).not.toBeNull();
|
||||
expect(result.extendedProfile?.socialHandles).toHaveLength(1);
|
||||
expect(result.extendedProfile?.achievements).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should handle null driver (no profile)', () => {
|
||||
const profileDto: GetDriverProfileOutputDTO = {
|
||||
currentDriver: null,
|
||||
stats: null,
|
||||
finishDistribution: null,
|
||||
teamMemberships: [],
|
||||
socialSummary: {
|
||||
friendsCount: 0,
|
||||
friends: [],
|
||||
},
|
||||
extendedProfile: null,
|
||||
};
|
||||
|
||||
const result = ProfileViewDataBuilder.build(profileDto);
|
||||
|
||||
expect(result.driver.id).toBe('');
|
||||
expect(result.driver.name).toBe('');
|
||||
expect(result.driver.countryCode).toBe('');
|
||||
expect(result.driver.bio).toBeNull();
|
||||
expect(result.driver.iracingId).toBeNull();
|
||||
expect(result.stats).toBeNull();
|
||||
expect(result.teamMemberships).toHaveLength(0);
|
||||
expect(result.extendedProfile).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle null stats', () => {
|
||||
const profileDto: GetDriverProfileOutputDTO = {
|
||||
currentDriver: {
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
bio: null,
|
||||
iracingId: null,
|
||||
joinedAt: '2024-01-01',
|
||||
globalRank: null,
|
||||
},
|
||||
stats: null,
|
||||
finishDistribution: null,
|
||||
teamMemberships: [],
|
||||
socialSummary: {
|
||||
friendsCount: 0,
|
||||
friends: [],
|
||||
},
|
||||
extendedProfile: null,
|
||||
};
|
||||
|
||||
const result = ProfileViewDataBuilder.build(profileDto);
|
||||
|
||||
expect(result.stats).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('data transformation', () => {
|
||||
it('should preserve all DTO fields in the output', () => {
|
||||
const profileDto: GetDriverProfileOutputDTO = {
|
||||
currentDriver: {
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
bio: 'Test bio',
|
||||
iracingId: 12345,
|
||||
joinedAt: '2024-01-01',
|
||||
globalRank: 100,
|
||||
},
|
||||
stats: {
|
||||
totalRaces: 50,
|
||||
wins: 10,
|
||||
podiums: 20,
|
||||
dnfs: 5,
|
||||
avgFinish: 5.5,
|
||||
bestFinish: 1,
|
||||
worstFinish: 20,
|
||||
finishRate: 90,
|
||||
winRate: 20,
|
||||
podiumRate: 40,
|
||||
percentile: 95,
|
||||
rating: 1500,
|
||||
consistency: 85,
|
||||
overallRank: 100,
|
||||
},
|
||||
finishDistribution: {
|
||||
totalRaces: 50,
|
||||
wins: 10,
|
||||
podiums: 20,
|
||||
topTen: 30,
|
||||
dnfs: 5,
|
||||
other: 15,
|
||||
},
|
||||
teamMemberships: [
|
||||
{
|
||||
teamId: 'team-1',
|
||||
teamName: 'Test Team',
|
||||
teamTag: 'TT',
|
||||
role: 'driver',
|
||||
joinedAt: '2024-01-01',
|
||||
isCurrent: true,
|
||||
},
|
||||
],
|
||||
socialSummary: {
|
||||
friendsCount: 10,
|
||||
friends: [
|
||||
{
|
||||
id: 'friend-1',
|
||||
name: 'Friend 1',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
},
|
||||
],
|
||||
},
|
||||
extendedProfile: {
|
||||
socialHandles: [
|
||||
{
|
||||
platform: 'twitter',
|
||||
handle: '@test',
|
||||
url: 'https://twitter.com/test',
|
||||
},
|
||||
],
|
||||
achievements: [
|
||||
{
|
||||
id: 'ach-1',
|
||||
title: 'Achievement',
|
||||
description: 'Test achievement',
|
||||
icon: 'trophy',
|
||||
rarity: 'rare',
|
||||
earnedAt: '2024-01-01',
|
||||
},
|
||||
],
|
||||
racingStyle: 'Aggressive',
|
||||
favoriteTrack: 'Test Track',
|
||||
favoriteCar: 'Test Car',
|
||||
timezone: 'UTC',
|
||||
availableHours: 10,
|
||||
lookingForTeam: true,
|
||||
openToRequests: true,
|
||||
},
|
||||
};
|
||||
|
||||
const result = ProfileViewDataBuilder.build(profileDto);
|
||||
|
||||
expect(result.driver.id).toBe(profileDto.currentDriver?.id);
|
||||
expect(result.driver.name).toBe(profileDto.currentDriver?.name);
|
||||
expect(result.driver.countryCode).toBe(profileDto.currentDriver?.country);
|
||||
expect(result.driver.bio).toBe(profileDto.currentDriver?.bio);
|
||||
expect(result.driver.iracingId).toBe(String(profileDto.currentDriver?.iracingId));
|
||||
expect(result.stats?.totalRacesLabel).toBe('50');
|
||||
expect(result.stats?.winsLabel).toBe('10');
|
||||
expect(result.teamMemberships).toHaveLength(1);
|
||||
expect(result.extendedProfile?.socialHandles).toHaveLength(1);
|
||||
expect(result.extendedProfile?.achievements).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should not modify the input DTO', () => {
|
||||
const profileDto: GetDriverProfileOutputDTO = {
|
||||
currentDriver: {
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
bio: 'Test bio',
|
||||
iracingId: 12345,
|
||||
joinedAt: '2024-01-01',
|
||||
globalRank: 100,
|
||||
},
|
||||
stats: {
|
||||
totalRaces: 50,
|
||||
wins: 10,
|
||||
podiums: 20,
|
||||
dnfs: 5,
|
||||
avgFinish: 5.5,
|
||||
bestFinish: 1,
|
||||
worstFinish: 20,
|
||||
finishRate: 90,
|
||||
winRate: 20,
|
||||
podiumRate: 40,
|
||||
percentile: 95,
|
||||
rating: 1500,
|
||||
consistency: 85,
|
||||
overallRank: 100,
|
||||
},
|
||||
finishDistribution: {
|
||||
totalRaces: 50,
|
||||
wins: 10,
|
||||
podiums: 20,
|
||||
topTen: 30,
|
||||
dnfs: 5,
|
||||
other: 15,
|
||||
},
|
||||
teamMemberships: [
|
||||
{
|
||||
teamId: 'team-1',
|
||||
teamName: 'Test Team',
|
||||
teamTag: 'TT',
|
||||
role: 'driver',
|
||||
joinedAt: '2024-01-01',
|
||||
isCurrent: true,
|
||||
},
|
||||
],
|
||||
socialSummary: {
|
||||
friendsCount: 10,
|
||||
friends: [
|
||||
{
|
||||
id: 'friend-1',
|
||||
name: 'Friend 1',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
},
|
||||
],
|
||||
},
|
||||
extendedProfile: {
|
||||
socialHandles: [
|
||||
{
|
||||
platform: 'twitter',
|
||||
handle: '@test',
|
||||
url: 'https://twitter.com/test',
|
||||
},
|
||||
],
|
||||
achievements: [
|
||||
{
|
||||
id: 'ach-1',
|
||||
title: 'Achievement',
|
||||
description: 'Test achievement',
|
||||
icon: 'trophy',
|
||||
rarity: 'rare',
|
||||
earnedAt: '2024-01-01',
|
||||
},
|
||||
],
|
||||
racingStyle: 'Aggressive',
|
||||
favoriteTrack: 'Test Track',
|
||||
favoriteCar: 'Test Car',
|
||||
timezone: 'UTC',
|
||||
availableHours: 10,
|
||||
lookingForTeam: true,
|
||||
openToRequests: true,
|
||||
},
|
||||
};
|
||||
|
||||
const originalDto = { ...profileDto };
|
||||
ProfileViewDataBuilder.build(profileDto);
|
||||
|
||||
expect(profileDto).toEqual(originalDto);
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle driver without avatar', () => {
|
||||
const profileDto: GetDriverProfileOutputDTO = {
|
||||
currentDriver: {
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
country: 'US',
|
||||
avatarUrl: null,
|
||||
bio: null,
|
||||
iracingId: null,
|
||||
joinedAt: '2024-01-01',
|
||||
globalRank: null,
|
||||
},
|
||||
stats: null,
|
||||
finishDistribution: null,
|
||||
teamMemberships: [],
|
||||
socialSummary: {
|
||||
friendsCount: 0,
|
||||
friends: [],
|
||||
},
|
||||
extendedProfile: null,
|
||||
};
|
||||
|
||||
const result = ProfileViewDataBuilder.build(profileDto);
|
||||
|
||||
expect(result.driver.avatarUrl).toContain('default');
|
||||
});
|
||||
|
||||
it('should handle driver without iracingId', () => {
|
||||
const profileDto: GetDriverProfileOutputDTO = {
|
||||
currentDriver: {
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
bio: null,
|
||||
iracingId: null,
|
||||
joinedAt: '2024-01-01',
|
||||
globalRank: null,
|
||||
},
|
||||
stats: null,
|
||||
finishDistribution: null,
|
||||
teamMemberships: [],
|
||||
socialSummary: {
|
||||
friendsCount: 0,
|
||||
friends: [],
|
||||
},
|
||||
extendedProfile: null,
|
||||
};
|
||||
|
||||
const result = ProfileViewDataBuilder.build(profileDto);
|
||||
|
||||
expect(result.driver.iracingId).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle driver without global rank', () => {
|
||||
const profileDto: GetDriverProfileOutputDTO = {
|
||||
currentDriver: {
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
bio: null,
|
||||
iracingId: null,
|
||||
joinedAt: '2024-01-01',
|
||||
globalRank: null,
|
||||
},
|
||||
stats: null,
|
||||
finishDistribution: null,
|
||||
teamMemberships: [],
|
||||
socialSummary: {
|
||||
friendsCount: 0,
|
||||
friends: [],
|
||||
},
|
||||
extendedProfile: null,
|
||||
};
|
||||
|
||||
const result = ProfileViewDataBuilder.build(profileDto);
|
||||
|
||||
expect(result.driver.globalRankLabel).toBe('—');
|
||||
});
|
||||
|
||||
it('should handle empty team memberships', () => {
|
||||
const profileDto: GetDriverProfileOutputDTO = {
|
||||
currentDriver: {
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
bio: null,
|
||||
iracingId: null,
|
||||
joinedAt: '2024-01-01',
|
||||
globalRank: null,
|
||||
},
|
||||
stats: null,
|
||||
finishDistribution: null,
|
||||
teamMemberships: [],
|
||||
socialSummary: {
|
||||
friendsCount: 0,
|
||||
friends: [],
|
||||
},
|
||||
extendedProfile: null,
|
||||
};
|
||||
|
||||
const result = ProfileViewDataBuilder.build(profileDto);
|
||||
|
||||
expect(result.teamMemberships).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should handle empty friends list', () => {
|
||||
const profileDto: GetDriverProfileOutputDTO = {
|
||||
currentDriver: {
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
country: 'US',
|
||||
avatarUrl: 'avatar-url',
|
||||
bio: null,
|
||||
iracingId: null,
|
||||
joinedAt: '2024-01-01',
|
||||
globalRank: null,
|
||||
},
|
||||
stats: null,
|
||||
finishDistribution: null,
|
||||
teamMemberships: [],
|
||||
socialSummary: {
|
||||
friendsCount: 0,
|
||||
friends: [],
|
||||
},
|
||||
extendedProfile: {
|
||||
socialHandles: [],
|
||||
achievements: [],
|
||||
racingStyle: null,
|
||||
favoriteTrack: null,
|
||||
favoriteCar: null,
|
||||
timezone: null,
|
||||
availableHours: null,
|
||||
lookingForTeam: false,
|
||||
openToRequests: false,
|
||||
},
|
||||
};
|
||||
|
||||
const result = ProfileViewDataBuilder.build(profileDto);
|
||||
|
||||
expect(result.extendedProfile?.friends).toHaveLength(0);
|
||||
expect(result.extendedProfile?.friendsCountLabel).toBe('0');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user