feat: Scoreboard: Ranking, Matrix, Event Log and Score Graph 1.00
This commit is contained in:
@@ -46,6 +46,8 @@ describe('parseSolveEventIntoRanking', () => {
|
||||
];
|
||||
const next = parseSolveEventIntoRanking(rows, {
|
||||
challengeId: 'c1',
|
||||
challengeName: 'alpha',
|
||||
categoryAbbreviation: 'CRY',
|
||||
playerId: 'p2',
|
||||
playerName: 'p2',
|
||||
awardedPoints: 50,
|
||||
@@ -90,7 +92,7 @@ describe('applySolveToGraph', () => {
|
||||
};
|
||||
const next = applySolveToGraph(
|
||||
baseView,
|
||||
{ challengeId: 'c1', playerId: 'p0', playerName: 'p0', awardedPoints: 30, rankBonus: 0, awardedAtUtc: '2025-01-01T06:00:00.000Z', position: 2 },
|
||||
{ challengeId: 'c1', challengeName: 'alpha', categoryAbbreviation: 'CRY', playerId: 'p0', playerName: 'p0', awardedPoints: 30, rankBonus: 0, awardedAtUtc: '2025-01-01T06:00:00.000Z', position: 2 },
|
||||
'2025-01-01T00:00:00.000Z',
|
||||
'2025-01-02T00:00:00.000Z',
|
||||
'2025-01-01T12:00:00.000Z',
|
||||
@@ -105,7 +107,7 @@ describe('applySolveToGraph', () => {
|
||||
it('returns empty when event is not configured', () => {
|
||||
const next = applySolveToGraph(
|
||||
null,
|
||||
{ challengeId: 'c1', playerId: 'p0', playerName: 'p0', awardedPoints: 30, rankBonus: 0, awardedAtUtc: '2025-01-01T06:00:00.000Z', position: 1 },
|
||||
{ challengeId: 'c1', challengeName: 'alpha', categoryAbbreviation: 'CRY', playerId: 'p0', playerName: 'p0', awardedPoints: 30, rankBonus: 0, awardedAtUtc: '2025-01-01T06:00:00.000Z', position: 1 },
|
||||
null,
|
||||
null,
|
||||
'2025-01-01T12:00:00.000Z',
|
||||
@@ -123,6 +125,8 @@ describe('mutateMatrixFromSolve', () => {
|
||||
};
|
||||
const next = mutateMatrixFromSolve(matrix, {
|
||||
challengeId: 'c1',
|
||||
challengeName: 'alpha',
|
||||
categoryAbbreviation: 'CRY',
|
||||
playerId: 'p2',
|
||||
playerName: 'p2',
|
||||
awardedPoints: 50,
|
||||
|
||||
@@ -133,6 +133,41 @@ describe('ScoreboardStore', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('propagates challenge name and category abbreviation from SSE solve frame to the Event Log row', () => {
|
||||
const api = new FakeApi();
|
||||
const destroyRef: any = { onDestroy: () => {} };
|
||||
const store = new ScoreboardStore(api as any, destroyRef);
|
||||
void store.loadAll();
|
||||
return new Promise<void>((resolve) => {
|
||||
const source = makeFakeSse((type, fn) => {
|
||||
if (type === 'solve') {
|
||||
setTimeout(() => {
|
||||
fn(new MessageEvent('solve', { data: JSON.stringify({
|
||||
challenge_id: 'c2',
|
||||
challenge_name: 'Hardware Hello',
|
||||
category_abbreviation: 'HW',
|
||||
player_id: 'p3',
|
||||
player_name: 'PlayerC',
|
||||
awarded_points: 115,
|
||||
rank_bonus: 15,
|
||||
awarded_at_utc: '2026-07-23T05:25:37.309Z',
|
||||
position: 1,
|
||||
}) }));
|
||||
setTimeout(() => {
|
||||
const top = store.eventLog()?.[0];
|
||||
expect(top?.challengeName).toBe('Hardware Hello');
|
||||
expect(top?.categoryAbbreviation).toBe('HW');
|
||||
expect(top?.playerName).toBe('PlayerC');
|
||||
expect(top?.awardedPoints).toBe(115);
|
||||
resolve();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
store.wireSse(() => source);
|
||||
});
|
||||
});
|
||||
|
||||
it('reset clears all signals and stops SSE', () => {
|
||||
const api = new FakeApi();
|
||||
const destroyRef: any = { onDestroy: () => {} };
|
||||
|
||||
Reference in New Issue
Block a user