Skip to content

Commit

Permalink
Merge pull request #532 from catho/QTM-527
Browse files Browse the repository at this point in the history
fix(QTM-527): Fixing navigation between items using keyboard
  • Loading branch information
MarcosViniciusPC authored Dec 20, 2023
2 parents 44c9de5 + dddcbbe commit 153bbff
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 10 deletions.
25 changes: 15 additions & 10 deletions components/AutoComplete/AutoComplete.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ const AutoComplete = ({
filterSuggestions.length,
);
const [showSuggestions, setShowSuggestions] = useState(false);
const [cursor, setCursor] = useState(0);
const [cursor, setCursor] = useState(-1);
const wrapperRef = useRef();
const listOptions = useRef();
const autoInputRef = useRef(null);
Expand All @@ -175,6 +175,14 @@ const AutoComplete = ({
}
${cursor + 1} de ${filterSuggestionsLength} está destacado`;

const focusOnInput = () => {
const input = wrapperRef.current?.children[1];
if (input) {
input.focus();
setCursor(-1);
}
};

const filterItems = (currentValue) =>
suggestions.filter((suggestion) => {
let option = normalizeChars(suggestion.toLowerCase());
Expand All @@ -191,7 +199,7 @@ const AutoComplete = ({
const handleChange = (currentValue) => {
setUserTypedValue(currentValue);
onChange(currentValue);
setCursor(0);
setCursor(-1);
handleFilter(currentValue);
};

Expand All @@ -217,15 +225,13 @@ const AutoComplete = ({
setUserTypedValue('');
onChange('');
setFilterSuggestions(suggestions);
setCursor(0);
setCursor(-1);
};

const handleEscPress = ({ key }) => {
const node = wrapperRef.current;
if (node && key === EscapeKeyPressValue) {
if (key === EscapeKeyPressValue) {
setShowSuggestions(false);
node.children[1].focus();
setCursor(0);
focusOnInput();
}
};

Expand Down Expand Up @@ -288,8 +294,7 @@ const AutoComplete = ({
listOptions.current.children[selectedCursor].focus();
}
if (upPress && cursor === 0) {
wrapperRef.current.children[1].focus();
setCursor(-1);
focusOnInput();
}
}, [upPress]);

Expand All @@ -299,7 +304,7 @@ const AutoComplete = ({
setUserTypedValue(filterSuggestions[cursor]);
onSelectedItem(filterSuggestions[cursor]);
setShowSuggestions(false);
wrapperRef.current.children[1].focus();
focusOnInput();
}
}, [cursor, enterPress]);

Expand Down
68 changes: 68 additions & 0 deletions components/AutoComplete/AutoComplete.unit.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import AutoComplete from './AutoComplete';
const Examples = ['morango', 'melancia', 'maça', 'banana', 'laranja'];
const ExamplesChanged = ['melanci', 'melancia'];

const ARROW_DOWN_KEY_CODE = '{ArrowDown}';
const ARROW_UP_KEY_CODE = '{ArrowUp}';
const ENTER_KEY_CODE = '{Enter}';
const ESCAPE_KEY_CODE = '{Escape}';

describe('AutoComplete', () => {
it('Should render Autocomplete', () => {
const { container } = render(<AutoComplete suggestions={Examples} />);
Expand Down Expand Up @@ -217,4 +222,67 @@ describe('AutoComplete', () => {
const autoCompleteInput = screen.getByRole('combobox');
expect(autoCompleteInput).toHaveAttribute('value', initialValue);
});

it('Should close options when user press Escape', async () => {
render(<AutoComplete suggestions={Examples} />);
const input = screen.getByRole('combobox');

await userEvent.type(input, 'moran');
const autoCompleteOptionsList = await screen.findByRole('listbox');

expect(autoCompleteOptionsList).toBeInTheDocument();

await userEvent.keyboard(ESCAPE_KEY_CODE);

expect(autoCompleteOptionsList).not.toBeInTheDocument();
});

it('Should allow User to select an option using only keyboard', async () => {
const onSelectedItemMock = jest.fn();
render(
<AutoComplete
suggestions={Examples}
onSelectedItem={onSelectedItemMock}
/>,
);
const input = screen.getByRole('combobox');

await userEvent.type(input, 'm');
const autoCompleteOptionsList = await screen.findByRole('listbox');

expect(autoCompleteOptionsList).toBeInTheDocument();

await userEvent.keyboard(
`${ARROW_DOWN_KEY_CODE}${ARROW_DOWN_KEY_CODE}${ARROW_UP_KEY_CODE}`,
);
const autoCompleteOptionItem = screen.getByRole('option', {
name: /morango/i,
});

expect(autoCompleteOptionItem).toHaveFocus();
await userEvent.keyboard(ENTER_KEY_CODE);

expect(input.value).toEqual('morango');
expect(onSelectedItemMock).toHaveBeenCalledWith('morango');
expect(autoCompleteOptionsList).not.toBeInTheDocument();
});

it('Should focus on input when there are no items to navigate above', async () => {
const onSelectedItemMock = jest.fn();
render(
<AutoComplete
suggestions={Examples}
onSelectedItem={onSelectedItemMock}
/>,
);
const input = screen.getByRole('combobox');

await userEvent.type(input, 'm');
const autoCompleteOptionsList = await screen.findByRole('listbox');

expect(autoCompleteOptionsList).toBeInTheDocument();

await userEvent.keyboard(`${ARROW_DOWN_KEY_CODE}${ARROW_UP_KEY_CODE}`);
expect(input).toHaveFocus();
});
});

0 comments on commit 153bbff

Please sign in to comment.