Skip to content

Commit

Permalink
feat(facets): add a new option "facetOrdering" to Menu, RefinementLis…
Browse files Browse the repository at this point in the history
…t & HierarchicalMenu (algolia/react-instantsearch#3067)

* feat(facetOrdering): add a new option "facetOrdering" to Menu, RefinementList & HierarchicalMenu

If `facetOrdering` is enabled (the default behaviour), before the default sortBy is used, the result from renderingContent.facetOrdering.values is first checked. If that's present, it will be used to sort the items.

You can still change that ordering afterwards with the existing transformItems, so if you are sorting in transformItems, you actually override the sorting done by facet ordering, and won't see the effect. To use facetOrdering, you thus need to remove any sorting done in transformItems.

If there is a facetOrdering present in the index, but you don't want to use it for a certain widget, you need to explicitly pass `facetOrdering: false` to the widget or connector

References:
- [RFC 45](https://github.com/algolia/instantsearch-rfcs/blob/master/accepted/flexible-facet-values.md)
- #4784
- algolia/algoliasearch-helper-js#822

* clarify
  • Loading branch information
Haroenv committed Jul 5, 2021
1 parent 761e9a6 commit 5aff22a
Show file tree
Hide file tree
Showing 7 changed files with 400 additions and 10 deletions.
@@ -1,4 +1,4 @@
import { SearchParameters } from 'algoliasearch-helper';
import { SearchResults, SearchParameters } from 'algoliasearch-helper';
import connect from '../connectHierarchicalMenu';

jest.mock('../../core/createConnector', () => x => x);
Expand Down Expand Up @@ -174,6 +174,159 @@ describe('connectHierarchicalMenu', () => {
expect(props.items).toEqual(['items']);
});

it('facetValues results uses facetOrdering by default', () => {
const props = {
...connect.defaultProps,
attributes: ['lvl0', 'lvl1'],
contextValue,
};
const searchState = { hierarchicalMenu: { lvl0: 'wat' } };
const state = connect.getSearchParameters(
new SearchParameters(),
props,
searchState
);
const results = new SearchResults(state, [
{
hits: [],
renderingContent: {
facetOrdering: {
values: {
lvl0: {
order: ['wat'],
},
lvl1: {
order: ['wat > wut'],
},
},
},
},
facets: {
lvl0: {
wat: 20,
oy: 10,
},
lvl1: {
'wat > wot': 15,
'wat > wut': 5,
},
},
},
]);

const providedProps = connect.getProvidedProps(props, searchState, {
results,
});
expect(providedProps.items).toEqual([
{
label: 'wat',
value: undefined,
count: 20,
isRefined: true,
items: [
{
label: 'wut',
value: 'wat > wut',
count: 5,
isRefined: false,
items: null,
},
{
label: 'wot',
value: 'wat > wot',
count: 15,
isRefined: false,
items: null,
},
],
},
{
label: 'oy',
value: 'oy',
count: 10,
isRefined: false,
items: null,
},
]);
});

it('facetValues results does not use facetOrdering if disabled', () => {
const props = {
attributes: ['lvl0', 'lvl1'],
facetOrdering: false,
contextValue,
};
const searchState = { hierarchicalMenu: { lvl0: 'wat' } };
const state = connect.getSearchParameters(
new SearchParameters(),
props,
searchState
);
const results = new SearchResults(state, [
{
hits: [],
renderingContent: {
facetOrdering: {
values: {
lvl0: {
order: ['wat'],
},
lvl1: {
order: ['wat > wut'],
},
},
},
},
facets: {
lvl0: {
wat: 20,
oy: 10,
},
lvl1: {
'wat > wot': 15,
'wat > wut': 5,
},
},
},
]);

const providedProps = connect.getProvidedProps(props, searchState, {
results,
});
expect(providedProps.items).toEqual([
{
label: 'oy',
value: 'oy',
count: 10,
isRefined: false,
items: null,
},
{
label: 'wat',
value: undefined,
count: 20,
isRefined: true,
items: [
// default ordering: alphabetical
{
label: 'wot',
value: 'wat > wot',
count: 15,
isRefined: false,
items: null,
},
{
label: 'wut',
value: 'wat > wut',
count: 5,
isRefined: false,
items: null,
},
],
},
]);
});

it('shows the effect of showMoreLimit when there is no transformItems', () => {
const results = {
getFacetValues: jest.fn(),
Expand Down
@@ -1,4 +1,4 @@
import { SearchParameters } from 'algoliasearch-helper';
import { SearchParameters, SearchResults } from 'algoliasearch-helper';
import connect from '../connectMenu';

jest.mock('../../core/createConnector', () => x => x);
Expand Down Expand Up @@ -245,6 +245,116 @@ describe('connectMenu', () => {
]);
});

it('facetValues have facetOrdering by default', () => {
const userProps = {
...connect.defaultProps,
attribute: 'ok',
contextValue,
};
const searchState = {
menu: { ok: 'wat' },
};
const parameters = connect.getSearchParameters(
new SearchParameters(),
userProps,
searchState
);

const searchResults = new SearchResults(parameters, [
{
hits: [],
renderingContent: {
facetOrdering: {
values: {
ok: {
order: ['wat'],
},
},
},
},
facets: {
ok: {
wat: 20,
lol: 2000,
},
},
},
]);

const providedProps = connect.getProvidedProps(userProps, searchState, {
results: searchResults,
});

expect(providedProps.items).toEqual([
{
count: 20,
isRefined: true,
label: 'wat',
value: '',
},
{
count: 2000,
isRefined: false,
label: 'lol',
value: 'lol',
},
]);
expect(providedProps.isFromSearch).toBe(false);
});

it('facetValues results does not use facetOrdering if disabled', () => {
const userProps = { attribute: 'ok', facetOrdering: false, contextValue };
const searchState = {
menu: { ok: 'wat' },
};
const parameters = connect.getSearchParameters(
new SearchParameters(),
userProps,
searchState
);

const searchResults = new SearchResults(parameters, [
{
hits: [],
renderingContent: {
facetOrdering: {
values: {
ok: {
order: ['wat'],
},
},
},
},
facets: {
ok: {
wat: 20,
lol: 2000,
},
},
},
]);

const providedProps = connect.getProvidedProps(userProps, searchState, {
results: searchResults,
});

expect(providedProps.items).toEqual([
{
count: 2000,
isRefined: false,
label: 'lol',
value: 'lol',
},
{
count: 20,
isRefined: true,
label: 'wat',
value: '',
},
]);
expect(providedProps.isFromSearch).toBe(false);
});

it("calling refine updates the widget's search state", () => {
const nextState = connect.refine(
{ attribute: 'ok', contextValue },
Expand Down Expand Up @@ -435,13 +545,14 @@ describe('connectMenu', () => {
};

props = connect.getProvidedProps(
{ attribute: 'ok', contextValue },
{ ...connect.defaultProps, attribute: 'ok', contextValue },
{},
{ results }
);

expect(results.getFacetValues).toHaveBeenCalledWith('ok', {
sortBy: ['count:desc', 'name:asc'],
facetOrdering: true,
});

expect(props.items).toEqual([
Expand Down Expand Up @@ -479,13 +590,19 @@ describe('connectMenu', () => {
};

props = connect.getProvidedProps(
{ attribute: 'ok', searchable: true, contextValue },
{
...connect.defaultProps,
attribute: 'ok',
searchable: true,
contextValue,
},
{},
{ results }
);

expect(results.getFacetValues).toHaveBeenCalledWith('ok', {
sortBy: undefined,
facetOrdering: true,
});

expect(props.items).toEqual([
Expand Down

0 comments on commit 5aff22a

Please sign in to comment.