431 lines
14 KiB
TypeScript
431 lines
14 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { TeamRankingsViewDataBuilder } from './TeamRankingsViewDataBuilder';
|
|
import type { GetTeamsLeaderboardOutputDTO } from '@/lib/types/generated/GetTeamsLeaderboardOutputDTO';
|
|
|
|
describe('TeamRankingsViewDataBuilder', () => {
|
|
describe('happy paths', () => {
|
|
it('should transform GetTeamsLeaderboardOutputDTO to TeamRankingsViewData correctly', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{
|
|
id: 'team-1',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
logoUrl: 'https://example.com/logo1.jpg',
|
|
memberCount: 15,
|
|
rating: 1500,
|
|
totalWins: 50,
|
|
totalRaces: 200,
|
|
performanceLevel: 'elite',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
{
|
|
id: 'team-2',
|
|
name: 'Speed Demons',
|
|
tag: 'SD',
|
|
logoUrl: 'https://example.com/logo2.jpg',
|
|
memberCount: 8,
|
|
rating: 1200,
|
|
totalWins: 20,
|
|
totalRaces: 150,
|
|
performanceLevel: 'advanced',
|
|
isRecruiting: true,
|
|
createdAt: '2023-06-01',
|
|
},
|
|
{
|
|
id: 'team-3',
|
|
name: 'Rookie Racers',
|
|
tag: 'RR',
|
|
logoUrl: 'https://example.com/logo3.jpg',
|
|
memberCount: 5,
|
|
rating: 800,
|
|
totalWins: 5,
|
|
totalRaces: 50,
|
|
performanceLevel: 'intermediate',
|
|
isRecruiting: false,
|
|
createdAt: '2023-09-01',
|
|
},
|
|
],
|
|
recruitingCount: 5,
|
|
groupsBySkillLevel: 'elite,advanced,intermediate',
|
|
topTeams: [
|
|
{
|
|
id: 'team-1',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
logoUrl: 'https://example.com/logo1.jpg',
|
|
memberCount: 15,
|
|
rating: 1500,
|
|
totalWins: 50,
|
|
totalRaces: 200,
|
|
performanceLevel: 'elite',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
{
|
|
id: 'team-2',
|
|
name: 'Speed Demons',
|
|
tag: 'SD',
|
|
logoUrl: 'https://example.com/logo2.jpg',
|
|
memberCount: 8,
|
|
rating: 1200,
|
|
totalWins: 20,
|
|
totalRaces: 150,
|
|
performanceLevel: 'advanced',
|
|
isRecruiting: true,
|
|
createdAt: '2023-06-01',
|
|
},
|
|
],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
// Verify teams
|
|
expect(result.teams).toHaveLength(3);
|
|
expect(result.teams[0].id).toBe('team-1');
|
|
expect(result.teams[0].name).toBe('Racing Team Alpha');
|
|
expect(result.teams[0].tag).toBe('RTA');
|
|
expect(result.teams[0].memberCount).toBe(15);
|
|
expect(result.teams[0].totalWins).toBe(50);
|
|
expect(result.teams[0].totalRaces).toBe(200);
|
|
expect(result.teams[0].logoUrl).toBe('https://example.com/logo1.jpg');
|
|
expect(result.teams[0].position).toBe(1);
|
|
expect(result.teams[0].isRecruiting).toBe(false);
|
|
expect(result.teams[0].performanceLevel).toBe('elite');
|
|
expect(result.teams[0].rating).toBe(1500);
|
|
expect(result.teams[0].category).toBeUndefined();
|
|
|
|
// Verify podium (top 3)
|
|
expect(result.podium).toHaveLength(3);
|
|
expect(result.podium[0].id).toBe('team-1');
|
|
expect(result.podium[0].position).toBe(1);
|
|
expect(result.podium[1].id).toBe('team-2');
|
|
expect(result.podium[1].position).toBe(2);
|
|
expect(result.podium[2].id).toBe('team-3');
|
|
expect(result.podium[2].position).toBe(3);
|
|
|
|
// Verify recruiting count
|
|
expect(result.recruitingCount).toBe(5);
|
|
});
|
|
|
|
it('should handle empty team array', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [],
|
|
recruitingCount: 0,
|
|
groupsBySkillLevel: '',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams).toEqual([]);
|
|
expect(result.podium).toEqual([]);
|
|
expect(result.recruitingCount).toBe(0);
|
|
});
|
|
|
|
it('should handle less than 3 teams for podium', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{
|
|
id: 'team-1',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
logoUrl: 'https://example.com/logo1.jpg',
|
|
memberCount: 15,
|
|
rating: 1500,
|
|
totalWins: 50,
|
|
totalRaces: 200,
|
|
performanceLevel: 'elite',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
{
|
|
id: 'team-2',
|
|
name: 'Speed Demons',
|
|
tag: 'SD',
|
|
logoUrl: 'https://example.com/logo2.jpg',
|
|
memberCount: 8,
|
|
rating: 1200,
|
|
totalWins: 20,
|
|
totalRaces: 150,
|
|
performanceLevel: 'advanced',
|
|
isRecruiting: true,
|
|
createdAt: '2023-06-01',
|
|
},
|
|
],
|
|
recruitingCount: 2,
|
|
groupsBySkillLevel: 'elite,advanced',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams).toHaveLength(2);
|
|
expect(result.podium).toHaveLength(2);
|
|
expect(result.podium[0].position).toBe(1);
|
|
expect(result.podium[1].position).toBe(2);
|
|
});
|
|
|
|
it('should handle missing avatar URLs with empty string fallback', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{
|
|
id: 'team-1',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
memberCount: 15,
|
|
totalWins: 50,
|
|
totalRaces: 200,
|
|
performanceLevel: 'elite',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
],
|
|
recruitingCount: 0,
|
|
groupsBySkillLevel: '',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams[0].logoUrl).toBe('');
|
|
});
|
|
|
|
it('should calculate position based on index', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{ id: 'team-1', name: 'Team 1', tag: 'T1', memberCount: 10, totalWins: 30, totalRaces: 150, performanceLevel: 'elite', isRecruiting: false, createdAt: '2023-01-01' },
|
|
{ id: 'team-2', name: 'Team 2', tag: 'T2', memberCount: 8, totalWins: 20, totalRaces: 120, performanceLevel: 'advanced', isRecruiting: true, createdAt: '2023-02-01' },
|
|
{ id: 'team-3', name: 'Team 3', tag: 'T3', memberCount: 6, totalWins: 10, totalRaces: 80, performanceLevel: 'intermediate', isRecruiting: false, createdAt: '2023-03-01' },
|
|
{ id: 'team-4', name: 'Team 4', tag: 'T4', memberCount: 4, totalWins: 5, totalRaces: 40, performanceLevel: 'beginner', isRecruiting: true, createdAt: '2023-04-01' },
|
|
],
|
|
recruitingCount: 2,
|
|
groupsBySkillLevel: 'elite,advanced,intermediate,beginner',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams[0].position).toBe(1);
|
|
expect(result.teams[1].position).toBe(2);
|
|
expect(result.teams[2].position).toBe(3);
|
|
expect(result.teams[3].position).toBe(4);
|
|
});
|
|
});
|
|
|
|
describe('data transformation', () => {
|
|
it('should preserve all DTO fields in the output', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{
|
|
id: 'team-123',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
logoUrl: 'https://example.com/logo.jpg',
|
|
memberCount: 15,
|
|
rating: 1500,
|
|
totalWins: 50,
|
|
totalRaces: 200,
|
|
performanceLevel: 'elite',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
],
|
|
recruitingCount: 5,
|
|
groupsBySkillLevel: 'elite,advanced',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams[0].name).toBe(teamDTO.teams[0].name);
|
|
expect(result.teams[0].tag).toBe(teamDTO.teams[0].tag);
|
|
expect(result.teams[0].logoUrl).toBe(teamDTO.teams[0].logoUrl);
|
|
expect(result.teams[0].memberCount).toBe(teamDTO.teams[0].memberCount);
|
|
expect(result.teams[0].rating).toBe(teamDTO.teams[0].rating);
|
|
expect(result.teams[0].totalWins).toBe(teamDTO.teams[0].totalWins);
|
|
expect(result.teams[0].totalRaces).toBe(teamDTO.teams[0].totalRaces);
|
|
expect(result.teams[0].performanceLevel).toBe(teamDTO.teams[0].performanceLevel);
|
|
expect(result.teams[0].isRecruiting).toBe(teamDTO.teams[0].isRecruiting);
|
|
});
|
|
|
|
it('should not modify the input DTO', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{
|
|
id: 'team-123',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
logoUrl: 'https://example.com/logo.jpg',
|
|
memberCount: 15,
|
|
rating: 1500,
|
|
totalWins: 50,
|
|
totalRaces: 200,
|
|
performanceLevel: 'elite',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
],
|
|
recruitingCount: 5,
|
|
groupsBySkillLevel: 'elite,advanced',
|
|
topTeams: [],
|
|
};
|
|
|
|
const originalDTO = JSON.parse(JSON.stringify(teamDTO));
|
|
TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(teamDTO).toEqual(originalDTO);
|
|
});
|
|
|
|
it('should handle large numbers correctly', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{
|
|
id: 'team-1',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
logoUrl: 'https://example.com/logo.jpg',
|
|
memberCount: 100,
|
|
rating: 999999,
|
|
totalWins: 5000,
|
|
totalRaces: 10000,
|
|
performanceLevel: 'elite',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
],
|
|
recruitingCount: 0,
|
|
groupsBySkillLevel: '',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams[0].rating).toBe(999999);
|
|
expect(result.teams[0].totalWins).toBe(5000);
|
|
expect(result.teams[0].totalRaces).toBe(10000);
|
|
});
|
|
});
|
|
|
|
describe('edge cases', () => {
|
|
it('should handle null/undefined logo URLs', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{
|
|
id: 'team-1',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
logoUrl: null as any,
|
|
memberCount: 15,
|
|
totalWins: 50,
|
|
totalRaces: 200,
|
|
performanceLevel: 'elite',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
],
|
|
recruitingCount: 0,
|
|
groupsBySkillLevel: '',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams[0].logoUrl).toBe('');
|
|
});
|
|
|
|
it('should handle null/undefined rating', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{
|
|
id: 'team-1',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
memberCount: 15,
|
|
rating: null as any,
|
|
totalWins: 50,
|
|
totalRaces: 200,
|
|
performanceLevel: 'elite',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
],
|
|
recruitingCount: 0,
|
|
groupsBySkillLevel: '',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams[0].rating).toBe(0);
|
|
});
|
|
|
|
it('should handle null/undefined totalWins and totalRaces', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{
|
|
id: 'team-1',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
memberCount: 15,
|
|
totalWins: null as any,
|
|
totalRaces: null as any,
|
|
performanceLevel: 'elite',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
],
|
|
recruitingCount: 0,
|
|
groupsBySkillLevel: '',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams[0].totalWins).toBe(0);
|
|
expect(result.teams[0].totalRaces).toBe(0);
|
|
});
|
|
|
|
it('should handle empty performance level', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{
|
|
id: 'team-1',
|
|
name: 'Racing Team Alpha',
|
|
tag: 'RTA',
|
|
memberCount: 15,
|
|
totalWins: 50,
|
|
totalRaces: 200,
|
|
performanceLevel: '',
|
|
isRecruiting: false,
|
|
createdAt: '2023-01-01',
|
|
},
|
|
],
|
|
recruitingCount: 0,
|
|
groupsBySkillLevel: '',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams[0].performanceLevel).toBe('N/A');
|
|
});
|
|
|
|
it('should handle position 0', () => {
|
|
const teamDTO: GetTeamsLeaderboardOutputDTO = {
|
|
teams: [
|
|
{ id: 'team-1', name: 'Team 1', tag: 'T1', memberCount: 10, totalWins: 30, totalRaces: 150, performanceLevel: 'elite', isRecruiting: false, createdAt: '2023-01-01' },
|
|
],
|
|
recruitingCount: 0,
|
|
groupsBySkillLevel: '',
|
|
topTeams: [],
|
|
};
|
|
|
|
const result = TeamRankingsViewDataBuilder.build(teamDTO);
|
|
|
|
expect(result.teams[0].position).toBe(1);
|
|
});
|
|
});
|
|
});
|