Add experimental metrics insights, comparisons, and scope filters

This commit is contained in:
2026-09-27 22:34:56 -04:00
parent 3922e28ca8
commit eb2a852fdc
18 changed files with 992 additions and 61 deletions
+21 -1
View File
@@ -2,7 +2,14 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
import { createMetricsRefresh } from '../../src/lib/ui/metrics-refresh.js';
afterEach(() => vi.useRealTimers());
const report = (days: number) => ({ days, summary: {}, points: [], maps: [], servers: [] });
const totals = { observed: 0, active: 0, idle: 0, unknown: 0, playerHours: 0 };
const report = (days: number) => ({ days, now: 1000, since: 0, summary: totals, points: [], maps: [], servers: [],
scope: { game: null, map: null, timeZone: 'UTC' }, scopeOptions: { games: [], maps: [] },
registeredServerCount: 0, firstRetainedSampleAt: null, latestSampleAt: null, scopeFirstSampleAt: null, scopeLatestSampleAt: null,
previous: { since: -1000, until: 0, summary: totals, firstSampleAt: null, lastSampleAt: null, partialHistory: true },
heatmap: { timeZone: 'UTC', cells: [] },
pooledPressure: { value: null, fullMapHours: 0, knownMapHours: 0, coveredMaps: 0, totalMaps: 0 }
});
function setup(fetcher: typeof fetch) {
let query = 'days=7';
const onData = vi.fn(), onError = vi.fn(), onLoading = vi.fn();
@@ -41,6 +48,19 @@ describe('metrics background refresh', () => {
expect(refresh.onData).toHaveBeenLastCalledWith(report(1));
});
it('preserves the report when an HTTP success lacks the expanded report contract', async () => {
const fetcher = vi.fn().mockResolvedValueOnce(Response.json({ ...report(7), heatmap: null }))
.mockResolvedValueOnce(Response.json({ ...report(7), scope: { game: null, map: null, timeZone: 'Invalid/Zone' } }))
.mockResolvedValueOnce(Response.json(report(7)));
const refresh = setup(fetcher);
await refresh.refresh();
await refresh.refresh();
expect(refresh.onData).not.toHaveBeenCalled();
expect(refresh.onError).toHaveBeenLastCalledWith('The metrics response was incomplete.');
await refresh.refresh();
expect(refresh.onData).toHaveBeenCalledTimes(1);
});
it('suppresses errors from a cancelled request', async () => {
let reject!: (error: Error) => void;
const refresh = setup(vi.fn(() => new Promise<Response>((_, fail) => { reject = fail; })));