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();
});
});
});