import { describe, it, expect, beforeEach } from 'vitest' import { mount } from '@vue/test-utils' import DefensiveSetup from '~/components/Decisions/DefensiveSetup.vue' import type { DefensiveDecision } from '~/types/game' describe('DefensiveSetup', () => { const defaultProps = { gameId: 'test-game-123', isActive: true, } describe('Rendering', () => { it('renders component with header', () => { const wrapper = mount(DefensiveSetup, { props: defaultProps, }) expect(wrapper.text()).toContain('Defensive Setup') }) it('shows opponent turn indicator when not active', () => { const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, isActive: false, }, }) expect(wrapper.text()).toContain("Opponent's Turn") }) it('renders all form sections', () => { const wrapper = mount(DefensiveSetup, { props: defaultProps, }) expect(wrapper.text()).toContain('Infield Depth') expect(wrapper.text()).toContain('Outfield Depth') expect(wrapper.text()).toContain('Hold Runners') }) }) describe('Initial Values', () => { it('uses default values when no currentSetup provided', () => { const wrapper = mount(DefensiveSetup, { props: defaultProps, }) // Check preview shows defaults expect(wrapper.text()).toContain('Normal') }) it('uses provided currentSetup values', () => { const currentSetup: DefensiveDecision = { infield_depth: 'back', outfield_depth: 'normal', hold_runners: [1, 3], } const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, currentSetup, }, }) expect(wrapper.vm.localSetup.infield_depth).toBe('back') expect(wrapper.vm.localSetup.outfield_depth).toBe('normal') expect(wrapper.vm.localSetup.hold_runners).toEqual([1, 3]) }) }) describe('Hold Runners', () => { it('initializes hold runner toggles from currentSetup', () => { const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, currentSetup: { infield_depth: 'normal', outfield_depth: 'normal', hold_runners: [1, 2], }, }, }) expect(wrapper.vm.holdFirst).toBe(true) expect(wrapper.vm.holdSecond).toBe(true) expect(wrapper.vm.holdThird).toBe(false) }) it('updates hold_runners array when toggles change', async () => { const wrapper = mount(DefensiveSetup, { props: defaultProps, }) wrapper.vm.holdFirst = true wrapper.vm.holdThird = true await wrapper.vm.$nextTick() expect(wrapper.vm.localSetup.hold_runners).toContain(1) expect(wrapper.vm.localSetup.hold_runners).toContain(3) expect(wrapper.vm.localSetup.hold_runners).not.toContain(2) }) }) describe('Preview Display', () => { it('displays current infield depth in preview', () => { const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, currentSetup: { infield_depth: 'back', outfield_depth: 'normal', hold_runners: [], }, }, }) expect(wrapper.text()).toContain('Back') }) it('displays holding status for multiple runners', () => { const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, currentSetup: { infield_depth: 'normal', outfield_depth: 'normal', hold_runners: [1, 2, 3], }, }, }) const holdingText = wrapper.vm.holdingDisplay expect(holdingText).toContain('1st') expect(holdingText).toContain('2nd') expect(holdingText).toContain('3rd') }) it('shows "None" when no runners held', () => { const wrapper = mount(DefensiveSetup, { props: defaultProps, }) expect(wrapper.vm.holdingDisplay).toBe('None') }) }) describe('Form Submission', () => { it('emits submit event with current setup', async () => { const wrapper = mount(DefensiveSetup, { props: defaultProps, }) wrapper.vm.localSetup = { infield_depth: 'in', outfield_depth: 'normal', hold_runners: [2], } await wrapper.find('form').trigger('submit.prevent') expect(wrapper.emitted('submit')).toBeTruthy() const emitted = wrapper.emitted('submit')![0][0] as DefensiveDecision expect(emitted.infield_depth).toBe('in') expect(emitted.outfield_depth).toBe('normal') expect(emitted.hold_runners).toEqual([2]) }) it('does not submit when not active', async () => { const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, isActive: false, }, }) await wrapper.find('form').trigger('submit.prevent') expect(wrapper.emitted('submit')).toBeFalsy() }) it('does not submit when no changes', async () => { const currentSetup: DefensiveDecision = { infield_depth: 'normal', outfield_depth: 'normal', hold_runners: [], } const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, currentSetup, }, }) await wrapper.find('form').trigger('submit.prevent') expect(wrapper.emitted('submit')).toBeFalsy() }) it('shows loading state during submission', async () => { const wrapper = mount(DefensiveSetup, { props: defaultProps, }) // Trigger submission wrapper.vm.submitting = true await wrapper.vm.$nextTick() // Verify button is in loading state expect(wrapper.vm.submitting).toBe(true) }) }) describe('Submit Button State', () => { it('shows "Wait for Your Turn" when not active', () => { const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, isActive: false, }, }) expect(wrapper.vm.submitButtonText).toBe('Wait for Your Turn') }) it('shows "Submit (Keep Setup)" when setup unchanged', () => { const currentSetup: DefensiveDecision = { infield_depth: 'normal', outfield_depth: 'normal', hold_runners: [], } const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, currentSetup, }, }) expect(wrapper.vm.submitButtonText).toBe('Submit (Keep Setup)') }) it('shows "Submit Defensive Setup" when active with changes', () => { const wrapper = mount(DefensiveSetup, { props: defaultProps, }) wrapper.vm.localSetup.infield_depth = 'back' expect(wrapper.vm.submitButtonText).toBe('Submit Defensive Setup') }) }) describe('Change Detection', () => { it('detects infield depth changes', () => { const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, currentSetup: { infield_depth: 'normal', outfield_depth: 'normal', hold_runners: [], }, }, }) expect(wrapper.vm.hasChanges).toBe(false) wrapper.vm.localSetup.infield_depth = 'back' expect(wrapper.vm.hasChanges).toBe(true) }) it('detects hold runners changes', () => { const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, currentSetup: { infield_depth: 'normal', outfield_depth: 'normal', hold_runners: [], }, }, }) expect(wrapper.vm.hasChanges).toBe(false) wrapper.vm.localSetup.hold_runners = [1] expect(wrapper.vm.hasChanges).toBe(true) }) }) describe('Prop Updates', () => { it('updates local state when currentSetup prop changes', async () => { const wrapper = mount(DefensiveSetup, { props: defaultProps, }) const newSetup: DefensiveDecision = { infield_depth: 'double_play', outfield_depth: 'normal', hold_runners: [1, 2, 3], } await wrapper.setProps({ currentSetup: newSetup }) expect(wrapper.vm.localSetup.infield_depth).toBe('double_play') expect(wrapper.vm.localSetup.outfield_depth).toBe('normal') expect(wrapper.vm.localSetup.hold_runners).toEqual([1, 2, 3]) }) }) describe('Disabled State', () => { it('disables all controls when not active', () => { const wrapper = mount(DefensiveSetup, { props: { ...defaultProps, isActive: false, }, }) const buttonGroups = wrapper.findAllComponents({ name: 'ButtonGroup' }) buttonGroups.forEach(bg => { expect(bg.props('disabled')).toBe(true) }) const toggles = wrapper.findAllComponents({ name: 'ToggleSwitch' }) toggles.forEach(toggle => { expect(toggle.props('disabled')).toBe(true) }) }) }) })