diff --git a/src/hooks.js b/src/hooks.js index c162608243..483024e67c 100644 --- a/src/hooks.js +++ b/src/hooks.js @@ -32,26 +32,3 @@ export const useEscapeClick = ({ onEscape, dependency }) => { }; }, [dependency]); }; - -/** - * Custom hook to debounce a string value. - * - * @param {string} value - The string value to be debounced. - * @param {number} [delay=500] - The delay in milliseconds before updating the debounced value. - * @returns {string} The debounced string value. - */ -export const useDebounce = (value, delay = 500) => { - const [debouncedValue, setDebouncedValue] = useState(value); - - useEffect(() => { - const timer = setTimeout(() => { - setDebouncedValue(value); - }, delay); - - return () => { - clearTimeout(timer); - }; - }, [value, delay]); - - return debouncedValue; -}; diff --git a/src/studio-home/__mocks__/studioHomeMock.js b/src/studio-home/__mocks__/studioHomeMock.js index 0de8903c80..5385201e52 100644 --- a/src/studio-home/__mocks__/studioHomeMock.js +++ b/src/studio-home/__mocks__/studioHomeMock.js @@ -47,7 +47,7 @@ module.exports = { org: 'org.0', rerunLink: null, run: 'Run_0', - url: null, + url: '', }, ], inProcessCourseActions: [], diff --git a/src/studio-home/processing-courses/index.jsx b/src/studio-home/processing-courses/index.jsx index 10fc02d1cf..67003659c6 100644 --- a/src/studio-home/processing-courses/index.jsx +++ b/src/studio-home/processing-courses/index.jsx @@ -13,7 +13,7 @@ const ProcessingCourses = () => { return ( <> -
+
{intl.formatMessage(messages.processingTitle)}

diff --git a/src/studio-home/tabs-section/courses-tab/courses-filters/index.jsx b/src/studio-home/tabs-section/courses-tab/courses-filters/index.jsx index 61847a3d7a..a1939681b8 100644 --- a/src/studio-home/tabs-section/courses-tab/courses-filters/index.jsx +++ b/src/studio-home/tabs-section/courses-tab/courses-filters/index.jsx @@ -131,7 +131,7 @@ const CoursesFilters = ({ onClear={handleClearSearchInput} /> {isLoading && ( - + )} diff --git a/src/studio-home/tabs-section/courses-tab/courses-filters/index.test.jsx b/src/studio-home/tabs-section/courses-tab/courses-filters/index.test.jsx index fdd41b12ce..76f521670b 100644 --- a/src/studio-home/tabs-section/courses-tab/courses-filters/index.test.jsx +++ b/src/studio-home/tabs-section/courses-tab/courses-filters/index.test.jsx @@ -126,4 +126,44 @@ describe('CoursesFilters', () => { userEvent.type(searchInput, 'testing{enter}'); expect(handleSubmit).toHaveBeenCalled(); }); + + it('should call dispatch after debounce delay when the search input changes', async () => { + renderComponent(); + const searchInput = screen.getByRole('searchbox'); + fireEvent.change(searchInput, { target: { value: 'test' } }); + await waitFor(() => expect(dispatchMock).toHaveBeenCalled(), { timeout: 500 }); + expect(dispatchMock).toHaveBeenCalledWith(expect.anything()); + }); + + it('should not call dispatch when the search input contains only spaces', async () => { + renderComponent(); + const searchInput = screen.getByRole('searchbox'); + fireEvent.change(searchInput, { target: { value: ' ' } }); + await new Promise((r) => setTimeout(r, 500)); + + expect(dispatchMock).not.toHaveBeenCalled(); + }); + + it('should display the loading spinner when isLoading is true', () => { + renderComponent({ isLoading: true }); + const spinner = screen.getByTestId('loading-search-spinner'); + expect(spinner).toBeInTheDocument(); + }); + + it('should not display the loading spinner when isLoading is false', () => { + renderComponent({ isLoading: false }); + const spinner = screen.queryByTestId('loading-search-spinner'); + expect(spinner).not.toBeInTheDocument(); + }); + + it('should clear the search input and call dispatch when the reset button is clicked', async () => { + renderComponent(); + const searchInput = screen.getByRole('searchbox'); + fireEvent.change(searchInput, { target: { value: 'test' } }); + const form = searchInput.closest('form'); + const resetButton = form.querySelector('button[type="reset"]'); + fireEvent.click(resetButton); + expect(searchInput.value).toBe(''); + expect(dispatchMock).toHaveBeenCalled(); + }); }); diff --git a/src/studio-home/tabs-section/courses-tab/index.test.jsx b/src/studio-home/tabs-section/courses-tab/index.test.jsx index ba5cea3f70..3c4811edc0 100644 --- a/src/studio-home/tabs-section/courses-tab/index.test.jsx +++ b/src/studio-home/tabs-section/courses-tab/index.test.jsx @@ -103,7 +103,6 @@ describe('', () => { const props = { isFailed: true }; const customStoreData = { studioHomeCoursesRequestParams: { currentPage: 1, isFiltered: false } }; renderComponent(props, customStoreData); - screen.debug(); const alertErrorFailed = screen.queryByTestId('error-failed-message'); expect(alertErrorFailed).toBeInTheDocument(); }); @@ -112,8 +111,23 @@ describe('', () => { const props = { isLoading: false, coursesDataItems: [] }; const customStoreData = { studioHomeCoursesRequestParams: { currentPage: 1, isFiltered: true } }; renderComponent(props, customStoreData); - screen.debug(); const alertCoursesNotFound = screen.queryByTestId('courses-not-found-alert'); expect(alertCoursesNotFound).toBeInTheDocument(); }); + + it('should render processing courses component when isEnabledPagination is false and isShowProcessing is true', () => { + const props = { isShowProcessing: true, isEnabledPagination: false }; + const customStoreData = { + studioHomeData: { + inProcessCourseActions: [], + }, + studioHomeCoursesRequestParams: { + currentPage: 1, + isFiltered: true, + }, + }; + renderComponent(props, customStoreData); + const alertCoursesNotFound = screen.queryByTestId('processing-courses-title'); + expect(alertCoursesNotFound).toBeInTheDocument(); + }); });