Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: move autosuggest tests from Enzyme to RTL #2611

Merged
merged 1 commit into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/Form/FormAutosuggest.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ function FormAutosuggest({
const iconToggle = (
<IconButton
className="pgn__form-autosuggest__icon-button"
data-testid="autosuggest_iconbutton"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We recently rewrote all tests (except FormAutosuggest) to RTL. For uniformity of test identifiers, we agreed to use a kebab case. Can you convert the names of the identifiers to a uniform format? autosuggest-iconbutton

src={isMenuClosed ? KeyboardArrowDown : KeyboardArrowUp}
iconAs={Icon}
size="sm"
Expand Down Expand Up @@ -230,6 +231,7 @@ function FormAutosuggest({
onChange={handleOnChange}
onClick={handleClick}
trailingElement={iconToggle}
data-testid="autosuggest_textbox_input"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
data-testid="autosuggest_textbox_input"
data-testid="autosuggest-textbox-input"

{...props}
/>

Expand All @@ -253,7 +255,7 @@ function FormAutosuggest({
>
{isLoading ? (
<div className="pgn__form-autosuggest__dropdown-loading">
<Spinner animation="border" variant="dark" screenReaderText={screenReaderText} />
<Spinner animation="border" variant="dark" screenReaderText={screenReaderText} data-testid="autosuggest_loading_spinner" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe more readable

Suggested change
<Spinner animation="border" variant="dark" screenReaderText={screenReaderText} data-testid="autosuggest_loading_spinner" />
<Spinner
animation="border"
variant="dark"
screenReaderText={screenReaderText}
data-testid="autosuggest-loading-spinner"
/>

</div>
) : state.dropDownItems.length > 0 && state.dropDownItems}
</ul>
Expand Down
3 changes: 2 additions & 1 deletion src/Form/FormAutosuggestOption.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ function FormAutosuggestOption({
return (
<MenuItem
as="li"
data-testid="autosuggest_optionitem"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
data-testid="autosuggest_optionitem"
data-testid="autosuggest-optionitem"

role="option"
tabindex="-1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch!

tabIndex="-1"
onClick={onClick}
className={classNames(className, 'dropdown-item')}
{...props}
Expand Down
245 changes: 135 additions & 110 deletions src/Form/tests/FormAutosuggest.test.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
import React from 'react';
import { mount } from 'enzyme';
import { act } from 'react-dom/test-utils';
import PropTypes from 'prop-types';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it better to move this line to setupTests.js? Did you encounter some problems with this?

import { IntlProvider } from 'react-intl';
import FormAutosuggest from '../FormAutosuggest';
import FormAutosuggestOption from '../FormAutosuggestOption';

const createDocumentListenersMock = () => {
const listeners = {};
const handler = (domEl, e) => listeners?.[e]?.({ target: domEl });

document.addEventListener = jest.fn((e, fn) => { listeners[e] = fn; });
document.removeEventListener = jest.fn(e => { delete listeners[e]; });

return {
click: domEl => handler(domEl, 'click'),
};
};

function FormAutosuggestWrapper(props) {
return (
<IntlProvider locale="en" messages={{}}>
Expand All @@ -25,141 +15,176 @@ function FormAutosuggestWrapper(props) {
);
}

describe('FormAutosuggest', () => {
afterEach(() => {
jest.clearAllMocks();
});

const onSelected = jest.fn();
const onClick = jest.fn();

const container = mount(
function FormAutosuggestTestComponent(props) {
return (
<FormAutosuggestWrapper
name="FormAutosuggest"
floatingLabel="floatingLabel text"
helpMessage="Example help message"
errorMessageText="Example error message"
onSelected={onSelected}
onSelected={props.onSelected}
>
<FormAutosuggestOption>Option 1</FormAutosuggestOption>
<FormAutosuggestOption onClick={onClick}>Option 2</FormAutosuggestOption>
<FormAutosuggestOption onClick={props.onClick}>Option 2</FormAutosuggestOption>
<FormAutosuggestOption>Learn from more than 160 member universities</FormAutosuggestOption>
</FormAutosuggestWrapper>,
</FormAutosuggestWrapper>
);
}

FormAutosuggestTestComponent.defaultProps = {
onSelected: jest.fn(),
onClick: jest.fn(),
};

FormAutosuggestTestComponent.propTypes = {
/** Specifies onSelected event handler. */
onSelected: PropTypes.func,
/** Specifies onClick event handler. */
onClick: PropTypes.func,
};

describe('render behavior', () => {
it('renders component without error', () => {
render(<FormAutosuggestWrapper />);
});

describe('render behavior', () => {
it('renders component without error', () => {
mount(<FormAutosuggestWrapper />);
});
it('renders without loading state', () => {
const { queryByTestId } = render(<FormAutosuggestTestComponent />);
const spinner = queryByTestId('autosuggest_loading_spinner');
expect(spinner).not.toBeInTheDocument();
});

it('render with loading state', () => {
const { queryByTestId } = render(<FormAutosuggestWrapper isLoading />);
const spinner = queryByTestId('autosuggest_loading_spinner');
expect(spinner).toBeInTheDocument();
});

it('render without loading state', () => {
expect(container.exists('.pgn__form-autosuggest__dropdown-loading')).toBe(false);
expect(container.props().isLoading).toBeUndefined();
});
it('renders the auto-populated value if it exists', () => {
render(<FormAutosuggestWrapper value="Test Value" />);
expect(screen.getByDisplayValue('Test Value')).toBeInTheDocument();
});

it('render with loading state', () => {
const wrapper = mount(<FormAutosuggestWrapper isLoading />);
it('renders component with options', () => {
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
const input = getByTestId('autosuggest_textbox_input');
userEvent.click(input);
const list = queryAllByTestId('autosuggest_optionitem');
expect(list.length).toBe(3);
});

expect(wrapper.exists('.pgn__form-autosuggest__dropdown-loading')).toBe(true);
expect(wrapper.props().isLoading).toBe(true);
});
it('renders with error msg', () => {
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent />);
const input = getByTestId('autosuggest_textbox_input');

it('renders the auto-populated value if it exists', () => {
const wrapper = mount(<FormAutosuggestWrapper value="Test Value" />);
// if you click into the input and click outside, you should see the error message
userEvent.click(input);
userEvent.click(document.body);

expect(wrapper.find('input').instance().value).toEqual('Test Value');
expect(wrapper.props().value).toEqual('Test Value');
});
const formControlFeedback = getByText('Example error message');

it('renders component with options', () => {
container.find('input').simulate('click');
const optionsList = container.find('.pgn__form-autosuggest__dropdown').find('li');
expect(formControlFeedback).toBeInTheDocument();
});
});

expect(optionsList.length).toEqual(3);
});
describe('controlled behavior', () => {
it('sets input value based on clicked option', () => {
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent />);
const input = getByTestId('autosuggest_textbox_input');

it('renders with error msg', () => {
container.find('input').simulate('click');
act(() => {
const event = new Event('click', { bubbles: true });
document.dispatchEvent(event);
});
container.update();
const formControlFeedback = container.find('FormControlFeedback');
userEvent.click(input);
const menuItem = getByText('Option 1');
userEvent.click(menuItem);

expect(formControlFeedback.text()).toEqual('Example error message');
});
expect(input.value).toEqual('Option 1');
});

describe('controlled behavior', () => {
it('selects option', () => {
container.find('input').simulate('click');
container.find('.pgn__form-autosuggest__dropdown').find('li')
.at(0).simulate('click');
it('calls onSelected based on clicked option', () => {
const onSelected = jest.fn();
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent onSelected={onSelected} />);
const input = getByTestId('autosuggest_textbox_input');

expect(container.find('input').instance().value).toEqual('Option 1');
expect(onSelected).toHaveBeenCalledWith('Option 1');
expect(onSelected).toHaveBeenCalledTimes(1);
});
userEvent.click(input);
const menuItem = getByText('Option 1');
userEvent.click(menuItem);

it('when a function is passed to onClick, it is called', () => {
container.find('input').simulate('change', { target: { value: 'Option 2' } });
container.find('.pgn__form-autosuggest__dropdown').find('li')
.at(0).simulate('click');
expect(onSelected).toHaveBeenCalledWith('Option 1');
expect(onSelected).toHaveBeenCalledTimes(1);
});

expect(onClick).toHaveBeenCalledTimes(1);
});
it('calls the function passed to onClick when an option with it is selected', () => {
const onClick = jest.fn();
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent onClick={onClick} />);
const input = getByTestId('autosuggest_textbox_input');

it('when a function is not passed to onClick, it is not called', () => {
container.find('input').simulate('change', { target: { value: 'Option 1' } });
container.find('.pgn__form-autosuggest__dropdown').find('li')
.at(0).simulate('click');
userEvent.click(input);
const menuItem = getByText('Option 2');
userEvent.click(menuItem);

expect(onClick).toHaveBeenCalledTimes(0);
});
expect(onClick).toHaveBeenCalledTimes(1);
});

it('options list depends on empty field value', () => {
container.find('input').simulate('change', { target: { value: '' } });
it('does not call onClick when an option without it is selected', () => {
const onClick = jest.fn();
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent onClick={onClick} />);
const input = getByTestId('autosuggest_textbox_input');

expect(container.find('input').instance().value).toEqual('');
});
userEvent.click(input);
const menuItem = getByText('Option 1');
userEvent.click(menuItem);

it('options list depends on filled field value', () => {
container.find('input').simulate('change', { target: { value: 'option 1' } });
expect(onClick).toHaveBeenCalledTimes(0);
});

expect(container.find('.pgn__form-autosuggest__dropdown').find('li').length).toEqual(1);
expect(onSelected).toHaveBeenCalledTimes(0);
});
it('filters dropdown based on typed field value with one match', () => {
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
const input = getByTestId('autosuggest_textbox_input');

it('toggles options list', () => {
const dropdownContainer = '.pgn__form-autosuggest__dropdown';
userEvent.click(input);
userEvent.type(input, 'Option 1');

expect(container.find(dropdownContainer).find('li').length).toEqual(1);
const list = queryAllByTestId('autosuggest_optionitem');
expect(list.length).toBe(1);
});

container.find('button.pgn__form-autosuggest__icon-button').simulate('click');
expect(container.find(dropdownContainer).find('li').length).toEqual(0);
it('toggles options list', () => {
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
const dropdownBtn = getByTestId('autosuggest_iconbutton');

container.find('button.pgn__form-autosuggest__icon-button').simulate('click');
expect(container.find(dropdownContainer).find('li').length).toEqual(1);
});
userEvent.click(dropdownBtn);
const list = queryAllByTestId('autosuggest_optionitem');
expect(list.length).toBe(3);

it('shows options list depends on field value', () => {
container.find('input').simulate('change', { target: { value: '1' } });
userEvent.click(dropdownBtn);
const updatedList = queryAllByTestId('autosuggest_optionitem');
expect(updatedList.length).toBe(0);

expect(container.find('.pgn__form-autosuggest__dropdown').find('li').length).toEqual(2);
});
userEvent.click(dropdownBtn);
const reopenedList = queryAllByTestId('autosuggest_optionitem');
expect(reopenedList.length).toBe(3);
});

it('closes options list on click outside', () => {
const fireEvent = createDocumentListenersMock();
const dropdownContainer = '.pgn__form-autosuggest__dropdown';
it('filters dropdown based on typed field value with multiple matches', () => {
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
const input = getByTestId('autosuggest_textbox_input');

userEvent.click(input);
userEvent.type(input, '1');

const list = queryAllByTestId('autosuggest_optionitem');
expect(list.length).toBe(2);
});

container.find('input').simulate('click');
expect(container.find(dropdownContainer).find('li').length).toEqual(2);
it('closes options list on click outside', () => {
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
const input = getByTestId('autosuggest_textbox_input');

act(() => { fireEvent.click(document.body); });
container.update();
userEvent.click(input);
const list = queryAllByTestId('autosuggest_optionitem');
expect(list.length).toBe(3);

expect(container.find(dropdownContainer).find('li').length).toEqual(0);
});
userEvent.click(document.body);
const updatedList = queryAllByTestId('autosuggest_optionitem');
expect(updatedList.length).toBe(0);
});
});
Loading