// Session 46 — Phase 3: MLB starting pitchers. const fs = require('fs'); const path = require('path'); const WEB = path.join(__dirname, '..', '..', 'web', 'src'); const svc = require('../../src/services/probablePitchers'); const slate = require('../../web/src/lib/slateAdapter'); const scheduleGames = [ { home: { team: 'Philadelphia Phillies', probablePitcher: { id: 1, name: 'Zack Wheeler' } }, away: { team: 'Atlanta Braves', probablePitcher: { id: 2, name: 'Spencer Strider' } } }, { home: { team: 'New York Yankees', probablePitcher: null }, away: { team: 'Boston Red Sox', probablePitcher: { id: 3, name: 'Brayan Bello' } } }, ]; describe('shapePitcherGames', () => { it('extracts pitcher names + team, drops games with no probables', () => { const shaped = svc.shapePitcherGames(scheduleGames); expect(shaped).toHaveLength(2); expect(shaped[0].away.pitcher).toBe('Spencer Strider'); expect(shaped[0].home.pitcher).toBe('Zack Wheeler'); expect(svc.shapePitcherGames([{ home: {}, away: {} }])).toHaveLength(0); }); }); describe('getProbablePitchers (injected adapter)', () => { it('returns shaped games with best-effort ERA', async () => { const games = await svc.getProbablePitchers('2026-06-18', { mlbAdapter: { getScheduleWithPitchers: async () => scheduleGames }, eraLookup: async (id) => (id === 1 ? 2.89 : id === 2 ? 3.21 : null), }); const phi = games[0]; expect(phi.home.era).toBe(2.89); expect(phi.away.era).toBe(3.21); }); it('degrades to [] when the adapter throws', async () => { const games = await svc.getProbablePitchers('x', { mlbAdapter: { getScheduleWithPitchers: async () => { throw new Error('down'); } } }); expect(games).toEqual([]); }); }); describe('slateAdapter pitcher mapping', () => { const shaped = svc.shapePitcherGames(scheduleGames).map((g) => ({ home: { ...g.home, era: 2.89 }, away: { ...g.away, era: 3.21 }, })); it('builds a team→pitcher map and resolves a game by team name', () => { const map = slate.buildPitcherMap(shaped); const p = slate.pitchersForGameTeams('Atlanta Braves', 'Philadelphia Phillies', map); expect(p.away.name).toBe('Spencer Strider'); expect(p.away.era).toBe('3.21'); expect(p.home.name).toBe('Zack Wheeler'); }); it('matches by mascot when the full name differs slightly', () => { const map = slate.buildPitcherMap(shaped); const p = slate.pitchersForGameTeams('Braves', 'Phillies', map); expect(p.away.name).toBe('Spencer Strider'); }); it('returns undefined when no pitchers match', () => { expect(slate.pitchersForGameTeams('Dodgers', 'Giants', slate.buildPitcherMap(shaped))).toBeUndefined(); }); }); describe('Slate wires MLB pitchers', () => { const src = fs.readFileSync(path.join(WEB, 'components', 'Slate.tsx'), 'utf8'); it('fetches /api/schedule/mlb/pitchers and attaches pitchers for MLB', () => { expect(src).toContain('/api/schedule/mlb/pitchers'); expect(src).toContain('buildPitcherMap'); expect(src).toContain('pitchersForGameTeams'); }); });