91 lines
3.3 KiB
JavaScript
91 lines
3.3 KiB
JavaScript
// 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);
|
|
});
|
|
});
|