// Session 41 — MLB stat_type acceptance. The Scan frontend sends MLB IDs // (hits, strikeouts, total_bases, rbi, home_runs, earned_runs, hits_allowed, // innings_pitched) but the /api/analyze validation gate only whitelisted the // NBA/soccer set, so every MLB scan 400'd. This file lives apart from // analyze.test.js because that suite sits exactly at the 10/min IP rate-limit // boundary; a separate file gets a fresh limiter (jest isolates module state // per file) so we can exercise all eight MLB stats under the cap. const request = require('supertest'); 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 mockAnalyzeViaEngine1 = jest.fn(); jest.mock('../../src/services/intelligence/analyzeViaEngine1', () => ({ analyzeViaEngine1: (...args) => mockAnalyzeViaEngine1(...args), })); jest.mock('../../src/utils/tierGating', () => ({ applyTierGating: (result) => result })); const { __internals: scanLimitInternals } = require('../../src/middleware/scanLimit'); const app = require('../../src/app'); const MLB_STATS = ['hits', 'strikeouts', 'total_bases', 'rbi', 'home_runs', 'earned_runs', 'hits_allowed', 'innings_pitched']; beforeEach(() => { jest.clearAllMocks(); mockRedis.get.mockResolvedValue(null); mockRedis.set.mockResolvedValue('OK'); mockAnalyzeViaEngine1.mockReset(); if (scanLimitInternals && scanLimitInternals.resetForTests) scanLimitInternals.resetForTests(); }); describe('POST /api/analyze/prop — MLB stat_types', () => { it.each(MLB_STATS)('accepts %s (no longer 400s at the validation gate)', async (stat) => { mockAnalyzeViaEngine1.mockResolvedValueOnce({ player: 'Aaron Judge', stat_type: stat, line: 1.5, direction: 'over', grade: 'B', confidence: 70, kill_conditions_triggered: [], reasoning: { summary: 'ok', steps: [] }, }); const res = await request(app) .post('/api/analyze/prop') .send({ player: 'Aaron Judge', sport: 'mlb', stat_type: stat, line: 1.5, direction: 'over' }); expect(res.status).toBe(200); expect(res.body.error).toBeUndefined(); expect(mockAnalyzeViaEngine1).toHaveBeenCalled(); }); it('still rejects a genuinely invalid stat_type', async () => { const res = await request(app) .post('/api/analyze/prop') .send({ player: 'Aaron Judge', sport: 'mlb', stat_type: 'vibes', line: 1.5, direction: 'over' }); expect(res.status).toBe(400); expect(res.body.error).toContain('Invalid stat_type'); }); });