Skip to content

Commit

Permalink
feat(connector): test connectRangeSlider
Browse files Browse the repository at this point in the history
In this change, I also had to add some changes:
 - rename the onChange to refine to be more consistent with the rest of
the API
 - let the dev set the value at the init phase
 - rename oldValues to bounds for better semantic of the code (important
to understand a failing test)
  • Loading branch information
Alexandre Stanislawski committed Mar 2, 2017
1 parent f5dfba7 commit 4f6c180
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 22 deletions.
190 changes: 190 additions & 0 deletions src/connectors/range-slider/__tests__/connectRangeSlider-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/* eslint-env mocha */

import expect from 'expect';
import sinon from 'sinon';

import jsHelper from 'algoliasearch-helper';
const SearchResults = jsHelper.SearchResults;

import connectRangeSlider from '../connectRangeSlider.js';

const fakeClient = {addAlgoliaAgent: () => {}};

describe('connectRangeSlider', () => {
it('Renders during init and render', () => {
const container = document.createElement('div');
// test that the dummyRendering is called with the isFirstRendering
// flag set accordingly
const rendering = sinon.stub();
const makeWidget = connectRangeSlider(rendering);

const attributeName = 'price';
const widget = makeWidget({
container,
attributeName,
});

const config = widget.getConfiguration();
expect(config).toEqual({
disjunctiveFacets: [attributeName],
});

const helper = jsHelper(fakeClient, '', config);
helper.search = sinon.stub();

widget.init({
helper,
state: helper.state,
createURL: () => '#',
onHistoryChange: () => {},
});

{ // should call the rendering once with isFirstRendering to true
expect(rendering.callCount).toBe(1);
const isFirstRendering = rendering.lastCall.args[1];
expect(isFirstRendering).toBe(true);

// should provide good values for the first rendering
const {range, collapsible, start,
shouldAutoHideContainer, containerNode} = rendering.lastCall.args[0];
expect(range).toEqual({min: 0, max: 0});
expect(start).toEqual([-Infinity, Infinity]);
expect(collapsible).toBe(false);
expect(shouldAutoHideContainer).toBe(true);
expect(containerNode).toBe(container);
}

widget.render({
results: new SearchResults(helper.state, [{
hits: [{test: 'oneTime'}],
facets: {price: {10: 1, 20: 1, 30: 1}},
facets_stats: { // eslint-disable-line
price: {
avg: 20,
max: 30,
min: 10,
sum: 60,
},
},
nbHits: 1,
nbPages: 1,
page: 0,
}]),
state: helper.state,
helper,
createURL: () => '#',
});

{ // Should call the rendering a second time, with isFirstRendering to false
expect(rendering.callCount).toBe(2);
const isFirstRendering = rendering.lastCall.args[1];
expect(isFirstRendering).toBe(false);

// should provide good values for the first rendering
const {range, collapsible, start,
shouldAutoHideContainer, containerNode} = rendering.lastCall.args[0];
expect(range).toEqual({min: 10, max: 30});
expect(start).toEqual([-Infinity, Infinity]);
expect(collapsible).toBe(false);
expect(shouldAutoHideContainer).toBe(false);
expect(containerNode).toBe(container);
}
});

it('Accepts some user bounds', () => {
const container = document.createElement('div');
const makeWidget = connectRangeSlider(() => {});

const attributeName = 'price';

expect(makeWidget({container, attributeName, min: 0}).getConfiguration()).toEqual({
disjunctiveFacets: [attributeName],
numericRefinements: {
[attributeName]: {'>=': [0]},
},
});

expect(makeWidget({container, attributeName, max: 100}).getConfiguration()).toEqual({
disjunctiveFacets: [attributeName],
numericRefinements: {
[attributeName]: {'<=': [100]},
},
});

expect(makeWidget({container, attributeName, min: 0, max: 100}).getConfiguration()).toEqual({
disjunctiveFacets: [attributeName],
numericRefinements: {
[attributeName]: {
'>=': [0],
'<=': [100],
},
},
});
});

it('Provides a function to update the refinements at each step', () => {
const container = document.createElement('div');

const rendering = sinon.stub();
const makeWidget = connectRangeSlider(rendering);

const attributeName = 'price';
const widget = makeWidget({
container,
attributeName,
});

const helper = jsHelper(fakeClient, '', widget.getConfiguration());
helper.search = sinon.stub();

widget.init({
helper,
state: helper.state,
createURL: () => '#',
onHistoryChange: () => {},
});

{ // first rendering
expect(helper.getNumericRefinement('price', '>=')).toEqual(undefined);
expect(helper.getNumericRefinement('price', '<=')).toEqual(undefined);
const renderOptions = rendering.lastCall.args[0];
const {refine} = renderOptions;
refine([10, 30]);
expect(helper.getNumericRefinement('price', '>=')).toEqual([10]);
expect(helper.getNumericRefinement('price', '<=')).toEqual([30]);
expect(helper.search.callCount).toBe(1);
}

widget.render({
results: new SearchResults(helper.state, [{
hits: [{test: 'oneTime'}],
facets: {price: {10: 1, 20: 1, 30: 1}},
facets_stats: { // eslint-disable-line
price: {
avg: 20,
max: 30,
min: 10,
sum: 60,
},
},
nbHits: 1,
nbPages: 1,
page: 0,
}, {}]),
state: helper.state,
helper,
createURL: () => '#',
});

{ // Second rendering
expect(helper.getNumericRefinement('price', '>=')).toEqual([10]);
expect(helper.getNumericRefinement('price', '<=')).toEqual([30]);
const renderOptions = rendering.lastCall.args[0];
const {refine} = renderOptions;
refine([23, 27]);
expect(helper.getNumericRefinement('price', '>=')).toEqual([23]);
expect(helper.getNumericRefinement('price', '<=')).toEqual([27]);
expect(helper.search.callCount).toBe(2);
}
});
});
33 changes: 13 additions & 20 deletions src/connectors/range-slider/connectRangeSlider.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,22 +95,15 @@ const connectRangeSlider = rangeSliderRendering => ({
disjunctiveFacets: [attributeName],
};

if (
(userMin !== undefined || userMax !== undefined)
&&
(!originalConf ||
originalConf.numericRefinements &&
originalConf.numericRefinements[attributeName] === undefined)
) {
conf.numericRefinements = {[attributeName]: {}};

if (userMin !== undefined) {
conf.numericRefinements[attributeName]['>='] = [userMin];
}
const hasUserBounds = userMin !== undefined || userMax !== undefined;
const boundsNotAlreadyDefined = !originalConf ||
originalConf.numericRefinements &&
originalConf.numericRefinements[attributeName] === undefined;

if (userMax !== undefined) {
conf.numericRefinements[attributeName]['<='] = [userMax];
}
if (hasUserBounds && boundsNotAlreadyDefined) {
conf.numericRefinements = {[attributeName]: {}};
if (userMin !== undefined) conf.numericRefinements[attributeName]['>='] = [userMin];
if (userMax !== undefined) conf.numericRefinements[attributeName]['<='] = [userMax];
}

return conf;
Expand Down Expand Up @@ -142,12 +135,12 @@ const connectRangeSlider = rangeSliderRendering => ({
templatesConfig,
templates,
});
this._refine = oldValues => newValues => {
this._refine = bounds => newValues => {
helper.clearRefinements(attributeName);
if (newValues[0] > oldValues.min) {
if (!bounds.min || newValues[0] > bounds.min) {
helper.addNumericRefinement(attributeName, '>=', formatToNumber(newValues[0]));
}
if (newValues[1] < oldValues.max) {
if (!bounds.max || newValues[1] < bounds.max) {
helper.addNumericRefinement(attributeName, '<=', formatToNumber(newValues[1]));
}
helper.search();
Expand All @@ -162,7 +155,7 @@ const connectRangeSlider = rangeSliderRendering => ({
rangeSliderRendering({
collapsible,
cssClasses,
onChange: this._refine(stats),
refine: this._refine(stats),
pips,
range: {min: Math.floor(stats.min), max: Math.ceil(stats.max)},
shouldAutoHideContainer: autoHideContainer && stats.min === stats.max,
Expand Down Expand Up @@ -193,7 +186,7 @@ const connectRangeSlider = rangeSliderRendering => ({
rangeSliderRendering({
collapsible,
cssClasses,
onChange: this._refine(stats),
refine: this._refine(stats),
pips,
range: {min: Math.floor(stats.min), max: Math.ceil(stats.max)},
shouldAutoHideContainer: autoHideContainer && stats.min === stats.max,
Expand Down
4 changes: 2 additions & 2 deletions src/widgets/range-slider/range-slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default connectRangeSlider(defaultRendering);
function defaultRendering({
collapsible,
cssClasses,
onChange,
refine,
pips,
range,
shouldAutoHideContainer,
Expand All @@ -52,7 +52,7 @@ function defaultRendering({
<Slider
collapsible={collapsible}
cssClasses={cssClasses}
onChange={onChange}
onChange={refine}
pips={pips}
range={range}
shouldAutoHideContainer={shouldAutoHideContainer}
Expand Down

0 comments on commit 4f6c180

Please sign in to comment.