import { expect, it, vi } from 'vitest'; import { render } from 'svelte/server'; import { writable } from 'svelte/store'; import PlayerProfilePage from '../../src/routes/leaderboard/players/[guid]/+page.svelte'; import PlayerMapCards from '../../src/lib/ui/components/PlayerMapCards.svelte'; import type { PlayerMapRecord, PlayerProfile, RecordEvidence } from '../../src/lib/leaderboard.js'; vi.mock('$app/stores', () => ({ page: writable({ url: new URL('http://localhost/leaderboard/players/101?players=2'), data: { user: null } }) })); vi.mock('$app/navigation', () => ({ goto: vi.fn(), invalidateAll: vi.fn() })); const evidence: RecordEvidence = { matchId: 71, game: 't5', mapKey: 't5:theater', mapName: 'Kino Der Toten', server: 't5_zombie_theater_1', startedAt: '2026-10-06T12:00:00Z', endedAt: '2026-10-06T13:00:00Z', startObserved: true, presentAtStart: true, firstObservedRound: 0, value: 22 }; const stats = { highestRound: 22, bestKills: 507, bestScore: 5290, kills: 722, roundsSurvived: 41, headshots: 10, revives: 2, downs: 3, gamesPlayed: 9, gamesCompleted: 8 }; const map: PlayerMapRecord = { ...stats, game: 't5', key: 't5:theater', name: 'Kino Der Toten', lastSeen: evidence.endedAt!, ranks: { highestRound: 7, bestKills: 12, bestScore: 3 }, records: { highestRound: evidence, bestKills: { ...evidence, matchId: 72, value: 507 }, bestScore: { ...evidence, matchId: 73, value: 5290 } } }; function expectRankedRecords(body: string) { for (const [label, rank] of [ ['Best round', 7], ['Best kills', 12], ['Best score', 3] ]) { expect(body).toContain(`aria-label="Kino Der Toten ${label} rank ${rank}"`); expect(body).toContain(`Rank #${rank}`); } for (const id of [71, 72, 73]) expect(body).toContain(`/matches/${id}?returnTo=`); for (const value of ['22', '507', '5,290']) expect(body).toContain(`>${value}`); } it('shows each record rank and preserves match links in mobile map cards', () => { expectRankedRecords( render(PlayerMapCards, { props: { maps: [map], returnTo: '/leaderboard/players/101?players=2' } }).body ); }); it('shows the same ranks in the desktop profile with lifetime map scope explained', () => { const profile: PlayerProfile = { guid: '101', name: 'Cherry', firstSeen: evidence.startedAt, lastSeen: evidence.endedAt!, stats, records: map.records, maps: [map], matches: [], matchesTotal: 0, limit: 25, offset: 0 }; const body = render(PlayerProfilePage, { props: { data: { profile, returnTo: '/leaderboard', scope: { game: '', map: '', players: '2', metric: 'kills', entry: null } } } }).body; const table = body.slice(body.indexOf('')); expectRankedRecords(table); expect(body.replace(/\s+/g, ' ')).toContain( 'Lifetime personal bests across all squad sizes, ranked against other players on each map.' ); expect(body).toContain('Tied records share a rank.'); expect(body).not.toContain('No qualifying match history yet'); expect(body).toContain('Show all completed matches'); }); it('renders a known player without qualifying history with identity and unavailable personal bests', () => { const profile: PlayerProfile = { guid: '101', name: 'New player', firstSeen: evidence.startedAt, lastSeen: evidence.startedAt, stats: { highestRound: 0, bestKills: 0, bestScore: 0, kills: 0, roundsSurvived: 0, headshots: 0, revives: 0, downs: 0, gamesPlayed: 0, gamesCompleted: 0 }, records: null, maps: [], matches: [], matchesTotal: 0, limit: 25, offset: 0 }; const body = render(PlayerProfilePage, { props: { data: { profile, returnTo: '/leaderboard', scope: { game: '', map: '', players: '', metric: 'highestRound', entry: null } } } }).body; const text = body.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' '); expect(text).toContain('New player'); expect(text).toContain('No qualifying match history yet'); expect(text).toContain('Stats appear after a recorded game ends'); expect(text).toContain('observed at round 2 or later'); expect(text).toContain('Lifetime best round —'); expect(text).toContain('Best game kills —'); expect(text).toContain('Highest reported score —'); expect(text).toContain('Lifetime games played 0'); expect(text).toContain('No map records yet'); expect(text).toContain('No qualifying matches recorded'); expect(text).toContain('First seen'); expect(text).toContain('Last seen'); expect(body).toContain('Player GUID'); expect(body).not.toContain('/matches/'); expect(body).not.toContain('Show all completed matches'); expect(body).not.toContain('