Session 23: All-day intelligence layer — schedule, game lines, streaks, hot lists, stat filtering, ParlayAPI dead (1567 tests)
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
// Integration: /api/streaks/:sport and /api/hotlist/:sport (Session 23).
|
||||
// rosterLogs is mocked so we exercise route → engine without Redis.
|
||||
|
||||
const express = require('express');
|
||||
const request = require('supertest');
|
||||
|
||||
jest.mock('../../src/services/rosterLogs', () => ({
|
||||
loadRosterLogs: jest.fn(),
|
||||
}));
|
||||
const { loadRosterLogs } = require('../../src/services/rosterLogs');
|
||||
|
||||
function mountStreaks() {
|
||||
delete require.cache[require.resolve('../../src/routes/streaks')];
|
||||
const app = express();
|
||||
app.use('/api/streaks', require('../../src/routes/streaks'));
|
||||
return app;
|
||||
}
|
||||
function mountHotlist() {
|
||||
delete require.cache[require.resolve('../../src/routes/hotlist')];
|
||||
const app = express();
|
||||
app.use('/api/hotlist', require('../../src/routes/hotlist'));
|
||||
return app;
|
||||
}
|
||||
|
||||
beforeEach(() => jest.clearAllMocks());
|
||||
|
||||
describe('GET /api/streaks/:sport', () => {
|
||||
test('returns computed streaks from cached logs', async () => {
|
||||
loadRosterLogs.mockResolvedValue([
|
||||
{ name: 'Wemby', team: 'SA', games: [{ points: 30 }, { points: 28 }, { points: 26 }] },
|
||||
]);
|
||||
const res = await request(mountStreaks()).get('/api/streaks/nba');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.source).toBe('computed');
|
||||
expect(res.body.streaks[0].player).toBe('Wemby');
|
||||
expect(res.body.streaks[0].currentStreak).toBe(3);
|
||||
});
|
||||
|
||||
test('stat filter narrows the response', async () => {
|
||||
loadRosterLogs.mockResolvedValue([
|
||||
{ name: 'A', games: [{ points: 30 }, { points: 30 }] },
|
||||
{ name: 'B', games: [{ assists: 9 }, { assists: 8 }] },
|
||||
]);
|
||||
const res = await request(mountStreaks()).get('/api/streaks/nba?stat=points');
|
||||
expect(res.body.stat).toBe('points');
|
||||
expect(res.body.streaks.every((s) => s.category === 'points')).toBe(true);
|
||||
});
|
||||
|
||||
test('empty roster → empty streaks, not an error', async () => {
|
||||
loadRosterLogs.mockResolvedValue([]);
|
||||
const res = await request(mountStreaks()).get('/api/streaks/mlb');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.streaks).toEqual([]);
|
||||
});
|
||||
|
||||
test('loader throwing → 200 with empty streaks (platform never down)', async () => {
|
||||
loadRosterLogs.mockRejectedValue(new Error('redis exploded'));
|
||||
const res = await request(mountStreaks()).get('/api/streaks/nba');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.streaks).toEqual([]);
|
||||
});
|
||||
|
||||
test('unsupported sport → 404', async () => {
|
||||
const res = await request(mountStreaks()).get('/api/streaks/cricket');
|
||||
expect(res.status).toBe(404);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/hotlist/:sport', () => {
|
||||
test('returns ranked hot players', async () => {
|
||||
loadRosterLogs.mockResolvedValue([
|
||||
{ name: 'Riser', seasonAvg: { points: 18 }, games: [{ points: 28 }, { points: 30 }] },
|
||||
]);
|
||||
const res = await request(mountHotlist()).get('/api/hotlist/nba?stat=points');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.players[0].name).toBe('Riser');
|
||||
expect(res.body.players[0].rank).toBe(1);
|
||||
});
|
||||
|
||||
test('empty roster → empty players', async () => {
|
||||
loadRosterLogs.mockResolvedValue([]);
|
||||
const res = await request(mountHotlist()).get('/api/hotlist/mlb');
|
||||
expect(res.body.players).toEqual([]);
|
||||
});
|
||||
|
||||
test('unsupported sport → 404', async () => {
|
||||
const res = await request(mountHotlist()).get('/api/hotlist/nfl');
|
||||
expect(res.status).toBe(404);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user