Skip to content

Commit

Permalink
fix: dispatches actions to update SearchContext from SearchBox (#89)
Browse files Browse the repository at this point in the history
* fix: dispatches actions to update SearchContext from SearchBox

* build: removing jest config, frontend-build config should be used

* test: updates SearchBox tests, adds renderWithSearchContext util
  • Loading branch information
chavesj authored Apr 14, 2021
1 parent a24cdf0 commit 62a58de
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 92 deletions.
8 changes: 0 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,6 @@
"webpack": "4.44.2",
"webpack-cli": "3.3.12"
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx}",
"!src/index.js",
"!**/node_modules/**",
"!**/tests/**"
]
},
"peerDependencies": {
"@edx/frontend-platform": "^1.5.2",
"@edx/paragon": "^14.5.0",
Expand Down
28 changes: 9 additions & 19 deletions src/course-search/SearchBox.jsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,40 @@
import React from 'react';
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { useHistory } from 'react-router-dom';
import qs from 'query-string';
import { SearchField } from '@edx/paragon';
import { connectSearchBox } from 'react-instantsearch-dom';

import { updateRefinementsFromQueryParams } from './data/utils';
import { deleteRefinementAction, setRefinementAction } from './data/actions';
import { STYLE_VARIANTS } from '../constants';
import { SearchContext } from './SearchContext';
import { QUERY_PARAM_FOR_PAGE, QUERY_PARAM_FOR_SEARCH_QUERY } from './data/constants';

export const searchText = 'Search courses';

export const SearchBoxBase = ({
className,
defaultRefinement,
refinementsFromQueryParams,
variant,
}) => {
const history = useHistory();
const { dispatch } = useContext(SearchContext);

/**
* Handles when a search is submitted by adding the user's search
* query as a query parameter. Note that it must preserved any other
* existing query parameters must be preserved.
*/
const handleSubmit = (searchQuery) => {
const refinements = { ...refinementsFromQueryParams };
refinements.q = searchQuery;
delete refinements.page; // reset to page 1

const updatedRefinements = updateRefinementsFromQueryParams(refinements);
history.push({ search: qs.stringify(updatedRefinements) });
dispatch(setRefinementAction(QUERY_PARAM_FOR_SEARCH_QUERY, searchQuery));
dispatch(deleteRefinementAction(QUERY_PARAM_FOR_PAGE));
};

/**
* Handles when a search is cleared by removing the user's search query
* from the query parameters.
*/
const handleClear = () => {
const refinements = { ...refinementsFromQueryParams };
delete refinements.q;
delete refinements.page; // reset to page 1

const updatedRefinements = updateRefinementsFromQueryParams(refinements);
history.push({ search: qs.stringify(updatedRefinements) });
dispatch(deleteRefinementAction(QUERY_PARAM_FOR_SEARCH_QUERY));
dispatch(deleteRefinementAction(QUERY_PARAM_FOR_PAGE));
};

return (
Expand All @@ -69,7 +60,6 @@ export const SearchBoxBase = ({
};

SearchBoxBase.propTypes = {
refinementsFromQueryParams: PropTypes.shape().isRequired,
defaultRefinement: PropTypes.string,
className: PropTypes.string,
variant: PropTypes.oneOf([STYLE_VARIANTS.default, STYLE_VARIANTS.inverse]),
Expand Down
1 change: 0 additions & 1 deletion src/course-search/SearchHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const SearchHeader = ({ variant, containerSize }) => {
<SearchBox
className="mb-4"
defaultRefinement={searchQueryFromQueryParams}
refinementsFromQueryParams={refinementsFromQueryParams}
variant={variant}
/>
</Col>
Expand Down
45 changes: 6 additions & 39 deletions src/course-search/tests/SearchBox.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ import { screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';

import { SearchBoxBase, searchText } from '../SearchBox';

import { renderWithRouter } from '../../utils/tests';
import { renderWithSearchContext } from '../../utils/tests';

const TEST_QUERY = 'test query';

describe('<SearchBox />', () => {
test('renders with a label', () => {
const refinements = {};
renderWithRouter(<SearchBoxBase refinementsFromQueryParams={refinements} />);
renderWithSearchContext(<SearchBoxBase />);

// assert the Paragon <SearchField /> component renders
expect(screen.queryByRole('search')).toBeInTheDocument();
Expand All @@ -22,26 +20,14 @@ describe('<SearchBox />', () => {
});

test('renders with an initial value', () => {
const refinements = {
q: TEST_QUERY,
};
const Component = () => (
<SearchBoxBase
refinementsFromQueryParams={refinements}
defaultRefinement={TEST_QUERY}
/>
);
renderWithRouter(<Component />);
renderWithSearchContext(<SearchBoxBase defaultRefinement={TEST_QUERY} />);

// assert the Paragon <SearchField /> component renders
expect(screen.queryByRole('searchbox')).toHaveAttribute('value', TEST_QUERY);
});

test('handles submit', () => {
const refinements = {};
const { history } = renderWithRouter(<SearchBoxBase
refinementsFromQueryParams={refinements}
/>);
test('handles submit and clear', () => {
const { history } = renderWithSearchContext(<SearchBoxBase />);

// fill in search input and submit the search
fireEvent.change(screen.getByRole('searchbox'), { target: { value: TEST_QUERY } });
Expand All @@ -50,31 +36,12 @@ describe('<SearchBox />', () => {
// assert url is updated with the query
expect(history).toHaveLength(2);
expect(history.location.search).toEqual('?q=test%20query');
});

test('handles clear', async () => {
const refinements = {
q: TEST_QUERY,
page: 2,
};
const Component = () => (
<SearchBoxBase
refinementsFromQueryParams={refinements}
defaultRefinement={TEST_QUERY}
/>
);
const { history } = renderWithRouter(<Component />, {
route: '/?q=test%20query&page=2',
});

// assert query initially exists in url
expect(history.location.search).toEqual('?q=test%20query&page=2');

// clear the input
fireEvent.click(screen.getByText('clear search'));

// assert query no longer exists in url
expect(history).toHaveLength(2);
expect(history).toHaveLength(3);
expect(history.location.search).toEqual('');
});
});
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export { default as SearchHeader } from './course-search/SearchHeader';
export { default as SearchPagination } from './course-search/SearchPagination';
export { useNbHitsFromSearchResults, getCatalogString } from './course-search/data/hooks';
export { SEARCH_FACET_FILTERS, SHOW_ALL_NAME } from './course-search/data/constants';
export { renderWithSearchContext } from './utils/tests';
export {
addToRefinementArray,
deleteRefinementAction,
Expand Down
29 changes: 4 additions & 25 deletions src/utils/tests.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import React from 'react';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { render } from '@testing-library/react';
import { AppContext } from '@edx/frontend-platform/react';
import SearchData from '../course-search/SearchContext';

// eslint-disable import/prefer-default-export
export function renderWithRouter(
ui,
{
Expand All @@ -25,28 +24,8 @@ export function renderWithRouter(
};
}

/* eslint-disable react/prop-types */
export const FakeAppContext = ({
initialAppState = {},
children,
}) => (
<AppContext.Provider value={initialAppState}>
export const renderWithSearchContext = (children) => renderWithRouter(
<SearchData>
{children}
</AppContext.Provider>
</SearchData>,
);
/* eslint-enable react/prop-types */

/* warning, this store may not be complete, please add to it as needed */
export const fakeReduxStore = {
courseEnrollments: {
courseRuns: [],
error: null,
isMarkCourseCompleteSuccess: false,
isMoveToInProgressSuccess: false,
},
offers: {
loading: false,
offersCount: 0,
offers: [],
},
};

0 comments on commit 62a58de

Please sign in to comment.