import React from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import { axe } from 'jest-axe'; import { Radio, RadioGroup, RadioGroupProps, RadioProps } from '..'; function WrappedRadio({ checked }: { checked: string }) { return ( Input 1 Input 2 ); } const renderWrappedRadioGroup = (checked: string) => { render(); }; const renderControlledRadioGroup = ( props: Omit = {}, ) => { render( Input 1 Input 2 Input 3 , ); }; const renderUncontrolledRadioGroup = ( props: Omit = {}, ) => { return render( Input 1 Input 2 Input 3 , ); }; const renderRadio = (props: Omit) => { const { getByTestId, ...rest } = render( , ); const radio = getByTestId('lg-radio'); return { radio, ...rest }; }; describe('packages/radio-group', () => { describe('a11y', () => { test('does not have basic accessibility issues', async () => { const { container } = renderUncontrolledRadioGroup(); const results = await axe(container); expect(results).toHaveNoViolations(); }); }); describe('when the RadioGroup is controlled', () => { let onChange: jest.Mock; beforeEach(() => { onChange = jest.fn(); }); afterEach(() => { jest.clearAllMocks(); }); test('initial value set by RadioGroup when prop provided', () => { renderControlledRadioGroup(); const firstInput = screen.getAllByRole('radio')[0]; expect(firstInput.getAttribute('aria-checked')).toBe('true'); }); test('onChange fires once when the label is clicked', () => { renderControlledRadioGroup({ onChange }); const secondInput = screen.getAllByRole('radio')[1]; fireEvent.click(secondInput); expect(onChange).toHaveBeenCalledTimes(1); }); test('Radio does not become checked when clicked', () => { renderControlledRadioGroup(); const firstInput = screen.getAllByRole('radio')[0]; const secondInput = screen.getAllByRole('radio')[1]; fireEvent.click(secondInput); expect(firstInput.getAttribute('aria-checked')).toBe('true'); expect(secondInput.getAttribute('aria-checked')).toBe(null); }); }); describe('when an external component controls the RadioGroup', () => { test('initial checked Radio is determined by `checked` prop on Radio', () => { renderWrappedRadioGroup('input-1'); const initialChecked = screen.getByTestId('first-radio'); expect((initialChecked as HTMLInputElement).checked).toBe(true); }); test('when `checked` value changes, the checked Radio changes', () => { renderWrappedRadioGroup('input-2'); const newChecked = screen.getByTestId('second-radio'); expect((newChecked as HTMLInputElement).checked).toBe(true); const initialChecked = screen.getByTestId('first-radio'); expect((initialChecked as HTMLInputElement).checked).toBe(false); }); }); describe('when the RadioGroup is uncontrolled', () => { let onChange: jest.Mock; beforeEach(() => { onChange = jest.fn(); }); afterEach(() => { jest.clearAllMocks(); }); test('renders the className to the RadioGroup container when the prop is set', () => { const className = 'test-className'; renderUncontrolledRadioGroup({ className }); const container = screen.getByRole('group'); expect(container.classList.contains(className)).toBe(true); }); test('renders the name in the "aria-label" field of the RadioGroup container', () => { const name = 'test-name'; renderUncontrolledRadioGroup({ name }); const container = screen.getByRole('group'); expect(container.getAttribute('aria-label')).toBe(name); }); test('sets Radio as checked by default when the "default" prop is passed', () => { renderUncontrolledRadioGroup(); const firstInput = screen.getAllByRole('radio')[0]; expect(firstInput.getAttribute('aria-checked')).toBe('true'); }); test('onChange fires once when the label is clicked', () => { renderUncontrolledRadioGroup({ onChange }); const secondInput = screen.getAllByRole('radio')[1]; fireEvent.click(secondInput); expect(onChange).toHaveBeenCalledTimes(1); }); test('Radio becomes checked when clicked', () => { renderUncontrolledRadioGroup(); const firstInput = screen.getAllByRole('radio')[0]; const secondInput = screen.getAllByRole('radio')[1]; fireEvent.click(secondInput); expect(firstInput.getAttribute('aria-checked')).toBe('false'); expect(secondInput.getAttribute('aria-checked')).toBe('true'); }); }); describe('packages/radio', () => { const className = 'radio-className'; test(`renders "${className}" in the labels's class list`, () => { const { radio } = renderRadio({ className }); const label = radio.parentElement; expect(label).not.toBeNull(); expect(label!.classList.contains(className)).toBe(true); }); test(`renders with aria-disabled attribute but not disabled attribute when disabled prop is set`, () => { const { radio } = renderRadio({ disabled: true }); expect(radio.getAttribute('aria-disabled')).toBeTruthy(); expect(radio.getAttribute('disabled')).toBeFalsy(); }); test('does not fire onChange events when disabled', () => { const onChange = jest.fn(); const { radio } = renderRadio({ disabled: true, onChange }); fireEvent.click(radio); expect(onChange).not.toHaveBeenCalled(); expect(radio.getAttribute('checked')).toBeFalsy(); expect(radio.getAttribute('aria-checked')).toBeFalsy(); expect(radio.getAttribute('aria-disabled')).toBeTruthy(); }); test(`radio is checked when value is set`, () => { const { radio } = renderRadio({ checked: true }); expect(radio.getAttribute('aria-checked')).toBe('true'); }); test(`radio renders a description`, () => { const { getByText } = renderRadio({ checked: true, description: 'a description', }); const description = getByText('a description'); expect(description).toBeInTheDocument(); }); }); });