Session 25: Fix all data rendering — proxy routes, Tank01 normalizer, box-score bridge, inline streaks (1579 tests)

This commit is contained in:
Kev
2026-06-12 17:58:55 -04:00
parent 433e827103
commit 956cdb863a
15 changed files with 602 additions and 39 deletions
+75
View File
@@ -58,3 +58,78 @@ describe('rosterLogs', () => {
expect(__internals.playerFromKey('gamelogs:nba:LeBron James:20', 'nba')).toBe('LeBron James');
});
});
// Session 25 — box-score aggregation bridge (prefetch key alignment).
describe('rosterLogs — Tank01 box-score aggregation', () => {
// Route scans by their MATCH pattern (3rd arg) so gamelogs + boxscore
// scans can return different key sets.
function routeScan(map) {
mockScan.mockImplementation(async (_cursor, _m, match) => ['0', map[match] || []]);
}
test('aggregates MLB box scores into per-player multi-game logs', async () => {
routeScan({
'gamelogs:mlb:*': [],
'tank01:mlb:boxscore:*': [
'tank01:mlb:boxscore:20260612_ARI@CIN',
'tank01:mlb:boxscore:20260611_ARI@LAD',
],
});
// Newer game (0612) and older game (0611) for the same batter.
store['tank01:mlb:boxscore:20260612_ARI@CIN'] = [
{ role: 'batter', name: 'Acuna', playerId: 'B1', team: 'ARI', _raw: { H: 2, HR: 1 }, _final: true },
];
store['tank01:mlb:boxscore:20260611_ARI@LAD'] = [
{ role: 'batter', name: 'Acuna', playerId: 'B1', team: 'ARI', _raw: { H: 1, HR: 0 }, _final: true },
];
const roster = await loadRosterLogs('mlb');
expect(roster).toHaveLength(1);
const acuna = roster[0];
expect(acuna.name).toBe('Acuna');
expect(acuna.team).toBe('ARI');
expect(acuna.games).toHaveLength(2);
// Most-recent first → the 2-hit game leads (flattened from _raw).
expect(acuna.games[0].H).toBe(2);
expect(acuna.games[1].H).toBe(1);
});
test('aggregated MLB logs feed the streaks engine (hit streak)', async () => {
routeScan({
'gamelogs:mlb:*': [],
'tank01:mlb:boxscore:*': ['tank01:mlb:boxscore:20260612_A@B', 'tank01:mlb:boxscore:20260611_A@B'],
});
store['tank01:mlb:boxscore:20260612_A@B'] = [{ role: 'batter', name: 'X', team: 'A', _raw: { H: 2 }, _final: true }];
store['tank01:mlb:boxscore:20260611_A@B'] = [{ role: 'batter', name: 'X', team: 'A', _raw: { H: 1 }, _final: true }];
const roster = await loadRosterLogs('mlb');
const { computeStreaks } = require('../../src/services/streaksService');
const streaks = computeStreaks(roster, 'mlb');
const hit = streaks.find((s) => s.type === 'hit_streak');
expect(hit).toBeDefined();
expect(hit.currentStreak).toBe(2);
});
test('NBA box-score rows are consumed without _raw flattening', async () => {
routeScan({
'gamelogs:nba:*': [],
'tank01:nba:boxscore:*': ['tank01:nba:boxscore:20260612_NYK@SA'],
});
store['tank01:nba:boxscore:20260612_NYK@SA'] = [
{ playerId: 'W1', name: 'Wemby', team: 'SA', pts: 30, reb: 12, ast: 3, threes: 2, blk: 4, stl: 1 },
];
const roster = await loadRosterLogs('nba');
expect(roster[0].games[0].pts).toBe(30);
});
test('gamelogs path still wins over box scores when present', async () => {
routeScan({ 'gamelogs:mlb:*': ['gamelogs:mlb:Star:20'] });
store['gamelogs:mlb:Star:20'] = [{ hits: 3 }, { hits: 2 }];
const roster = await loadRosterLogs('mlb');
expect(roster[0].name).toBe('Star');
expect(roster[0].games).toHaveLength(2);
});
test('boxScoreKeyDate extracts the date for recency ordering', () => {
expect(__internals.boxScoreKeyDate('tank01:mlb:boxscore:20260612_ARI@CIN')).toBe('20260612');
expect(__internals.boxScoreKeyDate('tank01:mlb:boxscore:weird')).toBe('0');
});
});