From d4c40b8b6af8b05eda447d6281fca29d282ae3f6 Mon Sep 17 00:00:00 2001 From: Marcos Date: Thu, 8 Feb 2024 17:27:34 -0300 Subject: [PATCH] chore: Added CoursewareSearch hooks coverage --- .../CoursewareResultsFilter.jsx | 12 +++-- .../courseware-search/CoursewareSearch.jsx | 20 ++++---- .../CoursewareSearch.test.jsx | 4 +- .../courseware-search/courseware-search.scss | 2 + src/course-home/courseware-search/hooks.js | 5 +- .../courseware-search/hooks.test.jsx | 49 ++++++++++++++++++- 6 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/course-home/courseware-search/CoursewareResultsFilter.jsx b/src/course-home/courseware-search/CoursewareResultsFilter.jsx index 34f286dc3f..6ff443ce32 100644 --- a/src/course-home/courseware-search/CoursewareResultsFilter.jsx +++ b/src/course-home/courseware-search/CoursewareResultsFilter.jsx @@ -22,9 +22,13 @@ export const CoursewareSearchResultsFilter = ({ intl }) => { const { results: data = [] } = lastSearch; - if (!data.length) { return null; } + // If there's no data, we show an empty result. + if (!data.length) { return ; } const results = useMemo(() => { + // This reducer distributes the data into different groups to make it easy to + // use on the filters. + // All results are added to the "all" key and then to its proper group key as well. const grouped = data.reduce((acc, { type, ...rest }) => { const resultType = filterTypes.includes(type) ? type : filterOther; acc[filterAll].push({ type: resultType, ...rest }); @@ -32,7 +36,7 @@ export const CoursewareSearchResultsFilter = ({ intl }) => { return acc; }, { [filterAll]: [] }); - // This is just to keep the tab order + // This is just to format the output object with the expected tab order. const output = {}; validFilters.forEach(key => { if (grouped[key]) { output[key] = grouped[key]; } }); @@ -60,11 +64,11 @@ export const CoursewareSearchResultsFilter = ({ intl }) => { activeKey={activeKey} onSelect={setFilter} > - {filters.filter(({ count }) => (count > 0)).map(({ key, label }) => (results[key].length ? ( + {filters.filter(({ count }) => (count > 0)).map(({ key, label }) => ( - ) : null))} + ))} ); }; diff --git a/src/course-home/courseware-search/CoursewareSearch.jsx b/src/course-home/courseware-search/CoursewareSearch.jsx index 6bdd53a0c9..5fb8c9742c 100644 --- a/src/course-home/courseware-search/CoursewareSearch.jsx +++ b/src/course-home/courseware-search/CoursewareSearch.jsx @@ -122,16 +122,16 @@ const CoursewareSearch = ({ intl, ...sectionProps }) => { )} {status === 'results' ? ( <> -
{total > 0 - ? intl.formatMessage(messages.searchResultsLabel, { total, keyword: lastSearchKeyword }) - : intl.formatMessage(messages.searchResultsNone)} -
+ {total > 0 ? ( +
{intl.formatMessage(messages.searchResultsLabel, { total, keyword: lastSearchKeyword })} +
+ ) : null} ) : null} diff --git a/src/course-home/courseware-search/CoursewareSearch.test.jsx b/src/course-home/courseware-search/CoursewareSearch.test.jsx index 125125a728..38353cd54e 100644 --- a/src/course-home/courseware-search/CoursewareSearch.test.jsx +++ b/src/course-home/courseware-search/CoursewareSearch.test.jsx @@ -236,14 +236,14 @@ describe('CoursewareSearch', () => { expect(screen.queryByTestId('courseware-search-error')).toBeInTheDocument(); }); - it('should show "No results found." if results is empty', () => { + it('should not show a summary if there are no results', () => { mockModels({ searchKeyword: 'test', total: 0, }); renderComponent(); - expect(screen.queryByTestId('courseware-search-summary').textContent).toBe('No results found.'); + expect(screen.queryByTestId('courseware-search-summary')).not.toBeInTheDocument(); }); it('should show a summary for the results', () => { diff --git a/src/course-home/courseware-search/courseware-search.scss b/src/course-home/courseware-search/courseware-search.scss index 3acfafb740..aa96b5b47c 100644 --- a/src/course-home/courseware-search/courseware-search.scss +++ b/src/course-home/courseware-search/courseware-search.scss @@ -51,6 +51,8 @@ &__empty { color: $gray-500; + padding: 6rem 0; + text-align: center; } &__item { diff --git a/src/course-home/courseware-search/hooks.js b/src/course-home/courseware-search/hooks.js index ad9519b27b..57222d41f8 100644 --- a/src/course-home/courseware-search/hooks.js +++ b/src/course-home/courseware-search/hooks.js @@ -70,9 +70,10 @@ export function useLockScroll() { }, []); } +const initSearchParams = { q: '', f: '' }; export function useCoursewareSearchParams() { - const [searchParams, setSearchParams] = useSearchParams(); - const clearSearchParams = () => setSearchParams({ q: '', f: '' }); + const [searchParams, setSearchParams] = useSearchParams(initSearchParams); + const clearSearchParams = () => setSearchParams(initSearchParams); const query = searchParams.get('q'); const filter = searchParams.get('f')?.toLowerCase(); diff --git a/src/course-home/courseware-search/hooks.test.jsx b/src/course-home/courseware-search/hooks.test.jsx index cc6b67554a..bbf7016251 100644 --- a/src/course-home/courseware-search/hooks.test.jsx +++ b/src/course-home/courseware-search/hooks.test.jsx @@ -1,9 +1,13 @@ import { renderHook, act } from '@testing-library/react-hooks'; -import { useParams } from 'react-router-dom'; +import { useParams, useSearchParams } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { fetchCoursewareSearchSettings } from '../data/thunks'; import { - useCoursewareSearchFeatureFlag, useCoursewareSearchState, useElementBoundingBox, useLockScroll, + useCoursewareSearchFeatureFlag, + useCoursewareSearchParams, + useCoursewareSearchState, + useElementBoundingBox, + useLockScroll, } from './hooks'; jest.mock('react-redux'); @@ -184,4 +188,45 @@ describe('CoursewareSearch Hooks', () => { expect(removeBodyClassSpy).toHaveBeenCalledWith('_search-no-scroll'); }); }); + + describe('useSearchParams', () => { + const initSearch = { q: '', f: '' }; + const q = { value: '' }; + const f = { value: '' }; + const mockedQuery = { q, f }; + const searchParams = { get: (prop) => mockedQuery[prop].value }; + const setSearchParams = jest.fn(); + + beforeEach(() => { + useSearchParams.mockImplementation(() => [searchParams, setSearchParams]); + }); + + it('should init the search params properly', () => { + const { + query, filter, setQuery, setFilter, clearSearchParams, + } = useCoursewareSearchParams(); + + expect(useSearchParams).toBeCalledWith(initSearch); + expect(query).toBe(''); + expect(filter).toBe(''); + + setQuery('setQuery'); + expect(setSearchParams).toBeCalledWith(expect.any(Function)); + + setFilter('setFilter'); + expect(setSearchParams).toBeCalledWith(expect.any(Function)); + + clearSearchParams(); + expect(setSearchParams).toBeCalledWith(initSearch); + }); + + it('should return the query and lowercase filter if any', () => { + q.value = '42'; + f.value = 'LOWERCASE'; + const { query, filter } = useCoursewareSearchParams(); + + expect(query).toBe('42'); + expect(filter).toBe('lowercase'); + }); + }); });