import { describe, it, expect, vi, beforeEach, MockedFunction } from 'vitest' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import EditTournamentForm from '@/components/EditTournamentForm' // Mock next/navigation vi.mock('next/navigation', () => ({ useRouter: () => ({ push: vi.fn(), }), })) // Mock next/link vi.mock('next/link', () => ({ default: ({ children, href }: { children: React.ReactNode; href: string }) => ( {children} ), })) // Mock fetch const mockFetch = vi.fn() global.fetch = mockFetch as MockedFunction const mockTournament = { id: 1, event_id: null, name: 'Test Tournament', description: 'A test tournament', eventDate: new Date('2024-01-15'), eventType: 'tournament', format: 'round_robin', status: 'planned', maxParticipants: 16, ownerId: null, targetScore: null, allowTies: false, createdAt: new Date(), updatedAt: new Date(), } describe('EditTournamentForm', () => { beforeEach(() => { vi.clearAllMocks() }) it('renders form with initial values', () => { render() expect(screen.getByLabelText('Tournament Name')).toHaveValue('Test Tournament') expect(screen.getByLabelText('Description')).toHaveValue('A test tournament') expect(screen.getByLabelText('Date')).toHaveValue('2024-01-15') expect(screen.getByLabelText('Event Type')).toHaveValue('tournament') expect(screen.getByLabelText('Format')).toHaveValue('round_robin') expect(screen.getByLabelText('Status')).toHaveValue('planned') expect(screen.getByLabelText('Max Participants (optional)')).toHaveValue(16) }) it('updates form values on change', async () => { const user = userEvent.setup() render() const nameInput = screen.getByLabelText('Tournament Name') await user.clear(nameInput) await user.type(nameInput, 'Updated Tournament') expect(nameInput).toHaveValue('Updated Tournament') }) it('submits form with updated data', async () => { const user = userEvent.setup() mockFetch.mockResolvedValueOnce({ ok: true, json: async () => ({ success: true }), } as Response) render() const nameInput = screen.getByLabelText('Tournament Name') await user.clear(nameInput) await user.type(nameInput, 'Updated Tournament') const submitButton = screen.getByText('Save Changes') await user.click(submitButton) await waitFor(() => { expect(mockFetch).toHaveBeenCalledWith( '/api/tournaments/1', expect.objectContaining({ method: 'PUT', body: expect.stringContaining('Updated Tournament'), }) ) }) }) it('shows error message on failed submission', async () => { const user = userEvent.setup() mockFetch.mockResolvedValueOnce({ ok: false, json: async () => ({ error: 'Failed to update tournament' }), } as Response) render() const submitButton = screen.getByText('Save Changes') await user.click(submitButton) await waitFor(() => { expect(screen.getByText('Failed to update tournament')).toBeInTheDocument() }) }) it('disables submit button while loading', async () => { const user = userEvent.setup() mockFetch.mockImplementation( () => new Promise((resolve) => { setTimeout(() => { resolve({ ok: true, json: async () => ({ success: true }), } as Response) }, 100) }) ) render() const submitButton = screen.getByText('Save Changes') await user.click(submitButton) expect(submitButton).toBeDisabled() expect(submitButton).toHaveTextContent('Saving...') }) })