Skip to content

Commit

Permalink
feat(clearRefinements): implement getWidgetRenderState (#4468)
Browse files Browse the repository at this point in the history
  • Loading branch information
francoischalifour authored and Haroenv committed Nov 30, 2020
1 parent 80b348e commit 2b3117c
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 58 deletions.
@@ -1,4 +1,4 @@
import jsHelper, { SearchResults } from 'algoliasearch-helper';
import algoliasearchHelper, { SearchResults } from 'algoliasearch-helper';
import {
createInitOptions,
createRenderOptions,
Expand Down Expand Up @@ -55,7 +55,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin

describe('Lifecycle', () => {
it('renders during init and render', () => {
const helper = jsHelper(createSearchClient(), 'indexName');
const helper = algoliasearchHelper(createSearchClient(), 'indexName');
helper.search = () => helper;
const rendering = jest.fn();
const makeWidget = connectClearRefinements<{ foo: string }>(rendering);
Expand Down Expand Up @@ -114,7 +114,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('does not throw without the unmount function', () => {
const helper = jsHelper(createSearchClient(), 'indexName');
const helper = algoliasearchHelper(createSearchClient(), 'indexName');
const rendering = () => {};
const makeWidget = connectClearRefinements(rendering);
const widget = makeWidget({});
Expand All @@ -123,11 +123,91 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
widget.dispose!({ helper, state: helper.state })
).not.toThrow();
});

describe('getWidgetRenderState', () => {
test('returns the render state', () => {
const renderFn = jest.fn();
const unmountFn = jest.fn();
const createClearRefinements = connectClearRefinements(
renderFn,
unmountFn
);
const clearRefinements = createClearRefinements({});
const helper = algoliasearchHelper(createSearchClient(), 'indexName', {
index: 'indexName',
hierarchicalFacets: [
{
name: 'category',
attributes: ['category', 'subCategory'],
separator: ' > ',
},
],
});

const renderState1 = clearRefinements.getWidgetRenderState!(
{},
createInitOptions()
);

expect(renderState1.clearRefinements).toEqual({
hasRefinements: false,
createURL: expect.any(Function),
refine: expect.any(Function),
widgetParams: {},
});

clearRefinements.init!(createInitOptions());

helper.toggleRefinement('category', 'Decoration');

const renderState2 = clearRefinements.getWidgetRenderState!(
{},
createRenderOptions({
helper,
scopedResults: [
{
indexId: 'indexName',
helper,
results: new SearchResults(helper.state, [
createSingleSearchResponse({
hits: [],
facets: {
category: {
Decoration: 880,
},
subCategory: {
'Decoration > Candle holders & candles': 193,
'Decoration > Frames & pictures': 173,
},
},
}),
createSingleSearchResponse({
facets: {
category: {
Decoration: 880,
Outdoor: 47,
},
},
}),
]),
},
],
})
);

expect(renderState2.clearRefinements).toEqual({
hasRefinements: true,
createURL: expect.any(Function),
refine: expect.any(Function),
widgetParams: {},
});
});
});
});

describe('Instance options', () => {
it('provides a function to clear the refinements', () => {
const helper = jsHelper(createSearchClient(), 'indexName', {
const helper = algoliasearchHelper(createSearchClient(), 'indexName', {
facets: ['myFacet'],
});
helper.search = () => helper;
Expand Down Expand Up @@ -170,7 +250,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('provides a function to clear the refinements and the query', () => {
const helper = jsHelper(createSearchClient(), 'indexName', {
const helper = algoliasearchHelper(createSearchClient(), 'indexName', {
facets: ['myFacet'],
});
helper.search = () => helper;
Expand Down Expand Up @@ -214,7 +294,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('provides the same `refine` and `createURL` function references during the lifecycle', () => {
const helper = jsHelper(createSearchClient(), 'indexName');
const helper = algoliasearchHelper(createSearchClient(), 'indexName');
helper.search = () => helper;

const rendering = jest.fn();
Expand Down Expand Up @@ -258,7 +338,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('gets refinements from results', () => {
const helper = jsHelper(createSearchClient(), '', {
const helper = algoliasearchHelper(createSearchClient(), '', {
facets: ['aFacet'],
});
helper.toggleRefinement('aFacet', 'some value');
Expand Down Expand Up @@ -293,7 +373,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
it('with query not excluded and not empty has refinements', () => {
// test if the values sent to the rendering function
// are consistent with the search state
const helper = jsHelper(createSearchClient(), '', {
const helper = algoliasearchHelper(createSearchClient(), '', {
facets: ['aFacet'],
});
helper.setQuery('no empty');
Expand Down Expand Up @@ -328,7 +408,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('with query not excluded and empty has no refinements', () => {
const helper = jsHelper(createSearchClient(), '', {
const helper = algoliasearchHelper(createSearchClient(), '', {
facets: ['aFacet'],
});
helper.search = () => helper;
Expand Down Expand Up @@ -362,7 +442,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('without includedAttributes or excludedAttributes and with a query has no refinements', () => {
const helper = jsHelper(createSearchClient(), 'indexName');
const helper = algoliasearchHelper(createSearchClient(), 'indexName');
helper.setQuery('not empty');
helper.search = () => helper;

Expand Down Expand Up @@ -393,7 +473,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('includes only includedAttributes', () => {
const helper = jsHelper(createSearchClient(), 'indexName', {
const helper = algoliasearchHelper(createSearchClient(), 'indexName', {
facets: ['facet1', 'facet2'],
});
helper.search = () => helper;
Expand Down Expand Up @@ -446,7 +526,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('includes only includedAttributes (with query)', () => {
const helper = jsHelper(createSearchClient(), 'indexName', {
const helper = algoliasearchHelper(createSearchClient(), 'indexName', {
facets: ['facet1'],
});
helper.search = () => helper;
Expand Down Expand Up @@ -496,7 +576,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('excludes excludedAttributes', () => {
const helper = jsHelper(createSearchClient(), 'indexName', {
const helper = algoliasearchHelper(createSearchClient(), 'indexName', {
facets: ['facet1', 'facet2'],
});
helper.search = () => helper;
Expand Down Expand Up @@ -579,7 +659,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('transformItems is called', () => {
const helper = jsHelper(createSearchClient(), 'indexName', {
const helper = algoliasearchHelper(createSearchClient(), 'indexName', {
facets: ['facet1', 'facet2', 'facet3'],
});
helper.search = () => helper;
Expand Down Expand Up @@ -644,7 +724,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin

describe('createURL', () => {
it('consistent with the list of excludedAttributes', () => {
const helper = jsHelper(createSearchClient(), 'indexName', {
const helper = algoliasearchHelper(createSearchClient(), 'indexName', {
facets: ['facet', 'otherFacet'],
});
helper.search = () => helper;
Expand Down Expand Up @@ -714,7 +794,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/clear-refin
});

it('reset the page to 0', () => {
const helper = jsHelper(createSearchClient(), 'indexName', {});
const helper = algoliasearchHelper(createSearchClient(), 'indexName', {});
helper.search = () => helper;
helper.setQuery('not empty');

Expand Down
113 changes: 71 additions & 42 deletions src/connectors/clear-refinements/connectClearRefinements.ts
@@ -1,3 +1,4 @@
import { AlgoliaSearchHelper } from 'algoliasearch-helper';
import {
checkRendering,
clearRefinements,
Expand Down Expand Up @@ -53,6 +54,11 @@ export type ClearRefinementsConnector = Connector<
ClearRefinementsConnectorParams
>;

type AttributesToClear = {
helper: AlgoliaSearchHelper;
items: string[];
};

const connectClearRefinements: ClearRefinementsConnector = function connectClearRefinements(
renderFn,
unmountFn = noop
Expand All @@ -74,9 +80,16 @@ const connectClearRefinements: ClearRefinementsConnector = function connectClear
);
}

const connectorState = {
type ConnectorState = {
refine(): void;
createURL(): string;
attributesToClear: AttributesToClear[];
};

const connectorState: ConnectorState = {
refine: noop,
createURL: () => '',
attributesToClear: [],
};

const cachedRefine = () => connectorState.refine();
Expand All @@ -85,67 +98,56 @@ const connectClearRefinements: ClearRefinementsConnector = function connectClear
return {
$$type: 'ais.clearRefinements',

init({ instantSearchInstance }) {
init(initOptions) {
const { renderState, instantSearchInstance } = initOptions;

renderFn(
{
hasRefinements: false,
refine: cachedRefine,
createURL: cachedCreateURL,
...this.getWidgetRenderState!(renderState, initOptions)
.clearRefinements!,
instantSearchInstance,
widgetParams,
},
true
);
},

render({ scopedResults, createURL, instantSearchInstance }) {
const attributesToClear = scopedResults.reduce<
Array<ReturnType<typeof getAttributesToClear>>
>((results, scopedResult) => {
return results.concat(
getAttributesToClear({
scopedResult,
includedAttributes,
excludedAttributes,
transformItems,
})
);
}, []);
render(renderOptions) {
const { createURL, renderState, instantSearchInstance } = renderOptions;

connectorState.refine = () => {
attributesToClear.forEach(({ helper: indexHelper, items }) => {
indexHelper
.setState(
clearRefinements({
helper: indexHelper,
attributesToClear: items,
})
)
.search();
});
connectorState.attributesToClear.forEach(
({ helper: indexHelper, items }) => {
indexHelper
.setState(
clearRefinements({
helper: indexHelper,
attributesToClear: items,
})
)
.search();
}
);
};

connectorState.createURL = () =>
createURL(
mergeSearchParameters(
...attributesToClear.map(({ helper: indexHelper, items }) => {
return clearRefinements({
helper: indexHelper,
attributesToClear: items,
});
})
...connectorState.attributesToClear.map(
({ helper: indexHelper, items }) => {
return clearRefinements({
helper: indexHelper,
attributesToClear: items,
});
}
)
)
);

renderFn(
{
hasRefinements: attributesToClear.some(
attributeToClear => attributeToClear.items.length > 0
),
refine: cachedRefine,
createURL: cachedCreateURL,
...this.getWidgetRenderState!(renderState, renderOptions)
.clearRefinements!,
instantSearchInstance,
widgetParams,
},
false
);
Expand All @@ -154,6 +156,33 @@ const connectClearRefinements: ClearRefinementsConnector = function connectClear
dispose() {
unmountFn();
},

getWidgetRenderState(renderState, { scopedResults }) {
connectorState.attributesToClear = scopedResults.reduce<
Array<ReturnType<typeof getAttributesToClear>>
>((results, scopedResult) => {
return results.concat(
getAttributesToClear({
scopedResult,
includedAttributes,
excludedAttributes,
transformItems,
})
);
}, []);

return {
...renderState,
clearRefinements: {
hasRefinements: connectorState.attributesToClear.some(
attributeToClear => attributeToClear.items.length > 0
),
refine: cachedRefine,
createURL: cachedCreateURL,
widgetParams,
},
};
},
};
};
};
Expand All @@ -163,7 +192,7 @@ function getAttributesToClear({
includedAttributes,
excludedAttributes,
transformItems,
}) {
}): AttributesToClear {
const clearsQuery =
includedAttributes.indexOf('query') !== -1 ||
excludedAttributes.indexOf('query') === -1;
Expand Down

0 comments on commit 2b3117c

Please sign in to comment.