-
Notifications
You must be signed in to change notification settings - Fork 72
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -102,6 +102,7 @@ function FormAutosuggest({ | |||||||||||||||
const iconToggle = ( | ||||||||||||||||
<IconButton | ||||||||||||||||
className="pgn__form-autosuggest__icon-button" | ||||||||||||||||
data-testid="autosuggest_iconbutton" | ||||||||||||||||
src={isMenuClosed ? KeyboardArrowDown : KeyboardArrowUp} | ||||||||||||||||
iconAs={Icon} | ||||||||||||||||
size="sm" | ||||||||||||||||
|
@@ -230,6 +231,7 @@ function FormAutosuggest({ | |||||||||||||||
onChange={handleOnChange} | ||||||||||||||||
onClick={handleClick} | ||||||||||||||||
trailingElement={iconToggle} | ||||||||||||||||
data-testid="autosuggest_textbox_input" | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
{...props} | ||||||||||||||||
/> | ||||||||||||||||
|
||||||||||||||||
|
@@ -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" /> | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe more readable
Suggested change
|
||||||||||||||||
</div> | ||||||||||||||||
) : state.dropDownItems.length > 0 && state.dropDownItems} | ||||||||||||||||
</ul> | ||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -12,8 +12,9 @@ function FormAutosuggestOption({ | |||||
return ( | ||||||
<MenuItem | ||||||
as="li" | ||||||
data-testid="autosuggest_optionitem" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
role="option" | ||||||
tabindex="-1" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch! |
||||||
tabIndex="-1" | ||||||
onClick={onClick} | ||||||
className={classNames(className, 'dropdown-item')} | ||||||
{...props} | ||||||
|
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'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it better to move this line to |
||
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={{}}> | ||
|
@@ -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); | ||
}); | ||
}); |
There was a problem hiding this comment.
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