import { describe, it, expect, beforeEach } from 'vitest' import { useDefensiveSetup } from '~/composables/useDefensiveSetup' describe('useDefensiveSetup', () => { beforeEach(() => { const { reset } = useDefensiveSetup() reset() }) describe('singleton behavior', () => { it('returns the same state across multiple calls', () => { /** * The composable is a module-level singleton — multiple calls to * useDefensiveSetup() should return refs pointing to the same state. */ const a = useDefensiveSetup() const b = useDefensiveSetup() a.toggleHold(1) expect(b.isHeld(1)).toBe(true) expect(b.holdRunnersArray.value).toEqual([1]) }) }) describe('toggleHold', () => { it('adds a base when not held', () => { const { toggleHold, isHeld } = useDefensiveSetup() toggleHold(1) expect(isHeld(1)).toBe(true) }) it('removes a base when already held', () => { const { toggleHold, isHeld } = useDefensiveSetup() toggleHold(2) expect(isHeld(2)).toBe(true) toggleHold(2) expect(isHeld(2)).toBe(false) }) it('can hold multiple bases independently', () => { const { toggleHold, isHeld, holdRunnersArray } = useDefensiveSetup() toggleHold(1) toggleHold(3) expect(isHeld(1)).toBe(true) expect(isHeld(2)).toBe(false) expect(isHeld(3)).toBe(true) expect(holdRunnersArray.value).toEqual([1, 3]) }) }) describe('holdRunnersArray', () => { it('returns sorted array of held base numbers', () => { /** * holdRunnersArray should always be sorted so the output is * deterministic regardless of toggle order. */ const { toggleHold, holdRunnersArray } = useDefensiveSetup() toggleHold(3) toggleHold(1) expect(holdRunnersArray.value).toEqual([1, 3]) }) it('returns empty array when nothing is held', () => { const { holdRunnersArray } = useDefensiveSetup() expect(holdRunnersArray.value).toEqual([]) }) }) describe('reset', () => { it('clears all hold state and resets depths to defaults', () => { const { toggleHold, infieldDepth, outfieldDepth, holdRunnersArray, reset } = useDefensiveSetup() toggleHold(1) toggleHold(2) infieldDepth.value = 'infield_in' outfieldDepth.value = 'shallow' reset() expect(holdRunnersArray.value).toEqual([]) expect(infieldDepth.value).toBe('normal') expect(outfieldDepth.value).toBe('normal') }) }) describe('syncFromDecision', () => { it('sets all state from a DefensiveDecision object', () => { const { syncFromDecision, infieldDepth, outfieldDepth, holdRunnersArray } = useDefensiveSetup() syncFromDecision({ infield_depth: 'corners_in', outfield_depth: 'shallow', hold_runners: [1, 3], }) expect(infieldDepth.value).toBe('corners_in') expect(outfieldDepth.value).toBe('shallow') expect(holdRunnersArray.value).toEqual([1, 3]) }) it('clears previously held runners not in new decision', () => { const { toggleHold, syncFromDecision, isHeld } = useDefensiveSetup() toggleHold(1) toggleHold(2) toggleHold(3) syncFromDecision({ infield_depth: 'normal', outfield_depth: 'normal', hold_runners: [2], }) expect(isHeld(1)).toBe(false) expect(isHeld(2)).toBe(true) expect(isHeld(3)).toBe(false) }) }) describe('getDecision', () => { it('returns a valid DefensiveDecision from current state', () => { const { toggleHold, infieldDepth, getDecision } = useDefensiveSetup() infieldDepth.value = 'infield_in' toggleHold(1) toggleHold(3) const decision = getDecision() expect(decision).toEqual({ infield_depth: 'infield_in', outfield_depth: 'normal', hold_runners: [1, 3], }) }) it('returns defaults when nothing has been set', () => { const { getDecision } = useDefensiveSetup() expect(getDecision()).toEqual({ infield_depth: 'normal', outfield_depth: 'normal', hold_runners: [], }) }) }) })