98 lines
3.4 KiB
JavaScript
98 lines
3.4 KiB
JavaScript
const request = require('supertest');
|
|
|
|
const mockGetOdds = jest.fn();
|
|
jest.mock('../../src/services/oddsService', () => {
|
|
const actual = jest.requireActual('../../src/services/oddsService');
|
|
return {
|
|
...actual,
|
|
getOdds: (...args) => mockGetOdds(...args),
|
|
};
|
|
});
|
|
|
|
const mockRedis = { get: jest.fn(), set: jest.fn(), hset: jest.fn(), hgetall: jest.fn(), expire: jest.fn() };
|
|
jest.mock('../../src/utils/redis', () => ({
|
|
getRedisClient: () => mockRedis,
|
|
cacheGet: async () => null,
|
|
cacheSet: async () => true,
|
|
cacheDel: async () => true,
|
|
isDegraded: () => false,
|
|
}));
|
|
|
|
const { SOCCER_SPORT_KEYS } = require('../../src/services/oddsService');
|
|
const app = require('../../src/app');
|
|
|
|
beforeEach(() => {
|
|
mockGetOdds.mockReset();
|
|
mockRedis.get.mockResolvedValue(null);
|
|
});
|
|
|
|
describe('SOCCER_SPORT_KEYS export', () => {
|
|
test('contains all 9 launch leagues', () => {
|
|
expect(SOCCER_SPORT_KEYS).toEqual(expect.arrayContaining([
|
|
'soccer_wc',
|
|
'soccer_epl',
|
|
'soccer_laliga',
|
|
'soccer_bundesliga',
|
|
'soccer_seriea',
|
|
'soccer_ligue1',
|
|
'soccer_ucl',
|
|
'soccer_mls',
|
|
'soccer_ligamx',
|
|
]));
|
|
expect(SOCCER_SPORT_KEYS).toHaveLength(9);
|
|
});
|
|
});
|
|
|
|
describe('GET /api/odds/soccer/:league', () => {
|
|
test('valid league reaches getOdds with the prefixed key', async () => {
|
|
mockGetOdds.mockResolvedValueOnce({
|
|
props: [], updated_at: '2026-06-15T00:00:00Z', source: 'live', quota_remaining: 4000,
|
|
});
|
|
const res = await request(app).get('/api/odds/soccer/wc').expect(200);
|
|
expect(mockGetOdds).toHaveBeenCalledWith('soccer_wc');
|
|
expect(res.body.sport).toBe('soccer_wc');
|
|
expect(Array.isArray(res.body.props)).toBe(true);
|
|
});
|
|
|
|
test('unknown league returns 400 with valid-list hint', async () => {
|
|
const res = await request(app).get('/api/odds/soccer/spaceleague').expect(400);
|
|
expect(res.body.error).toMatch(/Unknown soccer league/);
|
|
expect(res.body.error).toMatch(/wc/);
|
|
expect(mockGetOdds).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('EPL route works (proves it is not WC-only)', async () => {
|
|
mockGetOdds.mockResolvedValueOnce({
|
|
props: [{ player: 'X', stat_type: 'goals', line: 0.5 }], updated_at: '2026-06-15T00:00:00Z', source: 'cache',
|
|
});
|
|
const res = await request(app).get('/api/odds/soccer/epl').expect(200);
|
|
expect(mockGetOdds).toHaveBeenCalledWith('soccer_epl');
|
|
expect(res.body.sport).toBe('soccer_epl');
|
|
});
|
|
|
|
test('case-insensitive league path', async () => {
|
|
mockGetOdds.mockResolvedValueOnce({ props: [], updated_at: 't', source: 'cache' });
|
|
await request(app).get('/api/odds/soccer/LIGAMX').expect(200);
|
|
expect(mockGetOdds).toHaveBeenCalledWith('soccer_ligamx');
|
|
});
|
|
|
|
test('getOdds throwing surfaces as a status code, not a 500 leak', async () => {
|
|
const err = new Error('Odds data temporarily unavailable.');
|
|
err.statusCode = 429;
|
|
mockGetOdds.mockRejectedValueOnce(err);
|
|
const res = await request(app).get('/api/odds/soccer/wc').expect(429);
|
|
expect(res.body.error).toMatch(/temporarily unavailable/);
|
|
});
|
|
});
|
|
|
|
describe('existing NBA/NCAAB routes still work (no regression)', () => {
|
|
test('/api/odds/nba still returns the NBA shape', async () => {
|
|
mockGetOdds.mockResolvedValueOnce({
|
|
props: [], updated_at: 't', source: 'cache', quota_remaining: 4000,
|
|
});
|
|
const res = await request(app).get('/api/odds/nba').expect(200);
|
|
expect(res.body.sport).toBe('nba');
|
|
expect(mockGetOdds).toHaveBeenCalledWith('nba');
|
|
});
|
|
});
|