diff --git a/src/components/page-filters/page-filters-search/__tests__/page-filters-search.test.tsx b/src/components/page-filters/page-filters-search/__tests__/page-filters-search.test.tsx
index 8c36f681f..75e265f84 100644
--- a/src/components/page-filters/page-filters-search/__tests__/page-filters-search.test.tsx
+++ b/src/components/page-filters/page-filters-search/__tests__/page-filters-search.test.tsx
@@ -1,6 +1,6 @@
import React from 'react';
-import { render, screen, act, fireEvent } from '@/test-utils/rtl';
+import { render, screen, userEvent } from '@/test-utils/rtl';
import {
mockPageQueryParamConfig,
@@ -13,55 +13,81 @@ jest.mock('@/hooks/use-page-query-params/use-page-query-params', () =>
jest.fn(() => [mockQueryParamsValues, mockSetQueryParams])
);
+beforeEach(() => {
+ jest.useFakeTimers();
+});
+
afterEach(() => {
jest.clearAllMocks();
+ jest.useRealTimers();
});
describe(PageFiltersSearch.name, () => {
it('should render search bar correctly and call setSearch on input change', async () => {
- setup({});
+ const { user } = setup({});
const searchInput = await screen.findByRole('textbox');
- act(() => {
- fireEvent.change(searchInput, { target: { value: 'test-search' } });
- });
+ await user.type(searchInput, 'test-search');
expect(mockSetQueryParams).toHaveBeenCalledWith({ search: 'test-search' });
});
it('should prune quotes and spaces from input text if no regexp is passed', async () => {
- setup({});
+ const { user } = setup({});
const searchInput = await screen.findByRole('textbox');
- act(() => {
- fireEvent.change(searchInput, { target: { value: ` "test-search'` } });
- });
+ await user.type(searchInput, ` "test-search'`);
expect(mockSetQueryParams).toHaveBeenCalledWith({ search: 'test-search' });
});
it('should prune symbols from input text if regexp is passed', async () => {
- setup({ searchTrimRegExp: /[-]/g });
+ const { user } = setup({ searchTrimRegExp: /[-]/g });
const searchInput = await screen.findByRole('textbox');
- act(() => {
- fireEvent.change(searchInput, { target: { value: 'test-search' } });
- });
+ await user.type(searchInput, 'test-search');
expect(mockSetQueryParams).toHaveBeenCalledWith({ search: 'testsearch' });
});
+
+ it('should debounce setSearch if a debounce duration is passed', async () => {
+ const { user } = setup({ inputDebounceDurationMs: 400 });
+
+ const searchInput = await screen.findByRole('textbox');
+
+ await user.type(searchInput, 'test-');
+ jest.advanceTimersByTime(200);
+
+ await user.type(searchInput, 'search');
+ jest.advanceTimersByTime(500);
+
+ expect(mockSetQueryParams).toHaveBeenCalledTimes(1);
+ expect(mockSetQueryParams).toHaveBeenCalledWith({
+ search: 'test-search',
+ });
+ });
});
-function setup({ searchTrimRegExp }: { searchTrimRegExp?: RegExp }) {
- render(
+function setup({
+ searchTrimRegExp,
+ inputDebounceDurationMs,
+}: {
+ searchTrimRegExp?: RegExp;
+ inputDebounceDurationMs?: number;
+}) {
+ const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
+ const renderResult = render(
) {
const [queryParams, setQueryParams] = usePageQueryParams(
pageQueryParamsConfig,
{ replace: true, pageRerender: false }
);
+ const queryParamsSearch = queryParams[searchQueryParamKey];
+
+ const [inputState, setInputState] = useState
+ >),
+ [searchQueryParamKey, setQueryParams]
+ );
+
+ const setSearchMaybeDebounced = useMemo(() => {
+ if (inputDebounceDurationMs)
+ return debounce(setSearch, inputDebounceDurationMs);
+ return setSearch;
+ }, [setSearch, inputDebounceDurationMs]);
+
return (
{
const searchValue = event.target.value.replaceAll(searchTrimRegExp, '');
- setQueryParams({
- [searchQueryParamKey]: searchValue || undefined,
- } as Partial [K] extends string ? K : never;
searchPlaceholder: string;
searchTrimRegExp?: RegExp;
+ inputDebounceDurationMs?: number;
};
diff --git a/src/components/page-filters/page-filters.tsx b/src/components/page-filters/page-filters.tsx
index c0d3826d4..5f97d53e6 100644
--- a/src/components/page-filters/page-filters.tsx
+++ b/src/components/page-filters/page-filters.tsx
@@ -18,9 +18,7 @@ export default function PageFilters<
>({
pageFiltersConfig,
pageQueryParamsConfig,
- searchQueryParamKey,
- searchPlaceholder,
- searchTrimRegExp,
+ ...restSearchProps
}: Props ) {
const [areFiltersShown, setAreFiltersShown] = useState(false);
@@ -32,9 +30,7 @@ export default function PageFilters<