import { fireEvent, render, screen } from '@testing-library/react'; import { describe, expect, it } from 'vitest'; import { RadioGroup } from './RadioGroup'; describe('RadioGroup', () => { it('renders radio items', () => { render( , ); expect(screen.getByRole('radio', { name: 'Option A' })).toBeInTheDocument(); expect(screen.getByRole('radio', { name: 'Option B' })).toBeInTheDocument(); }); it('supports compact item sizing', () => { render( , ); expect(screen.getByRole('radio', { name: 'Compact' })).toHaveAttribute( 'data-size', 'sm', ); }); it('selects defaultValue on mount', () => { render( , ); expect(screen.getByRole('radio', { name: 'Option B' })).toHaveAttribute( 'aria-checked', 'true', ); expect(screen.getByRole('radio', { name: 'Option A' })).toHaveAttribute( 'aria-checked', 'false', ); }); it('selecting one item deselects the others', () => { render( , ); const radioB = screen.getByRole('radio', { name: 'Option B' }); fireEvent.click(radioB); expect(radioB).toHaveAttribute('aria-checked', 'true'); expect(screen.getByRole('radio', { name: 'Option A' })).toHaveAttribute( 'aria-checked', 'false', ); }); it('clicking the label selects its item', () => { render( , ); const label = screen.getByText('Option A'); const radio = screen.getByRole('radio', { name: 'Option A' }); expect(radio).toHaveAttribute('aria-checked', 'false'); fireEvent.click(label); expect(radio).toHaveAttribute('aria-checked', 'true'); }); it('disabled item is not interactive', () => { render( , ); const radio = screen.getByRole('radio', { name: 'Disabled' }); expect(radio).toHaveAttribute('aria-disabled', 'true'); fireEvent.click(radio); expect(radio).toHaveAttribute('aria-checked', 'false'); }); it('mutes the label when its item is disabled', () => { render( , ); expect( screen.getByText('Disabled').closest('[data-slot="radio-label"]'), ).toHaveClass('text-muted-foreground'); expect( screen.getByText('Enabled').closest('[data-slot="radio-label"]'), ).not.toHaveClass('text-muted-foreground'); }); it('supports arrow-key roving focus between items', () => { render( , ); // All radios in a group are reachable via keyboard. const radios = screen.getAllByRole('radio'); expect(radios).toHaveLength(3); // The group element exists and has roving-tabindex structure (tabIndex 0 on selected). const radioA = screen.getByRole('radio', { name: 'Option A' }); expect(radioA).toHaveAttribute('aria-checked', 'true'); // Click directly to simulate selection change (roving focus is a browser behavior). fireEvent.click(screen.getByRole('radio', { name: 'Option C' })); expect(screen.getByRole('radio', { name: 'Option C' })).toHaveAttribute( 'aria-checked', 'true', ); expect(radioA).toHaveAttribute('aria-checked', 'false'); }); it('disabled unlabeled item is not interactive', () => { render( , ); const radio = screen.getByRole('radio', { name: 'Hidden' }); expect(radio).toHaveAttribute('aria-disabled', 'true'); fireEvent.click(radio); expect(radio).toHaveAttribute('aria-checked', 'false'); }); it('renders compound RadioGroup.Item.Label', () => { render( Custom label , ); expect(screen.getByText('Custom label')).toHaveAttribute( 'data-slot', 'radio-label', ); }); });