mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
686 lines
26 KiB
TypeScript
686 lines
26 KiB
TypeScript
import {useEffect} from 'react';
|
|
|
|
import {fireEvent, render, screen, waitFor} from 'sentry-test/reactTestingLibrary';
|
|
|
|
import type {AutoCompleteProps} from 'sentry/components/autoComplete';
|
|
import AutoComplete from 'sentry/components/autoComplete';
|
|
|
|
const items = [
|
|
{
|
|
name: 'Apple',
|
|
},
|
|
{
|
|
name: 'Pineapple',
|
|
},
|
|
{
|
|
name: 'Orange',
|
|
},
|
|
];
|
|
|
|
/**
|
|
* For every render, we push all injected params into `autoCompleteState`, we probably want to
|
|
* assert against those instead of the wrapper's state since component state will be different if we have
|
|
* "controlled" props where <AutoComplete> does not handle state
|
|
*/
|
|
describe('AutoComplete', function () {
|
|
let input;
|
|
let autoCompleteState: any[] = [];
|
|
const mocks = {
|
|
onSelect: jest.fn(),
|
|
onClose: jest.fn(),
|
|
onOpen: jest.fn(),
|
|
};
|
|
|
|
afterEach(() => {
|
|
jest.resetAllMocks();
|
|
autoCompleteState = [];
|
|
});
|
|
|
|
function List({registerItemCount, itemCount, ...props}) {
|
|
useEffect(() => void registerItemCount(itemCount), [itemCount, registerItemCount]);
|
|
return <ul {...props} />;
|
|
}
|
|
|
|
function Item({registerVisibleItem, item, index, ...props}) {
|
|
useEffect(() => registerVisibleItem(index, item), [registerVisibleItem, index, item]);
|
|
return <li {...props} />;
|
|
}
|
|
|
|
const createComponent = (props: Partial<AutoCompleteProps<any>>) => (
|
|
<AutoComplete {...mocks} itemToString={item => item.name} {...props}>
|
|
{injectedProps => {
|
|
const {
|
|
getRootProps,
|
|
getInputProps,
|
|
getMenuProps,
|
|
getItemProps,
|
|
inputValue,
|
|
isOpen,
|
|
registerItemCount,
|
|
registerVisibleItem,
|
|
highlightedIndex,
|
|
} = injectedProps;
|
|
|
|
// This is purely for testing
|
|
autoCompleteState.push(injectedProps);
|
|
|
|
const filteredItems = items.filter(item =>
|
|
item.name.toLowerCase().includes(inputValue.toLowerCase())
|
|
);
|
|
|
|
return (
|
|
<div {...getRootProps()}>
|
|
<input placeholder="autocomplete" {...getInputProps({})} />
|
|
|
|
{isOpen && (
|
|
<div {...getMenuProps()} data-test-id="test-autocomplete">
|
|
<List
|
|
registerItemCount={registerItemCount}
|
|
itemCount={filteredItems.length}
|
|
>
|
|
{filteredItems.map((item, index) => (
|
|
<Item
|
|
key={item.name}
|
|
registerVisibleItem={registerVisibleItem}
|
|
index={index}
|
|
item={item}
|
|
aria-selected={highlightedIndex === index}
|
|
{...getItemProps({item, index})}
|
|
>
|
|
{item.name}
|
|
</Item>
|
|
))}
|
|
</List>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}}
|
|
</AutoComplete>
|
|
);
|
|
|
|
const createWrapper = (props?: any) => {
|
|
const wrapper = render(createComponent(props));
|
|
input = screen.getByPlaceholderText('autocomplete');
|
|
return wrapper;
|
|
};
|
|
|
|
describe('Uncontrolled', function () {
|
|
it('shows dropdown menu when input has focus', function () {
|
|
createWrapper();
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
for (const item of items) {
|
|
expect(screen.getByText(item.name)).toBeInTheDocument();
|
|
}
|
|
});
|
|
|
|
it('only tries to close once if input is blurred and click outside occurs', async function () {
|
|
createWrapper();
|
|
jest.useFakeTimers();
|
|
fireEvent.focus(input);
|
|
fireEvent.blur(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
// Click outside dropdown
|
|
fireEvent.click(document.body);
|
|
jest.runAllTimers();
|
|
|
|
await waitFor(() => expect(mocks.onClose).toHaveBeenCalledTimes(1));
|
|
});
|
|
|
|
it('only calls onClose dropdown menu when input is blurred', function () {
|
|
createWrapper();
|
|
jest.useFakeTimers();
|
|
fireEvent.focus(input);
|
|
fireEvent.blur(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
jest.runAllTimers();
|
|
|
|
expect(screen.queryByTestId('test-autocomplete')).not.toBeInTheDocument();
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('can close dropdown menu when Escape is pressed', function () {
|
|
createWrapper();
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.keyDown(input, {key: 'Escape', charCode: 27});
|
|
expect(screen.queryByTestId('test-autocomplete')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('can open and close dropdown menu using injected actions', function () {
|
|
createWrapper();
|
|
const [injectedProps] = autoCompleteState;
|
|
injectedProps.actions.open();
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
expect(mocks.onOpen).toHaveBeenCalledTimes(1);
|
|
|
|
injectedProps.actions.close();
|
|
expect(screen.queryByTestId('test-autocomplete')).not.toBeInTheDocument();
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('reopens dropdown menu after Escape is pressed and input is changed', function () {
|
|
createWrapper();
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.keyDown(input, {key: 'Escape', charCode: 27});
|
|
expect(screen.queryByTestId('test-autocomplete')).not.toBeInTheDocument();
|
|
|
|
fireEvent.change(input, {target: {value: 'a', charCode: 65}});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
});
|
|
|
|
it('reopens dropdown menu after item is selected and then input is changed', function () {
|
|
createWrapper();
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.change(input, {target: {value: 'eapp'}});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(screen.getByRole('option')).toBeInTheDocument();
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
expect(screen.queryByTestId('test-autocomplete')).not.toBeInTheDocument();
|
|
|
|
fireEvent.change(input, {target: {value: 'app'}});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(screen.getAllByRole('option')).toHaveLength(2);
|
|
});
|
|
|
|
it('selects dropdown item by clicking and sets input to selected value', function () {
|
|
createWrapper();
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
|
|
fireEvent.click(screen.getByText(items[1].name));
|
|
expect(mocks.onSelect).toHaveBeenCalledWith(
|
|
items[1],
|
|
expect.objectContaining({inputValue: '', highlightedIndex: 0}),
|
|
expect.anything()
|
|
);
|
|
|
|
expect(input).toHaveValue('Pineapple');
|
|
expect(screen.queryByRole('option')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('can navigate dropdown items with keyboard and select with "Enter" keypress', function () {
|
|
createWrapper();
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Orange')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
|
|
expect(mocks.onSelect).toHaveBeenCalledWith(
|
|
items[2],
|
|
expect.objectContaining({inputValue: '', highlightedIndex: 2}),
|
|
expect.anything()
|
|
);
|
|
expect(screen.queryByRole('option')).not.toBeInTheDocument();
|
|
expect(input).toHaveValue('Orange');
|
|
});
|
|
|
|
it('respects list bounds when navigating filtered items with arrow keys', function () {
|
|
createWrapper();
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowUp', charCode: 38});
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Orange')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Orange')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowUp', charCode: 38});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowUp', charCode: 38});
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowUp', charCode: 38});
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
});
|
|
|
|
it('can filter items and then navigate with keyboard', function () {
|
|
createWrapper();
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
|
|
fireEvent.keyDown(input, {target: {value: 'a', charCode: 65}});
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
expect(input).toHaveValue('a');
|
|
// Apple, pineapple, orange
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
|
|
fireEvent.change(input, {target: {value: 'ap'}});
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
expect(input).toHaveValue('ap');
|
|
expect(autoCompleteState[autoCompleteState.length - 1].inputValue).toBe('ap');
|
|
// Apple, pineapple
|
|
expect(screen.getAllByRole('option')).toHaveLength(2);
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
expect(screen.getAllByRole('option')).toHaveLength(2);
|
|
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
expect(mocks.onSelect).toHaveBeenCalledWith(
|
|
items[1],
|
|
expect.objectContaining({inputValue: 'ap', highlightedIndex: 1}),
|
|
expect.anything()
|
|
);
|
|
expect(screen.queryByRole('option')).not.toBeInTheDocument();
|
|
expect(input).toHaveValue('Pineapple');
|
|
});
|
|
|
|
it('can reset input when menu closes', function () {
|
|
const wrapper = createWrapper();
|
|
jest.useFakeTimers();
|
|
wrapper.rerender(createComponent({resetInputOnClose: true}));
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.keyDown(input, {target: {value: 'a', charCode: 65}});
|
|
expect(input).toHaveValue('a');
|
|
|
|
fireEvent.blur(input);
|
|
jest.runAllTimers();
|
|
expect(screen.queryByTestId('test-autocomplete')).not.toBeInTheDocument();
|
|
expect(input).toHaveValue('');
|
|
});
|
|
});
|
|
|
|
describe('isOpen controlled', function () {
|
|
it('has dropdown menu initially open', function () {
|
|
createWrapper({isOpen: true});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
});
|
|
|
|
it('closes when props change', function () {
|
|
const wrapper = createWrapper({isOpen: true});
|
|
wrapper.rerender(createComponent({isOpen: false}));
|
|
|
|
// Menu should be closed
|
|
expect(screen.queryByTestId('test-autocomplete')).not.toBeInTheDocument();
|
|
expect(screen.queryByRole('option')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('remains closed when input is focused, but calls `onOpen`', function () {
|
|
createWrapper({isOpen: false});
|
|
jest.useFakeTimers();
|
|
|
|
expect(screen.queryByTestId('test-autocomplete')).not.toBeInTheDocument();
|
|
|
|
fireEvent.focus(input);
|
|
jest.runAllTimers();
|
|
expect(screen.queryByTestId('test-autocomplete')).not.toBeInTheDocument();
|
|
expect(screen.queryByRole('option')).not.toBeInTheDocument();
|
|
|
|
expect(mocks.onOpen).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('remains open when input focus/blur events occur, but calls `onClose`', function () {
|
|
createWrapper({isOpen: true});
|
|
jest.useFakeTimers();
|
|
fireEvent.focus(input);
|
|
fireEvent.blur(input);
|
|
jest.runAllTimers();
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
// This still gets called even though menu is open
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('calls onClose when Escape is pressed', function () {
|
|
createWrapper({isOpen: true});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.keyDown(input, {key: 'Escape', charCode: 27});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('does not open and close dropdown menu using injected actions', function () {
|
|
createWrapper({isOpen: true});
|
|
const [injectedProps] = autoCompleteState;
|
|
injectedProps.actions.open();
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(mocks.onOpen).toHaveBeenCalledTimes(1);
|
|
|
|
injectedProps.actions.close();
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('onClose is called after item is selected', function () {
|
|
createWrapper({isOpen: true});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.change(input, {target: {value: 'eapp'}});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(screen.getByRole('option')).toBeInTheDocument();
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('selects dropdown item by clicking and sets input to selected value', function () {
|
|
createWrapper({isOpen: true});
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
|
|
fireEvent.click(screen.getByText(items[1].name));
|
|
expect(mocks.onSelect).toHaveBeenCalledWith(
|
|
items[1],
|
|
expect.objectContaining({inputValue: '', highlightedIndex: 0}),
|
|
expect.anything()
|
|
);
|
|
|
|
expect(input).toHaveValue('Pineapple');
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('can navigate dropdown items with keyboard and select with "Enter" keypress', function () {
|
|
createWrapper({isOpen: true});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Orange')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
|
|
expect(mocks.onSelect).toHaveBeenCalledWith(
|
|
items[2],
|
|
expect.objectContaining({inputValue: '', highlightedIndex: 2}),
|
|
expect.anything()
|
|
);
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
expect(input).toHaveValue('Orange');
|
|
});
|
|
|
|
it('respects list bounds when navigating filtered items with arrow keys', function () {
|
|
createWrapper({isOpen: true});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowUp', charCode: 38});
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Orange')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Orange')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowUp', charCode: 38});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowUp', charCode: 38});
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowUp', charCode: 38});
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
});
|
|
|
|
it('can filter items and then navigate with keyboard', function () {
|
|
createWrapper({isOpen: true});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
|
|
fireEvent.keyDown(input, {target: {value: 'a', charCode: 65}});
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
expect(input).toHaveValue('a');
|
|
// Apple, pineapple, orange
|
|
expect(screen.getAllByRole('option')).toHaveLength(3);
|
|
|
|
fireEvent.change(input, {target: {value: 'ap'}});
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
expect(input).toHaveValue('ap');
|
|
expect(autoCompleteState[autoCompleteState.length - 1].inputValue).toBe('ap');
|
|
// Apple, pineapple
|
|
expect(screen.getAllByRole('option')).toHaveLength(2);
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
expect(screen.getAllByRole('option')).toHaveLength(2);
|
|
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
expect(mocks.onSelect).toHaveBeenCalledWith(
|
|
items[1],
|
|
expect.objectContaining({inputValue: 'ap', highlightedIndex: 1}),
|
|
expect.anything()
|
|
);
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
expect(input).toHaveValue('Pineapple');
|
|
});
|
|
|
|
it('only scrolls highlighted item into view on keyboard events', function () {
|
|
const scrollIntoViewMock = jest.fn();
|
|
Element.prototype.scrollIntoView = scrollIntoViewMock;
|
|
|
|
createWrapper({isOpen: true});
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.mouseEnter(screen.getByText('Pineapple'));
|
|
expect(scrollIntoViewMock).not.toHaveBeenCalled();
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('can reset input value when menu closes', function () {
|
|
const wrapper = createWrapper({isOpen: true});
|
|
jest.useFakeTimers();
|
|
wrapper.rerender(createComponent({resetInputOnClose: true}));
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.keyDown(input, {target: {value: 'a', charCode: 65}});
|
|
expect(input).toHaveValue('a');
|
|
|
|
fireEvent.blur(input);
|
|
jest.runAllTimers();
|
|
expect(input).toHaveValue('');
|
|
});
|
|
});
|
|
|
|
describe('inputValue controlled', () => {
|
|
it('follows the inputValue prop', () => {
|
|
const wrapper = createWrapper({inputValue: 'initial value'});
|
|
expect(input).toHaveValue('initial value');
|
|
|
|
wrapper.rerender(createComponent({inputValue: 'new value'}));
|
|
|
|
expect(input).toHaveValue('new value');
|
|
});
|
|
|
|
it('calls onInputValueChange on input', () => {
|
|
const wrapper = createWrapper({inputValue: 'initial value'});
|
|
const onInputValueChange = jest.fn();
|
|
wrapper.rerender(createComponent({onInputValueChange}));
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.change(input, {target: {value: 'a'}});
|
|
|
|
expect(onInputValueChange).toHaveBeenCalledWith('a');
|
|
});
|
|
|
|
it('input value does not change when typed into', () => {
|
|
createWrapper({inputValue: 'initial value'});
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.change(input, {target: {value: 'a'}});
|
|
expect(input).toHaveValue('initial value');
|
|
});
|
|
|
|
it('input value does not change when blurred', () => {
|
|
createWrapper({inputValue: 'initial value'});
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.blur(input);
|
|
expect(input).toHaveValue('initial value');
|
|
});
|
|
|
|
it('can search for and select an item without changing the input value', () => {
|
|
const wrapper = createWrapper({inputValue: 'initial value'});
|
|
fireEvent.focus(input);
|
|
wrapper.rerender(createComponent({inputValue: 'apple'}));
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(screen.getAllByRole('option')).toHaveLength(2);
|
|
|
|
fireEvent.click(screen.getByText('Apple'));
|
|
|
|
expect(screen.queryByTestId('test-autocomplete')).not.toBeInTheDocument();
|
|
expect(input).toHaveValue('apple');
|
|
expect(mocks.onSelect).toHaveBeenCalledWith(
|
|
{name: 'Apple'},
|
|
expect.anything(),
|
|
expect.anything()
|
|
);
|
|
});
|
|
|
|
it('can filter and navigate dropdown items with keyboard and select with "Enter" keypress without changing input value', function () {
|
|
const wrapper = createWrapper({inputValue: 'initial value'});
|
|
wrapper.rerender(createComponent({inputValue: 'apple'}));
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
expect(screen.getByText('Apple')).toHaveAttribute('aria-selected', 'true');
|
|
expect(screen.getAllByRole('option')).toHaveLength(2);
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
|
|
expect(mocks.onSelect).toHaveBeenCalledWith(
|
|
items[1],
|
|
expect.objectContaining({highlightedIndex: 1}),
|
|
expect.anything()
|
|
);
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
expect(input).toHaveValue('apple');
|
|
});
|
|
});
|
|
|
|
it('selects using enter key', function () {
|
|
const wrapper = createWrapper({isOpen: true, shouldSelectWithEnter: false});
|
|
fireEvent.change(input, {target: {value: 'pine'}});
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
expect(mocks.onSelect).not.toHaveBeenCalled();
|
|
wrapper.unmount();
|
|
|
|
createWrapper({isOpen: true, shouldSelectWithEnter: true});
|
|
fireEvent.change(input, {target: {value: 'pine'}});
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
expect(mocks.onSelect).toHaveBeenCalledWith(
|
|
items[1],
|
|
expect.objectContaining({inputValue: 'pine', highlightedIndex: 0}),
|
|
expect.anything()
|
|
);
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
expect(input).toHaveValue('Pineapple');
|
|
});
|
|
|
|
it('selects using tab key', function () {
|
|
let wrapper = createWrapper({isOpen: true, shouldSelectWithTab: false});
|
|
fireEvent.change(input, {target: {value: 'pine'}});
|
|
fireEvent.keyDown(input, {key: 'Tab', charCode: 9});
|
|
expect(mocks.onSelect).not.toHaveBeenCalled();
|
|
wrapper.unmount();
|
|
|
|
wrapper = createWrapper({isOpen: true, shouldSelectWithTab: true});
|
|
fireEvent.change(input, {target: {value: 'pine'}});
|
|
fireEvent.keyDown(input, {key: 'Tab'});
|
|
expect(mocks.onSelect).toHaveBeenCalledWith(
|
|
items[1],
|
|
expect.objectContaining({inputValue: 'pine', highlightedIndex: 0}),
|
|
expect.anything()
|
|
);
|
|
expect(mocks.onClose).toHaveBeenCalledTimes(1);
|
|
expect(input).toHaveValue('Pineapple');
|
|
});
|
|
|
|
it('does not reset highlight state if `closeOnSelect` is false and we select a new item', function () {
|
|
createWrapper({closeOnSelect: false});
|
|
jest.useFakeTimers();
|
|
fireEvent.focus(input);
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
// Select item
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
|
|
// Should still remain open with same highlightedIndex
|
|
expect(screen.getByText('Pineapple')).toHaveAttribute('aria-selected', 'true');
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
|
|
fireEvent.keyDown(input, {key: 'ArrowDown', charCode: 40});
|
|
expect(screen.getByText('Orange')).toHaveAttribute('aria-selected', 'true');
|
|
|
|
// Select item
|
|
fireEvent.keyDown(input, {key: 'Enter', charCode: 13});
|
|
|
|
// Should still remain open with same highlightedIndex
|
|
expect(screen.getByText('Orange')).toHaveAttribute('aria-selected', 'true');
|
|
expect(screen.getByTestId('test-autocomplete')).toBeInTheDocument();
|
|
});
|
|
});
|