import { render, screen, fireEvent, waitFor } from '@testing-library/react' import { StageTransitionModal } from '../StageTransitionModal' const stages = [ { id: 'prospect', label: 'Prospect' }, { id: 'qualified', label: 'Qualified' }, { id: 'proposal', label: 'Proposal' }, { id: 'closed', label: 'Closed Won' }, ] const baseProps = { open: true, onClose: jest.fn(), onConfirm: jest.fn(), currentStage: 'prospect', stages, } describe('StageTransitionModal', () => { beforeEach(() => { jest.clearAllMocks() }) it('renders nothing when open is false', () => { render() expect(screen.queryByText(/move/i)).not.toBeInTheDocument() }) it('renders dialog when open is true', () => { render() expect(screen.getByText('Move Item to Stage')).toBeInTheDocument() }) it('includes entityName in dialog title when provided', () => { render() expect(screen.getByText('Move "ACME Deal" to Stage')).toBeInTheDocument() }) it('shows the current stage label', () => { render() expect(screen.getByText('Prospect')).toBeInTheDocument() }) it('excludes the current stage from the new stage dropdown', () => { render() const options = screen.getAllByRole('option') const optionValues = options.map((o) => (o as HTMLOptionElement).value) expect(optionValues).not.toContain('prospect') expect(optionValues).toContain('qualified') expect(optionValues).toContain('proposal') expect(optionValues).toContain('closed') }) it('defaults to the first non-current stage', () => { render() const select = screen.getByLabelText('New Stage') as HTMLSelectElement expect(select.value).toBe('qualified') }) it('calls onConfirm with selected stage when Confirm is clicked', () => { const onConfirm = jest.fn() render() fireEvent.click(screen.getByRole('button', { name: /confirm/i })) expect(onConfirm).toHaveBeenCalledWith('qualified', undefined) }) it('passes notes to onConfirm when notes are entered', () => { const onConfirm = jest.fn() render() fireEvent.change(screen.getByLabelText(/notes/i), { target: { value: 'Moving due to demo completed' }, }) fireEvent.click(screen.getByRole('button', { name: /confirm/i })) expect(onConfirm).toHaveBeenCalledWith('qualified', 'Moving due to demo completed') }) it('passes undefined for whitespace-only notes', () => { const onConfirm = jest.fn() render() fireEvent.change(screen.getByLabelText(/notes/i), { target: { value: ' ' } }) fireEvent.click(screen.getByRole('button', { name: /confirm/i })) expect(onConfirm).toHaveBeenCalledWith('qualified', undefined) }) it('calls onClose when Cancel is clicked', () => { const onClose = jest.fn() render() fireEvent.click(screen.getByRole('button', { name: /cancel/i })) expect(onClose).toHaveBeenCalledTimes(1) }) it('calls onClose when backdrop is clicked', () => { const onClose = jest.fn() const { container } = render( ) const backdrop = container.querySelector('[aria-hidden="true"]') fireEvent.click(backdrop!) expect(onClose).toHaveBeenCalledTimes(1) }) it('does not call onClose when backdrop clicked while submitting', () => { const onClose = jest.fn() const { container } = render( ) const backdrop = container.querySelector('[aria-hidden="true"]') fireEvent.click(backdrop!) expect(onClose).not.toHaveBeenCalled() }) it('shows Moving... when isSubmitting', () => { render() expect(screen.getByText('Moving...')).toBeInTheDocument() }) it('disables select and textarea when isSubmitting', () => { render() expect(screen.getByLabelText('New Stage')).toBeDisabled() expect(screen.getByLabelText(/notes/i)).toBeDisabled() }) it('disables Cancel when isSubmitting', () => { render() expect(screen.getByRole('button', { name: /cancel/i })).toBeDisabled() }) it('Confirm button is disabled while submitting', () => { render() expect(screen.getByText('Moving...').closest('button')).toBeDisabled() }) it('resets notes when dialog reopens', () => { const { rerender } = render( ) rerender() expect(screen.getByLabelText(/notes/i)).toHaveValue('') }) it('allows changing the target stage via the select', () => { render() const select = screen.getByLabelText('New Stage') as HTMLSelectElement fireEvent.change(select, { target: { value: 'closed' } }) expect(select.value).toBe('closed') }) it('calls onConfirm with the newly selected stage', () => { const onConfirm = jest.fn() render() fireEvent.change(screen.getByLabelText('New Stage'), { target: { value: 'closed' } }) fireEvent.click(screen.getByRole('button', { name: /confirm/i })) expect(onConfirm).toHaveBeenCalledWith('closed', undefined) }) it('renders Current Stage label', () => { render() expect(screen.getByText('Current Stage')).toBeInTheDocument() }) it('renders New Stage label', () => { render() expect(screen.getByText('New Stage')).toBeInTheDocument() }) })