This commit is contained in:
@@ -28,6 +28,27 @@ beforeEach(async () => {
|
||||
});
|
||||
afterEach(async () => fixture.cleanup());
|
||||
|
||||
const emptyProfile = {
|
||||
stats: {
|
||||
highestRound: 0,
|
||||
kills: 0,
|
||||
roundsSurvived: 0,
|
||||
headshots: 0,
|
||||
revives: 0,
|
||||
downs: 0,
|
||||
gamesPlayed: 0,
|
||||
gamesCompleted: 0,
|
||||
bestKills: 0,
|
||||
bestScore: 0
|
||||
},
|
||||
records: null,
|
||||
maps: [],
|
||||
matches: [],
|
||||
matchesTotal: 0,
|
||||
offset: 0,
|
||||
limit: 25
|
||||
};
|
||||
|
||||
async function report(
|
||||
event: GameEvent['event'],
|
||||
round = 0,
|
||||
@@ -94,6 +115,54 @@ it('keeps report revisions stable during a match and invalidates completed data
|
||||
expect(revision()).toBeGreaterThan(reopened);
|
||||
});
|
||||
|
||||
it.each([
|
||||
['t5', server, 'zombie_theater'],
|
||||
['t6', 't6_zombie_town_1', 'zm_transit']
|
||||
])(
|
||||
'loads a known %s player before qualification and refreshes cached profiles after game end',
|
||||
async (game, source, map) => {
|
||||
const { load } =
|
||||
await import('../../src/routes/leaderboard/players/[guid]/+page.server.js');
|
||||
const request = {
|
||||
params: { guid: player().guid },
|
||||
url: new URL(
|
||||
`http://localhost/leaderboard/players/${player().guid}?game=${game}&offset=999`
|
||||
)
|
||||
};
|
||||
const send = (event: GameEvent['event'], round = 0) =>
|
||||
report(event, round, [player(undefined, { kills: 20 })], source, map);
|
||||
|
||||
await expect(load(request)).rejects.toMatchObject({ status: 404 });
|
||||
await send('game_start');
|
||||
const started = await load(request);
|
||||
expect(started).toMatchObject({
|
||||
profile: { ...emptyProfile, guid: player().guid, name: player().name },
|
||||
scope: { entry: null }
|
||||
});
|
||||
expect(started.profile.firstSeen).toBe('2026-09-18T20:00:00.000Z');
|
||||
expect(started.profile.lastSeen).toBe(started.profile.firstSeen);
|
||||
await send('game_end', 1);
|
||||
expect((await load(request)).profile).toMatchObject(emptyProfile);
|
||||
await send('game_start');
|
||||
await send('heartbeat', 2);
|
||||
expect((await load(request)).profile).toMatchObject(emptyProfile);
|
||||
await send('game_end', 2);
|
||||
const completed = await load(request);
|
||||
expect(completed).toMatchObject({
|
||||
profile: {
|
||||
stats: { highestRound: 2, kills: 20, gamesPlayed: 1 },
|
||||
records: { highestRound: { value: 2 } },
|
||||
matchesTotal: 1,
|
||||
offset: 0
|
||||
},
|
||||
scope: { entry: { rank: 1, kills: 20 } }
|
||||
});
|
||||
await send('game_start');
|
||||
await send('heartbeat', 10);
|
||||
expect((await load(request)).profile.stats).toEqual(completed.profile.stats);
|
||||
}
|
||||
);
|
||||
|
||||
it('publishes round 2 or higher games only after game end, preserving early stats and excluding round 1 departures', async () => {
|
||||
const { getLeaderboard } = await import('../../src/lib/server/fleet/leaderboard.js');
|
||||
const { getPlayerProfile } = await import('../../src/lib/server/fleet/player-profile.js');
|
||||
@@ -107,7 +176,7 @@ it('publishes round 2 or higher games only after game end, preserving early stat
|
||||
total: 0,
|
||||
summary: { players: 0, matches: 0, kills: 0 }
|
||||
});
|
||||
expect(getPlayerProfile(player().guid)).toBeNull();
|
||||
expect(getPlayerProfile(player().guid)).toMatchObject(emptyProfile);
|
||||
expect(serverMatchHistory()).toEqual({ total: 0, matches: [], maps: [], page: 1, limit: 25 });
|
||||
await report('round_change', 2, [player(undefined, { kills: 6, score: 500 })]);
|
||||
expect(getLeaderboard()).toMatchObject({
|
||||
@@ -116,9 +185,9 @@ it('publishes round 2 or higher games only after game end, preserving early stat
|
||||
total: 0,
|
||||
summary: { players: 0, matches: 0, kills: 0 }
|
||||
});
|
||||
expect(getPlayerProfile(player().guid)).toBeNull();
|
||||
expect(getPlayerProfile(player().guid)).toMatchObject(emptyProfile);
|
||||
expect(serverMatchHistory()).toMatchObject({ total: 1, matches: [{ status: 'active' }] });
|
||||
expect(getPlayerProfile(departed.guid)).toBeNull();
|
||||
expect(getPlayerProfile(departed.guid)).toMatchObject(emptyProfile);
|
||||
await report('game_end', 2, [player(undefined, { kills: 10 })]);
|
||||
const board = getLeaderboard();
|
||||
const profile = getPlayerProfile(player().guid);
|
||||
@@ -137,7 +206,7 @@ it('publishes round 2 or higher games only after game end, preserving early stat
|
||||
],
|
||||
summary: { players: 1, matches: 1, kills: 10 }
|
||||
});
|
||||
expect(getPlayerProfile(departed.guid)).toBeNull();
|
||||
expect(getPlayerProfile(departed.guid)).toMatchObject(emptyProfile);
|
||||
expect(history).toMatchObject({
|
||||
total: 1,
|
||||
matches: [{ startPlayers: 2, uniquePlayers: 2, durationMs: 3000, finalRound: 2 }]
|
||||
@@ -478,7 +547,7 @@ it('keeps disconnected player records while completing only the final roster', a
|
||||
await report('game_start', 0, [player(), other]);
|
||||
await report('round_change', 4, [player(undefined, { kills: 80 }), other]);
|
||||
expect(getLeaderboard()).toMatchObject({ entries: [], total: 0 });
|
||||
expect(getPlayerProfile(other.guid)).toBeNull();
|
||||
expect(getPlayerProfile(other.guid)).toMatchObject(emptyProfile);
|
||||
await report('game_end', 5, [player(undefined, { kills: 100 })]);
|
||||
expect(await records(other.guid)).toEqual([
|
||||
expect.objectContaining({ kills: 40, highest_round: 4, rounds_survived: 3, completed: 0 })
|
||||
@@ -682,7 +751,7 @@ it('keeps deleted match identities and starts a separate match when the server n
|
||||
server_deleted_at: null,
|
||||
status: 'active'
|
||||
});
|
||||
expect(getPlayerProfile(player().guid)).toBeNull();
|
||||
expect(getPlayerProfile(player().guid)).toMatchObject(emptyProfile);
|
||||
await report('game_end', 8, [player(undefined, { kills: 120 })]);
|
||||
const profile = getPlayerProfile(player().guid)!;
|
||||
expect(profile.stats).toMatchObject({ gamesPlayed: 1, kills: 120 });
|
||||
|
||||
Reference in New Issue
Block a user