import * as React from 'react' import { isInaccessible } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { render } from '~/src/utils/test' import { FormControl, type FormControlProps, } from '~/src/components/FormControl' import { Checkbox } from './Checkbox' import { type CheckboxProps, type CheckedState } from './Checkbox.types' const VALUES = ['0', '1', '2'] describe('Checkbox', () => { const renderCheckbox = ({ children, ...rest }: CheckboxProps = {}) => render({children}) const renderCheckboxes = ( props: Omit, 'children'> = {} ) => render(
{VALUES.map((value) => ( {value} ))}
) let user: ReturnType beforeEach(() => { user = userEvent.setup() }) describe('ARIA', () => { it('should be accessible', () => { const { container } = renderCheckbox() expect(isInaccessible(container)).toBe(false) }) it('should have \'role="checkbox"\' attribute', () => { const { getByRole } = renderCheckbox() expect(getByRole('checkbox')).toBeInTheDocument() }) it('should be disabled when disabled prop is true', () => { const { getByRole } = renderCheckbox({ disabled: true }) expect(getByRole('checkbox')).toHaveAttribute('aria-disabled', 'true') }) it('should be required when required prop is true', () => { const { getByRole } = renderCheckbox({ required: true }) expect(getByRole('checkbox')).toHaveAttribute('aria-required', 'true') }) it('should be invalid when hasError prop is true', () => { const { getByRole } = renderCheckbox({ hasError: true }) expect(getByRole('checkbox')).toHaveAttribute('aria-invalid', 'true') }) it('should have \'aria-checked="mixed"\' attribute If it is in indeterminate state', () => { const { getByRole } = renderCheckbox({ checked: 'indeterminate' }) expect(getByRole('checkbox')).toHaveAttribute('aria-checked', 'mixed') }) }) describe('User Interactions', () => { it('should focus and check checkbox when user clicks on a checkbox', async () => { const { getByRole } = renderCheckbox() const checkbox = getByRole('checkbox') await user.click(checkbox) expect(checkbox).toHaveFocus() expect(checkbox).toBeChecked() }) it('should focus and check checkbox when user clicks on a label of checkbox', async () => { const { getByText, getByRole } = renderCheckbox({ children: 'Label' }) const checkbox = getByRole('checkbox') const label = getByText('Label') await user.click(label) expect(checkbox).toHaveFocus() expect(checkbox).toBeChecked() }) it('should call the checked change event handler when user clicks on a checkbox', async () => { const onCheckedChange = jest.fn() const { getByRole } = renderCheckbox({ onCheckedChange }) const checkbox = getByRole('checkbox') await user.click(checkbox) expect(onCheckedChange).toHaveBeenCalledTimes(1) }) it('should focus on the first checkbox item when user presses tab key', async () => { const { getByRole } = renderCheckboxes() const checkbox = getByRole('checkbox', { name: VALUES[0] }) await user.tab() expect(checkbox).toHaveFocus() }) it('should check checkbox when user presses space key on a focused checkbox', async () => { const { getByRole } = renderCheckboxes() const checkbox = getByRole('checkbox', { name: VALUES[0] }) await user.tab() expect(checkbox).toHaveFocus() await user.keyboard('{ }') expect(checkbox).toHaveFocus() expect(checkbox).toBeChecked() }) it('should call the checked change event handler user presses space key on a focused checkbox', async () => { const onCheckedChange = jest.fn() const { getByRole } = renderCheckboxes({ onCheckedChange }) const checkbox = getByRole('checkbox', { name: VALUES[0] }) await user.tab() expect(checkbox).toHaveFocus() await user.keyboard('{ }') expect(onCheckedChange).toHaveBeenCalledTimes(1) }) }) describe('With FormControl', () => { const renderCheckboxWithFormControl = ({ children, formControlProps = {}, checkboxProps = {}, }: { children?: React.ReactNode formControlProps?: Omit checkboxProps?: Omit, 'children'> }) => render( {children} ) it("FormControl's disabled prop should be passed to Checkbox", () => { const { getByRole } = renderCheckboxWithFormControl({ formControlProps: { disabled: true }, }) expect(getByRole('checkbox')).toHaveAttribute('aria-disabled', 'true') }) it("FormControl's hasError prop should be passed to Checkbox", () => { const { getByRole } = renderCheckboxWithFormControl({ formControlProps: { hasError: true }, }) expect(getByRole('checkbox')).toHaveAttribute('aria-invalid', 'true') }) it("FormControl's required prop should be passed to Checkbox", () => { const { getByRole } = renderCheckboxWithFormControl({ formControlProps: { required: true }, }) expect(getByRole('checkbox')).toHaveAttribute('aria-required', 'true') }) it("FormControl's id prop should be passed to Checkbox", () => { const { getByRole } = renderCheckboxWithFormControl({ formControlProps: { id: 'form-control-id' }, }) expect(getByRole('checkbox')).toHaveAttribute('id', 'form-control-id') }) it("FormControl's id prop should be overwritten by Checkbox's id prop", () => { const { getByRole } = renderCheckboxWithFormControl({ formControlProps: { id: 'form-control-id' }, checkboxProps: { id: 'checkbox-id' }, }) expect(getByRole('checkbox')).toHaveAttribute('id', 'checkbox-id') }) }) })