Skip to content

Commit

Permalink
feat: #1792 Migrate 'components/Inputs/' tests to React Testing Libra…
Browse files Browse the repository at this point in the history
…ry (#1891)

* [1792] migrate InputCheckbox tests to rtl, add afterEach to reset spy

* [1792] migrate InputCheckboxGroup tests to use RTL, reset spy afterEach, remove unused act; fix hasError test prop; add more detailed hasError prop flow type

* [1792] migrate InputError tests to use RTL

* [1792] migrate InputLabel tests to use RTL

* [1792] migrate InputLocation tests to use RTL

* [1792] migrate InputRadioGroup tests to use RTL, remove unused beforeEach spy on window.alert

* [1792] migrate InputSelect tests to use RTL; add further tests; add afterEach to reset spy

* [1792] migrate InputSubmit tests to use RTL, add further tests, add afterEach to reset spy

* [1792] migrate InputTag tests to use RTL

* replace InputSwitch deprecated keypress handler with keydown, migrate spec to RTL, minor: remove unused type prop

* [1792] minor: replace deprecated InputTag keypress; minor version update for RTL; comment InputSwitch keyDown test

* [1792] migrate InputDefault tests to use RTL

* [1792] migrate InputPassword tests to use RTL

* [1792] migrate Input.spec.jsx tests to use RTL

* [1792] add InputTextarea tests using RTL

* [1792] small input tests cleanups

* [1792] code review updates: refine checkbox group assertions, cleanup test cleanup
  • Loading branch information
udayanshevade authored Oct 10, 2020
1 parent 62d1a6a commit c2aadce
Show file tree
Hide file tree
Showing 19 changed files with 567 additions and 288 deletions.
2 changes: 1 addition & 1 deletion client/app/components/Input/InputCheckboxGroup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { Checkbox } from './utils';
export type Props = {
checkboxes: Checkbox[],
required?: boolean, // At least one checkbox must be checked
hasError?: Function,
hasError?: (errorPresent: boolean) => void,
};

export function InputCheckboxGroup({
Expand Down
5 changes: 2 additions & 3 deletions client/app/components/Input/InputSwitch.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function InputSwitch({
setKey(Utils.randomString());
};

const onKeyPress = (e: SyntheticKeyboardEvent<HTMLInputElement>) => {
const onKeyDown = (e: SyntheticKeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
toggleChecked();
}
Expand All @@ -48,7 +48,6 @@ export function InputSwitch({
<InputCheckbox
id={id}
key={key}
type="checkbox"
name={name}
label={label}
value={value}
Expand All @@ -70,7 +69,7 @@ export function InputSwitch({
id={`${id}_switch`}
className={`switchToggle ${css.switchToggle}`}
onClick={toggleChecked}
onKeyPress={onKeyPress}
onKeyDown={onKeyDown}
role="switch"
aria-checked={checked}
tabIndex={0}
Expand Down
4 changes: 2 additions & 2 deletions client/app/components/Input/InputTag.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export function InputTag({

const shouldRenderSuggestions = () => true;

const onKeyPress = (e: SyntheticKeyboardEvent<HTMLInputElement>) => {
const onKeyDown = (e: SyntheticKeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter' && onChange) {
e.preventDefault();
onChange({ label: autocompleteLabel, checkboxes });
Expand Down Expand Up @@ -156,7 +156,7 @@ export function InputTag({
onChange: onAutocompleteChange,
value: autocompleteLabel || '',
className: `tagAutocomplete ${inputCss.tagAutocomplete}`,
onKeyPress,
onKeyDown,
placeholder,
}}
/>
Expand Down
146 changes: 85 additions & 61 deletions client/app/components/Input/__tests__/Input.spec.jsx
Original file line number Diff line number Diff line change
@@ -1,119 +1,143 @@
// @flow
import { mount } from 'enzyme';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { InputMocks } from 'mocks/InputMocks';
import css from '../Input.scss';

/**
* TODO: Follow up on an issue when using the matcher `.toBeVisible()` on the inputs directly.
* The components behave correctly, but the computed styles don't seem to correspond.
* Even if the accordion is closed, and uses the class 'accordionClose', the actual style returns
* a visible value for the 'display' property, as opposed to the expected value 'none'.
* This is also seen with the helper `.toHaveStyle()` (in @testing-library/[email protected]).
* For now, checking whether div["role='region'"] from Accordion has the class 'accordionClose'.
*/

describe('Input', () => {
describe('InputDefault', () => {
describe('with accordion prop', () => {
it('toggles correctly', () => {
const wrapper = mount(
const { label } = InputMocks.inputTextProps;
render(
InputMocks.createInput(InputMocks.inputTextProps, {
accordion: true,
}),
);
expect(
wrapper.find('.accordionContent').find('input').exists(),
).toEqual(false);
wrapper.find('.accordion').simulate('click');
expect(
wrapper.find('.accordionContent').find('input').exists(),
).toEqual(true);
wrapper.find('.accordion').simulate('click');
expect(
wrapper.find('.accordionContent').find('input').exists(),
).toEqual(false);

const input = screen.getByRole('textbox');
const button = screen.getByRole('button', { name: new RegExp(label) });
const accordionContainer = screen.getByRole('region');

expect(input).toBeInTheDocument();

expect(accordionContainer).toHaveClass(css.accordionClose);
userEvent.click(button);
expect(accordionContainer).not.toHaveClass(css.accordionClose);
userEvent.click(button);
expect(accordionContainer).toHaveClass(css.accordionClose);
});
});
});

describe('CheckboxGroup', () => {
describe('with accordion prop', () => {
it('toggles correctly', () => {
const wrapper = mount(
const {
label: groupLabel,
checkboxes: [{ label }],
} = InputMocks.inputCheckboxGroupProps;
render(
InputMocks.createInput(InputMocks.inputCheckboxGroupProps, {
accordion: true,
}),
);
expect(
wrapper.find('.accordionContent').find('input').exists(),
).toEqual(false);
wrapper.find('.accordion').simulate('click');
expect(
wrapper.find('.accordionContent').find('input').exists(),
).toEqual(true);
wrapper.find('.accordion').simulate('click');
expect(
wrapper.find('.accordionContent').find('input').exists(),
).toEqual(false);

const checkbox = screen.getByRole('checkbox', { name: label });
const button = screen.getByRole('button', { name: groupLabel });
const accordionContainer = screen.getByRole('region');

expect(checkbox).toBeInTheDocument();

expect(accordionContainer).toHaveClass(css.accordionClose);
userEvent.click(button);
expect(accordionContainer).not.toHaveClass(css.accordionClose);
userEvent.click(button);
expect(accordionContainer).toHaveClass(css.accordionClose);
});
});
});

describe('Select', () => {
describe('with accordion prop', () => {
it('toggles correctly', () => {
const wrapper = mount(
const { label } = InputMocks.inputSelectProps;
render(
InputMocks.createInput(InputMocks.inputSelectProps, {
accordion: true,
}),
);
expect(
wrapper.find('.accordionContent').find('select').exists(),
).toEqual(false);
wrapper.find('.accordion').simulate('click');
expect(
wrapper.find('.accordionContent').find('select').exists(),
).toEqual(true);
wrapper.find('.accordion').simulate('click');
expect(
wrapper.find('.accordionContent').find('select').exists(),
).toEqual(false);

const combobox = screen.getByRole('combobox');
const button = screen.getByRole('button', { name: label });
const accordionContainer = screen.getByRole('region');

expect(combobox).toBeInTheDocument();

expect(accordionContainer).toHaveClass(css.accordionClose);
userEvent.click(button);
expect(accordionContainer).not.toHaveClass(css.accordionClose);
userEvent.click(button);
expect(accordionContainer).toHaveClass(css.accordionClose);
});
});
});

describe('Tag', () => {
describe('with accordion prop', () => {
it('toggles correctly', () => {
const wrapper = mount(
const { label } = InputMocks.inputTagProps;
render(
InputMocks.createInput(InputMocks.inputTagProps, {
accordion: true,
}),
);
expect(
wrapper.find('.accordionContent').find('input').exists(),
).toEqual(false);
wrapper.find('.accordion').simulate('click');
expect(
wrapper.find('.accordionContent').find('input').exists(),
).toEqual(true);
wrapper.find('.accordion').simulate('click');
expect(
wrapper.find('.accordionContent').find('input').exists(),
).toEqual(false);

const combobox = screen.getByRole('combobox');
const button = screen.getByRole('button', { name: new RegExp(label) });
const accordionContainer = screen.getByRole('region');

expect(combobox).toBeInTheDocument();

expect(accordionContainer).toHaveClass(css.accordionClose);
userEvent.click(button);
expect(accordionContainer).not.toHaveClass(css.accordionClose);
userEvent.click(button);
expect(accordionContainer).toHaveClass(css.accordionClose);
});
});
});

describe('Switch', () => {
describe('with accordion prop', () => {
it('toggles correctly', () => {
const wrapper = mount(
const { label } = InputMocks.inputSwitchProps;
render(
InputMocks.createInput(InputMocks.inputSwitchProps, {
accordion: true,
}),
);
expect(
wrapper.find('.accordionContent').find('.switch').exists(),
).toEqual(false);
wrapper.find('.accordion').simulate('click');
expect(
wrapper.find('.accordionContent').find('.switch').exists(),
).toEqual(true);
wrapper.find('.accordion').simulate('click');
expect(
wrapper.find('.accordionContent').find('.switch').exists(),
).toEqual(false);

const switchInput = screen.getByRole('switch');
const button = screen.getByRole('button', { name: new RegExp(label) });
const accordionContainer = screen.getByRole('region');

expect(switchInput).toBeInTheDocument();

expect(accordionContainer).toHaveClass(css.accordionClose);
userEvent.click(button);
expect(accordionContainer).not.toHaveClass(css.accordionClose);
userEvent.click(button);
expect(accordionContainer).toHaveClass(css.accordionClose);
});
});
});
Expand Down
47 changes: 25 additions & 22 deletions client/app/components/Input/__tests__/InputCheckbox.spec.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @flow
import { shallow } from 'enzyme';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { InputCheckbox } from 'components/Input/InputCheckbox';

Expand All @@ -18,9 +19,13 @@ describe('InputCheckbox', () => {
jest.spyOn(window, 'alert');
});

afterEach(() => {
jest.clearAllMocks();
});

describe('has no uncheckedValue prop', () => {
it('toggles checkbox correctly', () => {
const wrapper = shallow(
render(
<InputCheckbox
id={id}
name={name}
Expand All @@ -31,21 +36,18 @@ describe('InputCheckbox', () => {
onChange={someEvent}
/>,
);
expect(wrapper.find('input').props().value).toEqual(value);
wrapper
.find('input')
.simulate('change', { currentTarget: { checked: false } });
const checkbox = screen.getByRole('checkbox', { name: label });
expect(checkbox).toBeChecked();
userEvent.click(checkbox);
expect(window.alert).toHaveBeenCalledWith('Checkbox some-id is false');
wrapper
.find('input')
.simulate('change', { currentTarget: { checked: true } });
userEvent.click(checkbox);
expect(window.alert).toHaveBeenCalledWith('Checkbox some-id is true');
});
});

describe('has a uncheckedValue prop', () => {
it('toggles checkbox correctly', () => {
const wrapper = shallow(
const { container } = render(
<InputCheckbox
id={id}
name={name}
Expand All @@ -57,19 +59,20 @@ describe('InputCheckbox', () => {
onChange={someEvent}
/>,
);
expect(wrapper.find('input[type="hidden"]').props().value).toEqual(
uncheckedValue,
);
expect(wrapper.find('input[type="checkbox"]').props().value).toEqual(
value,
);
wrapper
.find('input[type="checkbox"]')
.simulate('change', { currentTarget: { checked: false } });

// ensures the input for the uncheckedValue is hidden
expect(screen.queryByRole('input')).not.toBeInTheDocument();
// Since '@testing-library/react' does not get hidden inputs,
// it can be queried directly from the container for this test.
const hiddenInput = container.querySelector('input[type="hidden"]');
expect(hiddenInput).toHaveValue(uncheckedValue);

// validates checkbox behavior
const checkbox = screen.getByRole('checkbox', { name: label });
expect(checkbox).toBeChecked();
userEvent.click(checkbox);
expect(window.alert).toHaveBeenCalledWith('Checkbox some-id is false');
wrapper
.find('input[type="checkbox"]')
.simulate('change', { currentTarget: { checked: true } });
userEvent.click(checkbox);
expect(window.alert).toHaveBeenCalledWith('Checkbox some-id is true');
});
});
Expand Down
Loading

0 comments on commit c2aadce

Please sign in to comment.