Focus player records and add squad leaderboards

This commit is contained in:
2026-10-07 19:14:33 -04:00
parent bab78038dc
commit bcecc42dd1
22 changed files with 569 additions and 430 deletions
+29 -6
View File
@@ -17,14 +17,16 @@ function scope(search = '') {
(page as unknown as Writable<{ url: URL }>).set({ url: new URL(`http://localhost/leaderboard${search}`) });
}
function html(data = report()) { return render(Leaderboard, { props: { data: { leaderboard: data, user: null, setupRequired: false } } }).body; }
beforeEach(() => scope());
beforeEach(() => scope('?map='));
it('shows prominent totals and restored stat columns, preserving ranks and collapsed identity and evidence', () => {
it('shows compact totals and core stat columns, preserving ranks without repeated row disclosures', () => {
const body = html();
const headers = body.slice(body.indexOf('<thead'), body.indexOf('</thead>'));
expect(headers.match(/scope="col"/g)).toHaveLength(9);
expect(headers.match(/scope="col"/g)).toHaveLength(6);
expect(headers).toContain('Highest round'); expect(headers).toContain('Total kills'); expect(headers).toContain('Games played');
for (const label of ['Total rounds', 'Headshots', 'Revives', 'Downs']) expect(headers).toContain(label);
expect(headers).toContain('Total rounds');
for (const label of ['Headshots', 'Revives', 'Downs', 'Games completed', 'Best game kills', 'Highest reported score']) expect(body).toContain(label);
expect(body).toContain('Show all stats');
expect(body).toMatch(/<span[^>]*>27<\/span>/);
expect(body).toContain('26–26 of 60 players');
const overview = body.slice(body.indexOf('class="overview'), body.indexOf('class="rankings'));
@@ -34,7 +36,12 @@ it('shows prominent totals and restored stat columns, preserving ranks and colla
expect(overview).not.toContain('<details');
expect(body).not.toMatch(/<details[^>]*open/);
expect(body).not.toContain('Copy GUID'); expect(body).not.toContain('Every round counts');
expect(body).toContain('Record details'); expect(body).toContain('First observed at round 8');
expect(body).not.toContain('Record details'); expect(body).not.toContain('Hide details');
const rows = body.slice(body.indexOf('<tbody'), body.indexOf('</tbody>'));
expect(rows.match(/<a\b/g)).toHaveLength(2);
expect(rows).not.toContain('<details');
expect(rows).toContain('Match #71');
expect(body).toContain('including players who joined mid-game');
expect(body).not.toContain('>Search</button>');
});
@@ -43,7 +50,7 @@ it('deduplicates the selected metric and preserves scope and pagination on playe
const data = report(); data.metric = 'kills';
const body = html(data);
const headers = body.slice(body.indexOf('<thead'), body.indexOf('</thead>'));
expect(headers.match(/scope="col"/g)).toHaveLength(8);
expect(headers.match(/scope="col"/g)).toHaveLength(5);
expect(body).toContain('offset%3D25'); expect(body).toContain('q%3DCherry');
scope('?game=t5&map=t5%3Atheater&metric=highestRound&q=Cherry&offset=25');
const recordBody = html();
@@ -52,6 +59,22 @@ it('deduplicates the selected metric and preserves scope and pagination on playe
expect(recordBody).toContain('Selection record'); expect(recordBody).not.toContain('Fleet record');
});
it('provides separate mobile filter controls and preserves explicit all-map and squad context', () => {
scope('?map=&players=2&metric=highestRound&offset=25');
const body = html();
expect(body).toContain('Leaderboard filters');
expect(body).toContain('id="leaderboard-players-mobile"');
expect(body).toContain('value="2" selected=""');
expect(body).toContain('All squad sizes');
expect(body).toContain('Solo'); expect(body).toContain('Duo'); expect(body).toContain('Trio'); expect(body).toContain('Four players');
expect(body).toContain('unknown starting counts appear only under All squad sizes');
expect(body).toContain('players%3D2');
expect(body).toContain('map%3D');
const ids = [...body.matchAll(/\bid="([^"]+)"/g)].map(match => match[1]);
expect(new Set(ids).size).toBe(ids.length);
expect(body).not.toMatch(/>Refresh<\/span>/);
});
it('keeps qualification and denominator visible for efficiency rankings and missing values distinct', () => {
scope('?metric=headshotRate');
const data = report(); data.metric = 'headshotRate';