import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { AutodraftSettings } from '~/components/AutodraftSettings'; // Mock fetch global.fetch = vi.fn(); describe('AutodraftSettings Component', () => { const defaultProps = { seasonId: 'season-123', teamId: 'team-456', isEnabled: false, mode: 'next_pick' as const, isMyTurn: false, onUpdate: vi.fn(), }; beforeEach(() => { vi.clearAllMocks(); (global.fetch as any).mockResolvedValue({ ok: true, json: async () => ({ success: true }), }); }); describe('Rendering', () => { it('should render the autodraft switch', () => { render(); expect(screen.getByText('Autodraft')).toBeInTheDocument(); expect(screen.getByRole('switch')).toBeInTheDocument(); }); it('should not show mode options when autodraft is disabled', () => { render(); expect(screen.queryByText('Next Pick')).not.toBeInTheDocument(); expect(screen.queryByText('While On')).not.toBeInTheDocument(); }); it('should show mode options when autodraft is enabled', () => { render(); expect(screen.getByText('Next Pick')).toBeInTheDocument(); expect(screen.getByText('While On')).toBeInTheDocument(); }); it('should show disabled message when it is user turn', () => { render(); expect(screen.getByText(/Autodraft settings are disabled during your pick/i)).toBeInTheDocument(); }); }); describe('Switch Toggle', () => { it('should enable autodraft when switch is toggled on', async () => { const onUpdate = vi.fn(); render(); const switchElement = screen.getByRole('switch'); fireEvent.click(switchElement); await waitFor(() => { expect(global.fetch).toHaveBeenCalledWith( '/api/autodraft/update', expect.objectContaining({ method: 'POST', }) ); }); await waitFor(() => { expect(onUpdate).toHaveBeenCalledWith(true, 'next_pick'); }); }); it('should disable autodraft when switch is toggled off', async () => { const onUpdate = vi.fn(); render(); const switchElement = screen.getByRole('switch'); fireEvent.click(switchElement); await waitFor(() => { expect(global.fetch).toHaveBeenCalled(); }); await waitFor(() => { expect(onUpdate).toHaveBeenCalledWith(false, 'next_pick'); }); }); it('should be disabled when it is user turn', () => { render(); const switchElement = screen.getByRole('switch'); expect(switchElement).toBeDisabled(); }); it('should handle API errors gracefully', async () => { const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); (global.fetch as any).mockResolvedValueOnce({ ok: false, json: async () => ({ error: 'Server error' }), }); render(); const switchElement = screen.getByRole('switch'); fireEvent.click(switchElement); await waitFor(() => { expect(consoleSpy).toHaveBeenCalled(); }); // Switch should revert to original state expect(switchElement).not.toBeChecked(); consoleSpy.mockRestore(); }); }); describe('Mode Selection', () => { it('should select next_pick mode by default', () => { render(); const nextPickRadio = screen.getByRole('radio', { name: /next pick/i }); expect(nextPickRadio).toBeChecked(); }); it('should select while_on mode when specified', () => { render(); const whileOnRadio = screen.getByRole('radio', { name: /while on/i }); expect(whileOnRadio).toBeChecked(); }); it('should change mode when radio button is clicked', async () => { const onUpdate = vi.fn(); render(); const whileOnRadio = screen.getByRole('radio', { name: /while on/i }); fireEvent.click(whileOnRadio); await waitFor(() => { expect(global.fetch).toHaveBeenCalled(); }); await waitFor(() => { expect(onUpdate).toHaveBeenCalledWith(true, 'while_on'); }); }); it('should disable mode selection when it is user turn', () => { render(); const nextPickRadio = screen.getByRole('radio', { name: /next pick/i }); const whileOnRadio = screen.getByRole('radio', { name: /while on/i }); expect(nextPickRadio).toBeDisabled(); expect(whileOnRadio).toBeDisabled(); }); }); describe('API Integration', () => { it('should send correct data when enabling autodraft', async () => { render(); const switchElement = screen.getByRole('switch'); fireEvent.click(switchElement); await waitFor(() => { expect(global.fetch).toHaveBeenCalledWith( '/api/autodraft/update', expect.objectContaining({ method: 'POST', body: expect.any(FormData), }) ); }); const fetchCall = (global.fetch as any).mock.calls[0]; const formData = fetchCall[1].body as FormData; expect(formData.get('seasonId')).toBe('season-123'); expect(formData.get('teamId')).toBe('team-456'); expect(formData.get('isEnabled')).toBe('true'); expect(formData.get('mode')).toBe('next_pick'); }); it('should send correct data when changing mode', async () => { render(); const whileOnRadio = screen.getByRole('radio', { name: /while on/i }); fireEvent.click(whileOnRadio); await waitFor(() => { expect(global.fetch).toHaveBeenCalled(); }); const fetchCall = (global.fetch as any).mock.calls[0]; const formData = fetchCall[1].body as FormData; expect(formData.get('mode')).toBe('while_on'); expect(formData.get('isEnabled')).toBe('true'); }); it('should show loading state during API call', async () => { let resolvePromise: any; const fetchPromise = new Promise((resolve) => { resolvePromise = resolve; }); (global.fetch as any).mockReturnValueOnce(fetchPromise); render(); const switchElement = screen.getByRole('switch'); fireEvent.click(switchElement); // Switch should be disabled during update await waitFor(() => { expect(switchElement).toBeDisabled(); }); // Resolve the promise resolvePromise({ ok: true, json: async () => ({ success: true }) }); // Switch should be enabled again await waitFor(() => { expect(switchElement).not.toBeDisabled(); }); }); }); describe('Edge Cases', () => { it('should handle rapid toggle clicks', async () => { render(); const switchElement = screen.getByRole('switch'); // Click multiple times rapidly fireEvent.click(switchElement); fireEvent.click(switchElement); fireEvent.click(switchElement); // Should only process the first click while updating await waitFor(() => { expect(global.fetch).toHaveBeenCalledTimes(1); }); }); it('should handle network errors', async () => { const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); (global.fetch as any).mockRejectedValueOnce(new Error('Network error')); render(); const switchElement = screen.getByRole('switch'); fireEvent.click(switchElement); await waitFor(() => { expect(consoleSpy).toHaveBeenCalled(); }); consoleSpy.mockRestore(); }); it('should maintain state consistency on error', async () => { (global.fetch as any).mockResolvedValueOnce({ ok: false, json: async () => ({ error: 'Server error' }), }); render(); const switchElement = screen.getByRole('switch'); expect(switchElement).not.toBeChecked(); fireEvent.click(switchElement); // Should revert to original state on error await waitFor(() => { expect(switchElement).not.toBeChecked(); }); }); }); });