-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: update SearchInput component with debounce functionality (#250)
#222 --------- Co-authored-by: Martin Rohrmeier <[email protected]>
- Loading branch information
Showing
13 changed files
with
400 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
### Overview | ||
|
||
- The SearchInput component is a versatile input field that supports both controlled and uncontrolled modes with debounce functionality. | ||
|
||
### Interaction | ||
|
||
- Users can enter search terms into the input field. If the `type` prop is not specified, it defaults to a search field, which browsers style differently to indicate its purpose. | ||
- When the input is having search term, a clear icon appears to help users reset their search. | ||
|
||
### Context and Usage | ||
|
||
The SearchInput component supports both controlled and uncontrolled modes: | ||
- It provides flexible input functionality with debounce support and can be used in both controlled and uncontrolled modes. | ||
- Use the `onSearch` handler to manage API calls, which will be triggered based on the specified debounce timeout. | ||
|
||
#### Common Behavior | ||
|
||
- The `onChange` handler triggers on every character change. | ||
- The debounce feature, with a default delay of 0 milliseconds, can be customized using the `debounceTimeout` prop. | ||
- The `onSearch` function is called after the debounce delay, allowing for API calls. | ||
|
||
#### Controlled Mode | ||
|
||
- Use the `value` prop to control the input. | ||
|
||
#### Uncontrolled Mode | ||
|
||
- Use the `defaultValue` prop to set the initial input value. | ||
|
||
### Guidance | ||
|
||
- The `onChange` handler functions the same as in a standard input field. | ||
- All props related to the MUI TextField component are supported. | ||
- New props added for managing the debounce feature: `debounceTimeout` and `onSearch`. | ||
|
||
## NOTICE | ||
|
||
This work is licensed under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode). | ||
|
||
- SPDX-License-Identifier: CC-BY-4.0 | ||
- SPDX-FileCopyrightText: Copyright (c) 2024 Contributors to the Eclipse Foundation | ||
- Source URL: https://github.com/eclipse-tractusx/portal-shared-components |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/******************************************************************************** | ||
* Copyright (c) 2024 Contributors to the Eclipse Foundation | ||
* | ||
* See the NOTICE file(s) distributed with this work for additional | ||
* information regarding copyright ownership. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Apache License, Version 2.0 which is available at | ||
* https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
********************************************************************************/ | ||
|
||
import { useState } from 'react' | ||
import { fireEvent, screen, waitFor } from '@testing-library/react' | ||
import { SearchInput } from '.' | ||
import { render } from '../../../test/testUtils' | ||
|
||
jest.useFakeTimers() | ||
|
||
describe('SearchInput', () => { | ||
const debounceTimeout = 300 | ||
const onSearch = jest.fn() | ||
const onChange = jest.fn() | ||
|
||
const ControlledSearchInput = () => { | ||
const [value, setValue] = useState('') | ||
return ( | ||
<SearchInput | ||
debounceTimeout={debounceTimeout} | ||
onSearch={onSearch} | ||
value={value} | ||
onChange={(e) => setValue(e.target.value)} | ||
placeholder="Search" | ||
/> | ||
) | ||
} | ||
const UncontrolledSearchInput = () => ( | ||
<SearchInput onSearch={onSearch} onChange={onChange} placeholder="Search" /> | ||
) | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks() | ||
}) | ||
|
||
test('renders the Search Input component', () => { | ||
render(<SearchInput />) | ||
}) | ||
|
||
test('should call search function after specified debounce timeout', async () => { | ||
render(<UncontrolledSearchInput />) | ||
const input = screen.getByPlaceholderText('Search') | ||
fireEvent.change(input, { target: { value: 'te' } }) | ||
fireEvent.change(input, { target: { value: 'testing...' } }) | ||
expect(onSearch).not.toHaveBeenCalled() | ||
expect(onChange).toHaveBeenCalledTimes(2) | ||
|
||
jest.advanceTimersByTime(debounceTimeout) | ||
await waitFor(() => expect(onSearch).toHaveBeenCalledWith('testing...')) | ||
expect(onSearch).toHaveBeenCalledTimes(1) | ||
}) | ||
|
||
test('should call onChange handler when input value changes', () => { | ||
render(<UncontrolledSearchInput />) | ||
|
||
const input = screen.getByPlaceholderText('Search') | ||
fireEvent.change(input, { target: { value: 't' } }) | ||
expect(onChange).toHaveBeenCalledTimes(1) | ||
fireEvent.change(input, { target: { value: 'te' } }) | ||
expect(onChange).toHaveBeenCalledTimes(2) | ||
fireEvent.change(input, { target: { value: 'test' } }) | ||
expect(onChange).toHaveBeenCalledTimes(3) | ||
}) | ||
|
||
test('should call debounced search function with new value after reset', async () => { | ||
render(<ControlledSearchInput />) | ||
|
||
const input = screen.getByPlaceholderText('Search') | ||
fireEvent.change(input, { target: { value: 'test' } }) | ||
|
||
jest.advanceTimersByTime(debounceTimeout) | ||
await waitFor(() => expect(onSearch).toHaveBeenCalledWith('test')) | ||
|
||
fireEvent.change(input, { target: { value: '' } }) | ||
|
||
jest.advanceTimersByTime(debounceTimeout) | ||
await waitFor(() => expect(onSearch).toHaveBeenCalledWith('')) | ||
}) | ||
|
||
test('should not call search function on initial render when value is provided', () => { | ||
render(<ControlledSearchInput />) | ||
|
||
jest.advanceTimersByTime(debounceTimeout) | ||
expect(onChange).not.toHaveBeenCalled() | ||
}) | ||
|
||
test('should call search function when controlled value changes', async () => { | ||
const { rerender } = render( | ||
<SearchInput | ||
debounceTimeout={debounceTimeout} | ||
onSearch={onSearch} | ||
value="initial" | ||
onChange={onChange} | ||
/> | ||
) | ||
|
||
rerender( | ||
<SearchInput | ||
debounceTimeout={debounceTimeout} | ||
onSearch={onSearch} | ||
value="updated" | ||
onChange={onChange} | ||
/> | ||
) | ||
|
||
jest.advanceTimersByTime(debounceTimeout) | ||
await waitFor(() => expect(onSearch).toHaveBeenCalledWith('updated')) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/******************************************************************************** | ||
* Copyright (c) 2024 Contributors to the Eclipse Foundation | ||
* | ||
* See the NOTICE file(s) distributed with this work for additional | ||
* information regarding copyright ownership. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Apache License, Version 2.0 which is available at | ||
* https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
********************************************************************************/ | ||
|
||
import { type Palette } from '@mui/material' | ||
const createPalette: (palette: Palette) => Palette = (palette) => palette | ||
export default createPalette |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/******************************************************************************** | ||
* Copyright (c) 2024 Contributors to the Eclipse Foundation | ||
* | ||
* See the NOTICE file(s) distributed with this work for additional | ||
* information regarding copyright ownership. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Apache License, Version 2.0 which is available at | ||
* https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
********************************************************************************/ | ||
|
||
import { type Palette } from '@mui/material' | ||
import { type TypographyOptions } from '@mui/material/styles/createTypography' | ||
|
||
const createTypography: ( | ||
palette: Palette, | ||
typography: TypographyOptions | ||
) => TypographyOptions = (palette, typography) => ({ | ||
...palette, | ||
...typography, | ||
}) | ||
export default createTypography |
Oops, something went wrong.