diff --git a/src/connectors/hits-per-page/__tests__/__snapshots__/connectHitsPerPage-test.js.snap b/src/connectors/hits-per-page/__tests__/__snapshots__/connectHitsPerPage-test.js.snap index 9f20568a55..8e44c7cfce 100644 --- a/src/connectors/hits-per-page/__tests__/__snapshots__/connectHitsPerPage-test.js.snap +++ b/src/connectors/hits-per-page/__tests__/__snapshots__/connectHitsPerPage-test.js.snap @@ -13,8 +13,9 @@ Array [ "value": 10, }, Object { + "default": true, "isRefined": true, - "label": "", + "label": "7 items per page", "value": 7, }, ] @@ -33,31 +34,10 @@ Array [ "value": 10, }, Object { + "default": true, "isRefined": false, - "label": "", + "label": "7 items per page", "value": 7, }, ] `; - -exports[`connectHitsPerPage routing getWidgetSearchParameters should add the refinements according to the UI state provided 1`] = ` -SearchParameters { - "disjunctiveFacets": Array [], - "disjunctiveFacetsRefinements": Object {}, - "facets": Array [], - "facetsExcludes": Object {}, - "facetsRefinements": Object {}, - "hierarchicalFacets": Array [], - "hierarchicalFacetsRefinements": Object {}, - "hitsPerPage": 10, - "index": "", - "numericRefinements": Object {}, - "tagRefinements": Array [], -} -`; - -exports[`connectHitsPerPage routing getWidgetState should add an entry equal to the refinement 1`] = ` -Object { - "hitsPerPage": 10, -} -`; diff --git a/src/connectors/hits-per-page/__tests__/connectHitsPerPage-test.js b/src/connectors/hits-per-page/__tests__/connectHitsPerPage-test.js index f10f3a6076..12819f273e 100644 --- a/src/connectors/hits-per-page/__tests__/connectHitsPerPage-test.js +++ b/src/connectors/hits-per-page/__tests__/connectHitsPerPage-test.js @@ -14,6 +14,33 @@ describe('connectHitsPerPage', () => { }).toThrowErrorMatchingInlineSnapshot(` "The \`items\` option expects an array of objects. +See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-page/js/#connector" +`); + }); + + it('throws with empty items', () => { + expect(() => { + connectHitsPerPage(() => {})({ + items: [], + }); + }).toThrowErrorMatchingInlineSnapshot(` +"A default value must be specified in \`items\`. + +See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-page/js/#connector" +`); + }); + + it('throws without default item', () => { + expect(() => { + connectHitsPerPage(() => {})({ + items: [ + { value: 3, label: '3 items per page' }, + { value: 10, label: '10 items per page' }, + ], + }); + }).toThrowErrorMatchingInlineSnapshot(` +"A default value must be specified in \`items\`. + See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-page/js/#connector" `); }); @@ -33,12 +60,25 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa `); }); + it('does not throw with items and one default value', () => { + expect(() => { + connectHitsPerPage(() => {})({ + items: [ + { value: 3, label: '3 items per page', default: true }, + { value: 10, label: '10 items per page' }, + ], + }); + }).not.toThrow(); + }); + it('is a widget', () => { const render = jest.fn(); const unmount = jest.fn(); const customHitsPerPage = connectHitsPerPage(render, unmount); - const widget = customHitsPerPage({ items: [] }); + const widget = customHitsPerPage({ + items: [{ label: '10 items per page', value: 10, default: true }], + }); expect(widget).toEqual( expect.objectContaining({ @@ -59,13 +99,15 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa const makeWidget = connectHitsPerPage(renderFn); const widget = makeWidget({ items: [ - { value: 3, label: '3 items per page' }, + { value: 3, label: '3 items per page', default: true }, { value: 10, label: '10 items per page' }, ], }); expect(widget.getConfiguration(new SearchParameters({}))).toEqual( - new SearchParameters({}) + new SearchParameters({ + hitsPerPage: 3, + }) ); expect(renderFn).toHaveBeenCalledTimes(0); @@ -86,7 +128,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa expect.objectContaining({ widgetParams: { items: [ - { value: 3, label: '3 items per page' }, + { value: 3, label: '3 items per page', default: true }, { value: 10, label: '10 items per page' }, ], }, @@ -106,7 +148,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa expect.objectContaining({ widgetParams: { items: [ - { value: 3, label: '3 items per page' }, + { value: 3, label: '3 items per page', default: true }, { value: 10, label: '10 items per page' }, ], }, @@ -120,7 +162,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa const makeWidget = connectHitsPerPage(renderFn); const widget = makeWidget({ items: [ - { value: 3, label: '3 items per page' }, + { value: 3, label: '3 items per page', default: true }, { value: 10, label: '10 items per page' }, ], transformItems: items => @@ -200,21 +242,6 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa ); }); - it('Does not configures the search when there is no default value', () => { - const renderFn = jest.fn(); - const makeWidget = connectHitsPerPage(renderFn); - const widget = makeWidget({ - items: [ - { value: 3, label: '3 items per page' }, - { value: 10, label: '10 items per page' }, - ], - }); - - expect(widget.getConfiguration(new SearchParameters({}))).toEqual( - new SearchParameters({}) - ); - }); - it('Provide a function to change the current hits per page, and provide the current value', () => { const renderFn = jest.fn(); const makeWidget = connectHitsPerPage(renderFn); @@ -222,7 +249,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa items: [ { value: 3, label: '3 items per page' }, { value: 10, label: '10 items per page' }, - { value: 11, label: '' }, + { value: 11, label: '11 items per page', default: true }, ], }); @@ -266,7 +293,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa items: [ { value: 3, label: '3 items per page' }, { value: 10, label: '10 items per page' }, - { value: 20, label: '20 items per page' }, + { value: 20, label: '20 items per page', default: true }, ], }); @@ -304,7 +331,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa items: [ { value: 3, label: '3 items per page' }, { value: 10, label: '10 items per page' }, - { value: 7, label: '' }, + { value: 7, label: '7 items per page', default: true }, ], }); @@ -339,7 +366,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa const makeWidget = connectHitsPerPage(renderFn); const widget = makeWidget({ items: [ - { value: 3, label: '3 items per page' }, + { value: 3, label: '3 items per page', default: true }, { value: 10, label: '10 items per page' }, ], }); @@ -381,7 +408,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa const makeWidget = connectHitsPerPage(renderFn); const widget = makeWidget({ items: [ - { value: 3, label: '3 items per page' }, + { value: 3, label: '3 items per page', default: true }, { value: 10, label: '10 items per page' }, ], }); @@ -423,7 +450,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa const makeWidget = connectHitsPerPage(renderFn); const widget = makeWidget({ items: [ - { value: 3, label: '3 items per page' }, + { value: 3, label: '3 items per page', default: true }, { value: 10, label: '10 items per page' }, ], }); @@ -469,7 +496,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa const makeWidget = connectHitsPerPage(renderFn, unmountFn); const widget = makeWidget({ items: [ - { value: 3, label: '3 items per page' }, + { value: 3, label: '3 items per page', default: true }, { value: 10, label: '10 items per page' }, ], }); @@ -488,7 +515,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa const makeWidget = connectHitsPerPage(renderFn); const widget = makeWidget({ items: [ - { value: 3, label: '3 items per page' }, + { value: 3, label: '3 items per page', default: true }, { value: 10, label: '10 items per page' }, ], }); @@ -508,7 +535,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa const makeWidget = connectHitsPerPage(renderFn, unmountFn); const widget = makeWidget({ items: [ - { value: 3, label: '3 items per page' }, + { value: 3, label: '3 items per page', default: true }, { value: 10, label: '10 items per page' }, ], }); @@ -521,116 +548,113 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits-per-pa }); }); - describe('routing', () => { - const getInitializedWidget = () => { - const renderFn = jest.fn(); - const makeWidget = connectHitsPerPage(renderFn); + describe('getWidgetState', () => { + test('returns the `uiState` empty', () => { + const render = jest.fn(); + const makeWidget = connectHitsPerPage(render); + const helper = algoliasearchHelper({}, 'indexName'); const widget = makeWidget({ items: [ { value: 3, label: '3 items per page', default: true }, - { value: 10, label: '10 items per page' }, + { value: 22, label: '22 items per page' }, ], }); - const helper = algoliasearchHelper( + const actual = widget.getWidgetState( {}, - '', - widget.getConfiguration(new SearchParameters({})) + { + searchParameters: helper.state, + } ); - helper.search = jest.fn(); - - widget.init({ - helper, - state: helper.state, - createURL: () => '#', - }); - const { refine } = renderFn.mock.calls[0][0]; + expect(actual).toEqual({}); + }); - return [widget, helper, refine]; - }; + test('returns the `uiState` with a refinement', () => { + const render = jest.fn(); + const makeWidget = connectHitsPerPage(render); + const helper = algoliasearchHelper({}, 'indexName', { + hitsPerPage: '22', + }); + const widget = makeWidget({ + items: [ + { value: 3, label: '3 items per page', default: true }, + { value: 22, label: '22 items per page' }, + ], + }); - describe('getWidgetState', () => { - test('should give back the object unmodified if there are no refinements', () => { - const [widget, helper] = getInitializedWidget(); - const uiStateBefore = {}; - const uiStateAfter = widget.getWidgetState(uiStateBefore, { + const actual = widget.getWidgetState( + {}, + { searchParameters: helper.state, - helper, - }); + } + ); - expect(uiStateAfter).toBe(uiStateBefore); + expect(actual).toEqual({ + hitsPerPage: 22, }); + }); + }); - test('should not add an entry when the default value is selected', () => { - const [widget, helper] = getInitializedWidget(); - helper.setQueryParameter('hitsPerPage', 3); - const uiStateBefore = {}; - const uiStateAfter = widget.getWidgetState(uiStateBefore, { - searchParameters: helper.state, - helper, - }); + describe('getWidgetSearchParameters', () => { + test('returns the `SearchParameters` with the default value', () => { + const render = jest.fn(); + const makeWidget = connectHitsPerPage(render); + const helper = algoliasearchHelper({}, 'indexName'); + const widget = makeWidget({ + items: [ + { value: 3, label: '3 items per page', default: true }, + { value: 22, label: '22 items per page' }, + ], + }); - expect(uiStateAfter).toBe(uiStateBefore); + const actual = widget.getWidgetSearchParameters(helper.state, { + uiState: {}, }); - test('should add an entry equal to the refinement', () => { - const [widget, helper] = getInitializedWidget(); - helper.setQueryParameter('hitsPerPage', 10); - const uiStateBefore = {}; - const uiStateAfter = widget.getWidgetState(uiStateBefore, { - searchParameters: helper.state, - helper, - }); + expect(actual.hitsPerPage).toEqual(3); + }); - expect(uiStateAfter).toMatchSnapshot(); + test('returns the `SearchParameters` with the value from `uiState`', () => { + const render = jest.fn(); + const makeWidget = connectHitsPerPage(render); + const helper = algoliasearchHelper({}, 'indexName'); + const widget = makeWidget({ + items: [ + { value: 3, label: '3 items per page', default: true }, + { value: 22, label: '22 items per page' }, + ], }); - test('should give back the object unmodified if refinements are already set', () => { - const [widget, helper] = getInitializedWidget(); - const uiStateBefore = { - hitsPerPage: 10, - }; - helper.setQueryParameter('hitsPerPage', 10); - const uiStateAfter = widget.getWidgetState(uiStateBefore, { - searchParameters: helper.state, - helper, - }); - - expect(uiStateAfter).toBe(uiStateBefore); + const actual = widget.getWidgetSearchParameters(helper.state, { + uiState: { + hitsPerPage: 22, + }, }); + + expect(actual.hitsPerPage).toEqual(22); }); - describe('getWidgetSearchParameters', () => { - test('should return the same SP if there are no refinements in the UI state', () => { - const [widget, helper] = getInitializedWidget(); - // The URL contains nothing - const uiState = {}; - // The current search is empty - const searchParametersBefore = SearchParameters.make(helper.state); - const searchParametersAfter = widget.getWidgetSearchParameters( - searchParametersBefore, - { uiState } - ); - // Applying the empty UI state should not create a new object - expect(searchParametersAfter).toBe(searchParametersBefore); + test('returns the `SearchParameters` with the value from `uiState` without the previous refinement', () => { + const render = jest.fn(); + const makeWidget = connectHitsPerPage(render); + const helper = algoliasearchHelper({}, 'indexName', { + hitsPerPage: 22, + }); + const widget = makeWidget({ + items: [ + { value: 3, label: '3 items per page', default: true }, + { value: 22, label: '22 items per page' }, + ], }); - test('should add the refinements according to the UI state provided', () => { - const [widget, helper] = getInitializedWidget(); - // The URL contains some values for the widget - const uiState = { - hitsPerPage: 10, - }; - // Current the search is empty - const searchParametersBefore = SearchParameters.make(helper.state); - const searchParametersAfter = widget.getWidgetSearchParameters( - searchParametersBefore, - { uiState } - ); - // Applying the UI state should add the new configuration - expect(searchParametersAfter).toMatchSnapshot(); + const actual = widget.getWidgetSearchParameters(helper.state, { + uiState: { + hitsPerPage: 33, + }, }); + + expect(actual.hitsPerPage).toEqual(33); }); }); }); diff --git a/src/connectors/hits-per-page/connectHitsPerPage.js b/src/connectors/hits-per-page/connectHitsPerPage.js index 1d22506068..d158877d68 100644 --- a/src/connectors/hits-per-page/connectHitsPerPage.js +++ b/src/connectors/hits-per-page/connectHitsPerPage.js @@ -2,7 +2,6 @@ import { checkRendering, warning, createDocumentationMessageGenerator, - find, noop, } from '../../lib/utils'; @@ -108,25 +107,28 @@ export default function connectHitsPerPage(renderFn, unmountFn = noop) { ); } - const defaultValues = items.filter(item => item.default); - if (defaultValues.length > 1) { + const defaultItems = items.filter(item => item.default === true); + + if (defaultItems.length === 0) { + throw new Error( + withUsage(`A default value must be specified in \`items\`.`) + ); + } + + if (defaultItems.length > 1) { throw new Error( withUsage('More than one default value is specified in `items`.') ); } - const defaultValue = find(userItems, item => item.default === true); + const defaultItem = defaultItems[0]; return { $$type: 'ais.hitsPerPage', getConfiguration(state) { - if (!defaultValue) { - return state; - } - return state.setQueryParameters({ - hitsPerPage: state.hitsPerPage || defaultValue.value, + hitsPerPage: state.hitsPerPage || defaultItem.value, }); }, @@ -214,11 +216,8 @@ You may want to add another entry to the \`items\` option with this value.` getWidgetState(uiState, { searchParameters }) { const hitsPerPage = searchParameters.hitsPerPage; - if ( - (defaultValue && hitsPerPage === defaultValue.value) || - hitsPerPage === undefined || - uiState.hitsPerPage === hitsPerPage - ) { + + if (hitsPerPage === undefined) { return uiState; } @@ -229,19 +228,9 @@ You may want to add another entry to the \`items\` option with this value.` }, getWidgetSearchParameters(searchParameters, { uiState }) { - const hitsPerPage = uiState.hitsPerPage; - if (hitsPerPage) - return searchParameters.setQueryParameter( - 'hitsPerPage', - uiState.hitsPerPage - ); - if (defaultValue) { - return searchParameters.setQueryParameter( - 'hitsPerPage', - defaultValue.value - ); - } - return searchParameters.setQueryParameter('hitsPerPage', undefined); + return searchParameters.setQueryParameters({ + hitsPerPage: uiState.hitsPerPage || defaultItem.value, + }); }, }; }; diff --git a/src/widgets/hits-per-page/__tests__/__snapshots__/hits-per-page-test.js.snap b/src/widgets/hits-per-page/__tests__/__snapshots__/hits-per-page-test.js.snap index 22428311ed..c2be197db1 100644 --- a/src/widgets/hits-per-page/__tests__/__snapshots__/hits-per-page-test.js.snap +++ b/src/widgets/hits-per-page/__tests__/__snapshots__/hits-per-page-test.js.snap @@ -16,6 +16,7 @@ exports[`hitsPerPage() calls twice render(, container) 1`] = ` options={ Array [ Object { + "default": true, "isRefined": true, "label": "10 results", "value": 10, diff --git a/src/widgets/hits-per-page/__tests__/hits-per-page-test.js b/src/widgets/hits-per-page/__tests__/hits-per-page-test.js index 90fff33c11..a2347f2a39 100644 --- a/src/widgets/hits-per-page/__tests__/hits-per-page-test.js +++ b/src/widgets/hits-per-page/__tests__/hits-per-page-test.js @@ -34,7 +34,7 @@ describe('hitsPerPage()', () => { beforeEach(() => { container = document.createElement('div'); items = [ - { value: 10, label: '10 results' }, + { value: 10, label: '10 results', default: true }, { value: 20, label: '20 results' }, ]; cssClasses = { @@ -61,14 +61,7 @@ describe('hitsPerPage()', () => { render.mockClear(); }); - it('does not configure the default hits per page if not specified', () => { - expect(typeof widget.getConfiguration).toEqual('function'); - expect(widget.getConfiguration(new SearchParameters({}))).toEqual( - new SearchParameters({}) - ); - }); - - it('does configures the default hits per page if specified', () => { + it('configures the default hits per page', () => { const widgetWithDefaults = hitsPerPage({ container: document.createElement('div'), items: [ diff --git a/stories/hits-per-page.stories.js b/stories/hits-per-page.stories.js index b7316ff232..38a9153f92 100644 --- a/stories/hits-per-page.stories.js +++ b/stories/hits-per-page.stories.js @@ -9,8 +9,7 @@ storiesOf('HitsPerPage', module) instantsearch.widgets.hitsPerPage({ container, items: [ - { value: 3, label: '3 per page' }, - { value: 4, label: '4 per page' }, + { value: 3, label: '3 per page', default: true }, { value: 5, label: '5 per page' }, { value: 10, label: '10 per page' }, ], @@ -18,21 +17,6 @@ storiesOf('HitsPerPage', module) ); }) ) - .add( - 'with default hitPerPage to 5', - withHits(({ search, container, instantsearch }) => { - search.addWidget( - instantsearch.widgets.hitsPerPage({ - container, - items: [ - { value: 3, label: '3 per page' }, - { value: 5, label: '5 per page', default: true }, - { value: 10, label: '10 per page' }, - ], - }) - ); - }) - ) .add( 'with transformed items', withHits(({ search, container, instantsearch }) => {