process.env.PARLAYAPI_KEY = 'test-key'; process.env.PARLAYAPI_BASE_URL = 'https://api.parlayapi.test/v1'; const mockAxiosGet = jest.fn(); jest.mock('axios', () => ({ get: (...args) => mockAxiosGet(...args) })); const mockCache = { current: new Map() }; jest.mock('../../src/utils/redis', () => ({ cacheGet: async (k) => mockCache.current.get(k) ?? null, cacheSet: async (k, v) => { mockCache.current.set(k, v); return true; }, cacheDel: async (k) => { mockCache.current.delete(k); return true; }, })); const adapter = require('../../src/services/adapters/parlayApiAdapter'); beforeEach(() => { mockAxiosGet.mockReset(); mockCache.current.clear(); }); describe('parlayApiAdapter.configured', () => { test('reflects PARLAYAPI_KEY presence', () => { expect(adapter.configured()).toBe(true); delete process.env.PARLAYAPI_KEY; expect(adapter.configured()).toBe(false); process.env.PARLAYAPI_KEY = 'test-key'; }); }); describe('parlayApiAdapter.getHistoricalProps', () => { test('throws on unsupported sport', async () => { await expect(adapter.getHistoricalProps('curling', 'X', 'points', 10)).rejects.toThrow(/Unsupported sport/); }); test('normalizes API response into stable shape', async () => { mockAxiosGet.mockResolvedValue({ status: 200, data: { props: [ { player: 'Jalen Brunson', stat_type: 'points', line: 26.5, closing_line: 27.0, result: 'over', game_date: '2026-04-15' }, ], }, }); const result = await adapter.getHistoricalProps('nba', 'Jalen Brunson', 'points', 10); expect(result).toHaveLength(1); expect(result[0]).toMatchObject({ sport: 'nba', player_name: 'Jalen Brunson', stat_type: 'points', line: 26.5, closing_line: 27.0, result: 'over', source: 'parlayapi', }); }); test('cache hit on second call', async () => { mockAxiosGet.mockResolvedValue({ status: 200, data: { props: [] } }); await adapter.getHistoricalProps('nba', 'P', 'points', 10); await adapter.getHistoricalProps('nba', 'P', 'points', 10); expect(mockAxiosGet).toHaveBeenCalledTimes(1); }); test('returns [] when unconfigured', async () => { delete process.env.PARLAYAPI_KEY; expect(await adapter.getHistoricalProps('nba', 'P', 'points', 10)).toEqual([]); process.env.PARLAYAPI_KEY = 'test-key'; }); }); describe('parlayApiAdapter.getClosingLines', () => { test('returns array from response.lines', async () => { mockAxiosGet.mockResolvedValue({ status: 200, data: { lines: [{ player: 'A', line: 10 }, { player: 'B', line: 15 }] }, }); const lines = await adapter.getClosingLines('nba', '2026-04-15'); expect(lines).toHaveLength(2); }); });