import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { describe, expect, it, vi } from 'vitest'; import { MdRadioGroup } from '../MdRadioGroup'; const mockOptions = [ { value: 'opt1', text: 'Option 1' }, { value: 'opt2', text: 'Option 2' }, { value: 'opt3', text: 'Option 3' }, ]; describe('MdRadioGroup', () => { describe('rendering', () => { it('renders radio group', () => { const { container } = render( {}} />); expect(container.querySelector('.md-radiogroup')).toBeInTheDocument(); }); it('renders all options', () => { render( {}} />); expect(screen.getByText('Option 1')).toBeInTheDocument(); expect(screen.getByText('Option 2')).toBeInTheDocument(); expect(screen.getByText('Option 3')).toBeInTheDocument(); }); it('renders label', () => { render( {}} />); expect(screen.getByText('Select option')).toBeInTheDocument(); }); it('renders all radio buttons', () => { render( {}} />); const radios = screen.getAllByRole('radio'); expect(radios).toHaveLength(3); }); it('does not render label section without label or helpText', () => { const { container } = render( {}} />); expect(container.querySelector('.md-radiogroup__label-wrapper')).not.toBeInTheDocument(); }); }); describe('selected value', () => { it('checks selected option', () => { render( {}} />); const radios = screen.getAllByRole('radio'); expect(radios[0]).not.toBeChecked(); expect(radios[1]).toBeChecked(); expect(radios[2]).not.toBeChecked(); }); it('handles no selection', () => { render( {}} />); const radios = screen.getAllByRole('radio'); radios.forEach(radio => { expect(radio).not.toBeChecked(); }); }); it('handles undefined value', () => { render( {}} />); const radios = screen.getAllByRole('radio'); radios.forEach(radio => { expect(radio).not.toBeChecked(); }); }); }); describe('directions', () => { it('applies vertical direction', () => { const { container } = render( {}} />); expect(container.querySelector('.md-radiogroup__options--vertical')).toBeInTheDocument(); }); it('applies horizontal direction by default', () => { const { container } = render( {}} />); expect(container.querySelector('.md-radiogroup__options--vertical')).not.toBeInTheDocument(); }); }); describe('states', () => { it('disables all radio buttons when disabled', () => { const { container } = render( {}} />); expect(container.querySelector('.md-radiogroup--disabled')).toBeInTheDocument(); }); it('shows error state', () => { const { container } = render( {}} />, ); expect(container.querySelector('.md-radiogroup__error')).toBeInTheDocument(); }); it('displays error text', () => { render( {}} />); expect(screen.getByText('Selection required')).toBeInTheDocument(); }); it('does not show error without errorText', () => { const { container } = render( {}} />); expect(container.querySelector('.md-radiogroup__error')).not.toBeInTheDocument(); }); }); describe('help text', () => { it('renders help button when helpText provided', () => { const { container } = render( {}} />, ); expect(container.querySelector('.md-helpbutton')).toBeInTheDocument(); }); it('shows help text when help button is clicked', async () => { const user = userEvent.setup(); const { container } = render( {}} />, ); const helpButton = container.querySelector('.md-helpbutton') as HTMLElement; await user.click(helpButton); expect(screen.getByText('Select one option')).toBeInTheDocument(); }); it('uses custom helpTextFor label', () => { const { container } = render( {}} />, ); const helpButton = container.querySelector('.md-helpbutton') as HTMLElement; expect(helpButton).toHaveAttribute('aria-label', 'Help for Options'); }); }); describe('events', () => { it('calls onChange when radio is clicked', async () => { const user = userEvent.setup(); const onChange = vi.fn(); render(); const radio = screen.getAllByRole('radio')[1]; await user.click(radio); expect(onChange).toHaveBeenCalled(); }); it('passes correct value in onChange', async () => { const user = userEvent.setup(); const onChange = vi.fn(); render(); const radio = screen.getAllByRole('radio')[1]; await user.click(radio); expect(onChange.mock.calls[0][0].target.value).toBe('opt2'); }); it('calls onFocus when radio receives focus', async () => { const user = userEvent.setup(); const onFocus = vi.fn(); render( {}} />); const radio = screen.getAllByRole('radio')[0]; await user.click(radio); expect(onFocus).toHaveBeenCalled(); }); it('calls onBlur when radio loses focus', async () => { const user = userEvent.setup(); const onBlur = vi.fn(); render( {}} />); const radios = screen.getAllByRole('radio'); await user.click(radios[0]); await user.click(radios[1]); expect(onBlur).toHaveBeenCalled(); }); }); describe('accessibility', () => { it('renders with radiogroup role', () => { render( {}} />); expect(screen.getByRole('radiogroup')).toBeInTheDocument(); }); it('renders as fieldset', () => { const { container } = render( {}} />); expect(container.querySelector('fieldset')).toBeInTheDocument(); }); it('renders label as legend', () => { render( {}} />); const fieldset = screen.getByRole('radiogroup'); expect(fieldset).toContainElement(screen.getByText('Select option')); }); it('associates help text with options', () => { const { container } = render( {}} />, ); const optionsDiv = container.querySelector('.md-radiogroup__options'); expect(optionsDiv).toHaveAttribute('aria-describedby', expect.stringContaining('help-text')); }); }); describe('props forwarding', () => { it('applies custom className', () => { const { container } = render( {}} />); expect(container.querySelector('.md-radiogroup')).toHaveClass('custom-class'); }); it('applies custom id', () => { const { container } = render( {}} />); expect(container.querySelector('#custom-id')).toBeInTheDocument(); }); it('forwards other props to fieldset', () => { render( {}} />); expect(screen.getByTestId('radio-group')).toBeInTheDocument(); }); }); });