Fix the broken deeplink of support form

Summary:
I just noticed that the deeplink of the support form didn't select the right group. It got broken after the recent design change of the support form. This diff fixes that issue.

I have also added unit tests.

Reviewed By: passy

Differential Revision: D21817153

fbshipit-source-id: 06298b3b60cfc1bd77bea6c1f902b983474808dc
This commit is contained in:
Pritesh Nandgaonkar
2020-06-02 04:45:58 -07:00
committed by Facebook GitHub Bot
parent 3c97c1d3bc
commit 965a36ee52
2 changed files with 190 additions and 9 deletions

View File

@@ -71,6 +71,7 @@ function RowComponent(props: {
}) { }) {
return ( return (
<RowComponentContainer <RowComponentContainer
data-testid={'row-component'}
onClick={() => { onClick={() => {
props.onClick(props.elem.id); props.onClick(props.elem.id);
}}> }}>
@@ -85,15 +86,11 @@ function RowComponent(props: {
export default function (props: Props) { export default function (props: Props) {
const {list, handleNoResults, onSelect, selectedElementID} = props; const {list, handleNoResults, onSelect, selectedElementID} = props;
const initialElement = list.find((e) => {
return e.id === selectedElementID;
});
const [filteredElements, setFilteredElements] = useState<Array<Element>>([]); const [filteredElements, setFilteredElements] = useState<Array<Element>>([]);
const [searchedValue, setSearchedValue] = useState<string>( const [searchedValue, setSearchedValue] = useState<string>('');
initialElement ? initialElement.label : '',
);
const [selectedElement, setSelectedElement] = useState<Element | undefined>( const [selectedElement, setSelectedElement] = useState<Element | undefined>(
initialElement, undefined,
); );
const [focussed, setFocus] = useState<boolean>(false); const [focussed, setFocus] = useState<boolean>(false);
const wrapperRef = useRef<HTMLDivElement>(null); const wrapperRef = useRef<HTMLDivElement>(null);
@@ -129,6 +126,16 @@ export default function (props: Props) {
[setFocus], [setFocus],
); );
// Set the searched value and selectedElement when the selectedElementID changes.
useEffect(() => {
const initialElement = list.find((e) => e.id === selectedElementID);
if (initialElement) {
setSearchedValue(initialElement.label);
}
setSelectedElement(initialElement);
setFocus(false);
}, [selectedElementID, list]);
// Effect to filter items // Effect to filter items
useEffect(() => { useEffect(() => {
if (searchedValue.length > 0) { if (searchedValue.length > 0) {
@@ -195,6 +202,7 @@ export default function (props: Props) {
onFocus={onFocusCallBack} onFocus={onFocusCallBack}
value={searchedValue} value={searchedValue}
isValidInput={false} isValidInput={false}
data-testid={'search-input'}
/> />
</SearchBox> </SearchBox>
</Tooltip> </Tooltip>
@@ -203,14 +211,14 @@ export default function (props: Props) {
<ListViewContainer scrollable={true}> <ListViewContainer scrollable={true}>
{filteredElements.map((e, idx) => { {filteredElements.map((e, idx) => {
return ( return (
<> <FlexColumn key={idx}>
<RowComponent <RowComponent
elem={e} elem={e}
onClick={onSelectCallBack} onClick={onSelectCallBack}
selected={selectedElement && e.id == selectedElement.id} selected={selectedElement && e.id == selectedElement.id}
/> />
{idx < filteredElements.length - 1 && <Separator />} {idx < filteredElements.length - 1 && <Separator />}
</> </FlexColumn>
); );
})} })}
</ListViewContainer> </ListViewContainer>

View File

@@ -0,0 +1,173 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import * as React from 'react';
import {render, fireEvent} from '@testing-library/react';
import DropDownSearchView from '../DropDownSearchView';
import {act} from 'react-dom/test-utils';
test('Test selected element id is shown as the selected one.', async () => {
const res = render(
<DropDownSearchView
list={[{id: 'id1', label: 'label1'}]}
onSelect={jest.fn()}
handleNoResults={jest.fn()}
selectedElementID={'id1'}
/>,
);
const searchInput = (await res.findByTestId(
'search-input',
)) as HTMLInputElement;
expect(searchInput).toBeTruthy();
expect(searchInput.value).toEqual('label1');
act(() => {
searchInput.dispatchEvent(new FocusEvent('focus', {bubbles: true}));
});
expect(await res.queryByText('label1')).toBeTruthy();
});
test('Test the change of the selectedElementID changes the the selected element in the UI.', async () => {
const res = render(
<DropDownSearchView
list={[
{id: 'id1', label: 'label1'},
{id: 'id2', label: 'label2'},
]}
onSelect={jest.fn()}
handleNoResults={jest.fn()}
selectedElementID={'id1'}
/>,
);
const searchInput = (await res.findByTestId(
'search-input',
)) as HTMLInputElement;
expect(searchInput).toBeTruthy();
expect(searchInput.value).toEqual('label1');
res.rerender(
<DropDownSearchView
list={[
{id: 'id1', label: 'label1'},
{id: 'id2', label: 'label2'},
]}
onSelect={jest.fn()}
handleNoResults={jest.fn()}
selectedElementID={'id2'}
/>,
);
const searchInputRerendered = (await res.findByTestId(
'search-input',
)) as HTMLInputElement;
expect(searchInputRerendered).toBeTruthy();
expect(searchInputRerendered.value).toEqual('label2');
});
test('Test the entire flow and click on the available options.', async () => {
const onSelect = jest.fn();
const res = render(
<DropDownSearchView
list={[
{id: 'id1', label: 'label1'},
{id: 'id2', label: 'label2'},
{id: 'id3', label: 'label3'},
{id: 'id4', label: 'label4'},
]}
onSelect={onSelect}
handleNoResults={jest.fn()}
selectedElementID={'id1'}
/>,
);
const searchInput = (await res.findByTestId(
'search-input',
)) as HTMLInputElement;
expect(searchInput).toBeTruthy();
expect(searchInput.value).toEqual('label1');
act(() => {
searchInput.dispatchEvent(new FocusEvent('focus', {bubbles: true}));
});
// Right now just the filtered elements will show up
expect(await res.queryByText('label1')).toBeTruthy();
expect(await res.queryByText('label2')).toBeFalsy();
expect(await res.queryByText('label3')).toBeFalsy();
expect(await res.queryByText('label4')).toBeFalsy();
act(() => {
fireEvent.change(searchInput, {target: {value: ''}});
});
// Once the input field is cleared all the available options will show up.
expect(await res.queryByText('label1')).toBeTruthy();
expect(await res.queryByText('label2')).toBeTruthy();
expect(await res.queryByText('label3')).toBeTruthy();
const text4 = await res.queryByText('label4');
expect(text4).toBeTruthy();
act(() => {
text4?.parentElement?.dispatchEvent(
new MouseEvent('click', {bubbles: true}),
);
});
expect(searchInput.value).toEqual('label4');
expect(onSelect).toBeCalledTimes(1);
// After onSelect the expanded menu gets closed.
expect(await res.queryByText('label1')).toBeFalsy();
expect(await res.queryByText('label2')).toBeFalsy();
expect(await res.queryByText('label3')).toBeFalsy();
expect(await res.queryByText('label4')).toBeFalsy();
});
test('Test the validation error.', async () => {
const handleNoResults = jest.fn();
const res = render(
<DropDownSearchView
list={[
{id: 'id1', label: 'label1 group'},
{id: 'id2', label: 'label2 group'},
{id: 'id3', label: 'label3 support'},
{id: 'id4', label: 'label4 support'},
]}
handleNoResults={handleNoResults}
selectedElementID={undefined}
/>,
);
const searchInput = (await res.findByTestId(
'search-input',
)) as HTMLInputElement;
expect(searchInput).toBeTruthy();
expect(searchInput.value).toEqual('');
act(() => {
searchInput.dispatchEvent(new FocusEvent('focus', {bubbles: true}));
});
// Right now just the filtered elements will show up
expect(await res.queryByText('label1 group')).toBeTruthy();
expect(await res.queryByText('label2 group')).toBeTruthy();
expect(await res.queryByText('label3 support')).toBeTruthy();
expect(await res.queryByText('label4 support')).toBeTruthy();
act(() => {
fireEvent.change(searchInput, {target: {value: 'support'}});
});
// Only the items which satisfy the search query should be shown
expect(await res.queryByText('label3 support')).toBeTruthy();
expect(await res.queryByText('label4 support')).toBeTruthy();
expect(await res.queryByText('label1 group')).toBeFalsy();
expect(await res.queryByText('label2 group')).toBeFalsy();
act(() => {
fireEvent.change(searchInput, {target: {value: 'gibberish'}});
});
expect(handleNoResults).toBeCalled();
expect(await res.queryByText('label3 support')).toBeFalsy();
expect(await res.queryByText('label4 support')).toBeFalsy();
expect(await res.queryByText('label1 group')).toBeFalsy();
expect(await res.queryByText('label2 group')).toBeFalsy();
});