Skip to content

Commit

Permalink
test: update Checkbox tests to use react testing library (#1341)
Browse files Browse the repository at this point in the history
  • Loading branch information
scurker authored Feb 9, 2024
1 parent 3818823 commit f6a8495
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 140 deletions.
140 changes: 0 additions & 140 deletions packages/react/__tests__/src/components/Checkbox/index.js

This file was deleted.

1 change: 1 addition & 0 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@svgr/rollup": "^6.1.2",
"@testing-library/jest-dom": "^6.1.3",
"@testing-library/react": "11.1.2",
"@testing-library/user-event": "^14.5.2",
"@types/classnames": "^2.2.10",
"@types/enzyme-adapter-react-16": "^1.0.9",
"@types/jest": "^29.5.11",
Expand Down
187 changes: 187 additions & 0 deletions packages/react/src/components/Checkbox/Checkbox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import React, { createRef } from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { spy } from 'sinon';
import { axe } from 'jest-axe';
import Checkbox from './';

type SetOptional<T, Keys extends keyof T> = Pick<Partial<T>, Keys> &
Omit<T, Keys>;
type CheckboxProps = SetOptional<
React.ComponentProps<typeof Checkbox>,
'label' | 'id'
>;

const renderCheckbox = ({
label,
...props
}: CheckboxProps = {}): HTMLInputElement => {
render(<Checkbox id="checkbox-id" label={label || 'checkbox'} {...props} />);
// no individual assertions needed, as this should throw if the element does not exist
return screen.getByRole('checkbox', {
name: label as string
}) as HTMLInputElement;
};

test('should render unchecked checkbox', () => {
const input = renderCheckbox({ label: 'this is a checkbox' });
expect(input).not.toBeChecked();
expect(screen.queryByText('this is a checkbox')).toBeInTheDocument();
});

test('should render checked checkbox', () => {
const input = renderCheckbox({ checked: true });
expect(input).toBeChecked();
});

test('should render disabled unchecked checkbox', () => {
const input = renderCheckbox({ disabled: true });
expect(input).toBeDisabled();
expect(input).not.toBeChecked();
});

test('should render disabled checked checkbox', () => {
const input = renderCheckbox({ disabled: true, checked: true });
expect(input).toBeDisabled();
expect(input).toBeChecked();
});

test('should render error checkbox', () => {
const input = renderCheckbox({ error: 'you should check this checkbox' });
expect(input).toHaveAccessibleDescription('you should check this checkbox');
expect(
screen.queryByText('you should check this checkbox')
).toBeInTheDocument();
});

test('should toggle checkbox correctly', async () => {
const user = userEvent.setup();
const input = renderCheckbox();
const checkboxIcon = input.parentElement!.querySelector(
'.Checkbox__overlay'
) as HTMLElement;
expect(checkboxIcon).toHaveClass('Icon--checkbox-unchecked');
expect(checkboxIcon).not.toHaveClass('Icon--checkbox-checked');
expect(input).not.toBeChecked();

await user.click(checkboxIcon);
expect(checkboxIcon).not.toHaveClass('Icon--checkbox-unchecked');
expect(checkboxIcon).toHaveClass('Icon--checkbox-checked');
});

test('should handle focus correctly', () => {
const onFocus = spy();
const input = renderCheckbox({ onFocus });
const checkboxIcon = input.parentElement!.querySelector(
'.Checkbox__overlay'
) as HTMLElement;
expect(checkboxIcon).not.toHaveClass('.Checkbox__overlay--focused');
expect(onFocus.notCalled).toBeTruthy();

input.focus();
expect(input).toHaveFocus();
expect(checkboxIcon).toHaveClass('Checkbox__overlay--focused');
expect(onFocus.calledOnce).toBeTruthy();
});

test('should handle blur correctly', () => {
const onBlur = spy();
const input = renderCheckbox({ onBlur, checked: true });
const checkboxIcon = input.parentElement!.querySelector(
'.Checkbox__overlay'
) as HTMLElement;
expect(checkboxIcon).not.toHaveClass('.Checkbox__overlay--focused');
expect(onBlur.notCalled).toBeTruthy();

input.focus();
input.blur();
expect(input).not.toHaveFocus();
expect(checkboxIcon).not.toHaveClass('Checkbox__overlay--focused');
expect(onBlur.calledOnce).toBeTruthy();
});

test('should handle onChange correctly', async () => {
const user = userEvent.setup();
const onChange = spy();
const input = renderCheckbox({ onChange });

expect(onChange.notCalled).toBeTruthy();
await user.click(input);
expect(onChange.calledOnce).toBeTruthy();
});

test('should support ref prop', () => {
const ref = createRef<HTMLInputElement>();
render(<Checkbox id="id" label="checkbox" ref={ref} />);
expect(ref.current).toBeInstanceOf(HTMLInputElement);
expect(ref.current).toEqual(
screen.queryByRole('checkbox', { name: 'checkbox' })
);
});

test('should support checkboxRef prop', () => {
const ref = createRef<HTMLInputElement>();
render(<Checkbox id="id" label="checkbox" checkboxRef={ref} />);
expect(ref.current).toBeInstanceOf(HTMLInputElement);
expect(ref.current).toEqual(
screen.queryByRole('checkbox', { name: 'checkbox' })
);
});

test('should support className prop', () => {
const input = renderCheckbox({ className: 'banana' });
expect(input.parentElement).toHaveClass('Checkbox', 'banana');
});

test('should support value prop', () => {
render(
<form data-testid="form">
<Checkbox id="id-1" name="checkbox" label="checkbox" value="apples" />
<Checkbox
id="id-2"
name="checkbox"
label="checkbox"
value="bananas"
checked
/>
</form>
);
const form = screen.getByTestId('form');
expect(form).toHaveFormValues({ checkbox: ['bananas'] });
});

test('should support labelDescription prop', () => {
const input = renderCheckbox({
labelDescription: 'more stuff and things you should know'
});
expect(input).toHaveAccessibleDescription(
/more stuff and things you should know/
);
expect(
screen.queryByText('more stuff and things you should know')
).toBeInTheDocument();
});

test('should have no axe violations with unchecked checkbox', async () => {
const input = renderCheckbox();
const results = await axe(input);
expect(results).toHaveNoViolations();
});

test('should have no axe violations with checked checkbox', async () => {
const input = renderCheckbox({ checked: true });
const results = await axe(input);
expect(results).toHaveNoViolations();
});

test('should have no axe violations with disabled checkbox', async () => {
const input = renderCheckbox({ disabled: true });
const results = await axe(input);
expect(results).toHaveNoViolations();
});

test('should have no axe violations when checkbox has errors', async () => {
const input = renderCheckbox({ error: 'you should check this checkbox' });
const results = await axe(input);
expect(results).toHaveNoViolations();
});
5 changes: 5 additions & 0 deletions packages/react/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1789,6 +1789,11 @@
"@babel/runtime" "^7.12.1"
"@testing-library/dom" "^7.26.6"

"@testing-library/user-event@^14.5.2":
version "14.5.2"
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.2.tgz#db7257d727c891905947bd1c1a99da20e03c2ebd"
integrity sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==

"@tootallnate/once@2":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
Expand Down

0 comments on commit f6a8495

Please sign in to comment.