Skip to content

Commit 4f6c180

Browse files
author
Alexandre Stanislawski
committed
feat(connector): test connectRangeSlider
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)
1 parent f5dfba7 commit 4f6c180

File tree

3 files changed

+205
-22
lines changed

3 files changed

+205
-22
lines changed
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/* eslint-env mocha */
2+
3+
import expect from 'expect';
4+
import sinon from 'sinon';
5+
6+
import jsHelper from 'algoliasearch-helper';
7+
const SearchResults = jsHelper.SearchResults;
8+
9+
import connectRangeSlider from '../connectRangeSlider.js';
10+
11+
const fakeClient = {addAlgoliaAgent: () => {}};
12+
13+
describe('connectRangeSlider', () => {
14+
it('Renders during init and render', () => {
15+
const container = document.createElement('div');
16+
// test that the dummyRendering is called with the isFirstRendering
17+
// flag set accordingly
18+
const rendering = sinon.stub();
19+
const makeWidget = connectRangeSlider(rendering);
20+
21+
const attributeName = 'price';
22+
const widget = makeWidget({
23+
container,
24+
attributeName,
25+
});
26+
27+
const config = widget.getConfiguration();
28+
expect(config).toEqual({
29+
disjunctiveFacets: [attributeName],
30+
});
31+
32+
const helper = jsHelper(fakeClient, '', config);
33+
helper.search = sinon.stub();
34+
35+
widget.init({
36+
helper,
37+
state: helper.state,
38+
createURL: () => '#',
39+
onHistoryChange: () => {},
40+
});
41+
42+
{ // should call the rendering once with isFirstRendering to true
43+
expect(rendering.callCount).toBe(1);
44+
const isFirstRendering = rendering.lastCall.args[1];
45+
expect(isFirstRendering).toBe(true);
46+
47+
// should provide good values for the first rendering
48+
const {range, collapsible, start,
49+
shouldAutoHideContainer, containerNode} = rendering.lastCall.args[0];
50+
expect(range).toEqual({min: 0, max: 0});
51+
expect(start).toEqual([-Infinity, Infinity]);
52+
expect(collapsible).toBe(false);
53+
expect(shouldAutoHideContainer).toBe(true);
54+
expect(containerNode).toBe(container);
55+
}
56+
57+
widget.render({
58+
results: new SearchResults(helper.state, [{
59+
hits: [{test: 'oneTime'}],
60+
facets: {price: {10: 1, 20: 1, 30: 1}},
61+
facets_stats: { // eslint-disable-line
62+
price: {
63+
avg: 20,
64+
max: 30,
65+
min: 10,
66+
sum: 60,
67+
},
68+
},
69+
nbHits: 1,
70+
nbPages: 1,
71+
page: 0,
72+
}]),
73+
state: helper.state,
74+
helper,
75+
createURL: () => '#',
76+
});
77+
78+
{ // Should call the rendering a second time, with isFirstRendering to false
79+
expect(rendering.callCount).toBe(2);
80+
const isFirstRendering = rendering.lastCall.args[1];
81+
expect(isFirstRendering).toBe(false);
82+
83+
// should provide good values for the first rendering
84+
const {range, collapsible, start,
85+
shouldAutoHideContainer, containerNode} = rendering.lastCall.args[0];
86+
expect(range).toEqual({min: 10, max: 30});
87+
expect(start).toEqual([-Infinity, Infinity]);
88+
expect(collapsible).toBe(false);
89+
expect(shouldAutoHideContainer).toBe(false);
90+
expect(containerNode).toBe(container);
91+
}
92+
});
93+
94+
it('Accepts some user bounds', () => {
95+
const container = document.createElement('div');
96+
const makeWidget = connectRangeSlider(() => {});
97+
98+
const attributeName = 'price';
99+
100+
expect(makeWidget({container, attributeName, min: 0}).getConfiguration()).toEqual({
101+
disjunctiveFacets: [attributeName],
102+
numericRefinements: {
103+
[attributeName]: {'>=': [0]},
104+
},
105+
});
106+
107+
expect(makeWidget({container, attributeName, max: 100}).getConfiguration()).toEqual({
108+
disjunctiveFacets: [attributeName],
109+
numericRefinements: {
110+
[attributeName]: {'<=': [100]},
111+
},
112+
});
113+
114+
expect(makeWidget({container, attributeName, min: 0, max: 100}).getConfiguration()).toEqual({
115+
disjunctiveFacets: [attributeName],
116+
numericRefinements: {
117+
[attributeName]: {
118+
'>=': [0],
119+
'<=': [100],
120+
},
121+
},
122+
});
123+
});
124+
125+
it('Provides a function to update the refinements at each step', () => {
126+
const container = document.createElement('div');
127+
128+
const rendering = sinon.stub();
129+
const makeWidget = connectRangeSlider(rendering);
130+
131+
const attributeName = 'price';
132+
const widget = makeWidget({
133+
container,
134+
attributeName,
135+
});
136+
137+
const helper = jsHelper(fakeClient, '', widget.getConfiguration());
138+
helper.search = sinon.stub();
139+
140+
widget.init({
141+
helper,
142+
state: helper.state,
143+
createURL: () => '#',
144+
onHistoryChange: () => {},
145+
});
146+
147+
{ // first rendering
148+
expect(helper.getNumericRefinement('price', '>=')).toEqual(undefined);
149+
expect(helper.getNumericRefinement('price', '<=')).toEqual(undefined);
150+
const renderOptions = rendering.lastCall.args[0];
151+
const {refine} = renderOptions;
152+
refine([10, 30]);
153+
expect(helper.getNumericRefinement('price', '>=')).toEqual([10]);
154+
expect(helper.getNumericRefinement('price', '<=')).toEqual([30]);
155+
expect(helper.search.callCount).toBe(1);
156+
}
157+
158+
widget.render({
159+
results: new SearchResults(helper.state, [{
160+
hits: [{test: 'oneTime'}],
161+
facets: {price: {10: 1, 20: 1, 30: 1}},
162+
facets_stats: { // eslint-disable-line
163+
price: {
164+
avg: 20,
165+
max: 30,
166+
min: 10,
167+
sum: 60,
168+
},
169+
},
170+
nbHits: 1,
171+
nbPages: 1,
172+
page: 0,
173+
}, {}]),
174+
state: helper.state,
175+
helper,
176+
createURL: () => '#',
177+
});
178+
179+
{ // Second rendering
180+
expect(helper.getNumericRefinement('price', '>=')).toEqual([10]);
181+
expect(helper.getNumericRefinement('price', '<=')).toEqual([30]);
182+
const renderOptions = rendering.lastCall.args[0];
183+
const {refine} = renderOptions;
184+
refine([23, 27]);
185+
expect(helper.getNumericRefinement('price', '>=')).toEqual([23]);
186+
expect(helper.getNumericRefinement('price', '<=')).toEqual([27]);
187+
expect(helper.search.callCount).toBe(2);
188+
}
189+
});
190+
});

src/connectors/range-slider/connectRangeSlider.js

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -95,22 +95,15 @@ const connectRangeSlider = rangeSliderRendering => ({
9595
disjunctiveFacets: [attributeName],
9696
};
9797

98-
if (
99-
(userMin !== undefined || userMax !== undefined)
100-
&&
101-
(!originalConf ||
102-
originalConf.numericRefinements &&
103-
originalConf.numericRefinements[attributeName] === undefined)
104-
) {
105-
conf.numericRefinements = {[attributeName]: {}};
106-
107-
if (userMin !== undefined) {
108-
conf.numericRefinements[attributeName]['>='] = [userMin];
109-
}
98+
const hasUserBounds = userMin !== undefined || userMax !== undefined;
99+
const boundsNotAlreadyDefined = !originalConf ||
100+
originalConf.numericRefinements &&
101+
originalConf.numericRefinements[attributeName] === undefined;
110102

111-
if (userMax !== undefined) {
112-
conf.numericRefinements[attributeName]['<='] = [userMax];
113-
}
103+
if (hasUserBounds && boundsNotAlreadyDefined) {
104+
conf.numericRefinements = {[attributeName]: {}};
105+
if (userMin !== undefined) conf.numericRefinements[attributeName]['>='] = [userMin];
106+
if (userMax !== undefined) conf.numericRefinements[attributeName]['<='] = [userMax];
114107
}
115108

116109
return conf;
@@ -142,12 +135,12 @@ const connectRangeSlider = rangeSliderRendering => ({
142135
templatesConfig,
143136
templates,
144137
});
145-
this._refine = oldValues => newValues => {
138+
this._refine = bounds => newValues => {
146139
helper.clearRefinements(attributeName);
147-
if (newValues[0] > oldValues.min) {
140+
if (!bounds.min || newValues[0] > bounds.min) {
148141
helper.addNumericRefinement(attributeName, '>=', formatToNumber(newValues[0]));
149142
}
150-
if (newValues[1] < oldValues.max) {
143+
if (!bounds.max || newValues[1] < bounds.max) {
151144
helper.addNumericRefinement(attributeName, '<=', formatToNumber(newValues[1]));
152145
}
153146
helper.search();
@@ -162,7 +155,7 @@ const connectRangeSlider = rangeSliderRendering => ({
162155
rangeSliderRendering({
163156
collapsible,
164157
cssClasses,
165-
onChange: this._refine(stats),
158+
refine: this._refine(stats),
166159
pips,
167160
range: {min: Math.floor(stats.min), max: Math.ceil(stats.max)},
168161
shouldAutoHideContainer: autoHideContainer && stats.min === stats.max,
@@ -193,7 +186,7 @@ const connectRangeSlider = rangeSliderRendering => ({
193186
rangeSliderRendering({
194187
collapsible,
195188
cssClasses,
196-
onChange: this._refine(stats),
189+
refine: this._refine(stats),
197190
pips,
198191
range: {min: Math.floor(stats.min), max: Math.ceil(stats.max)},
199192
shouldAutoHideContainer: autoHideContainer && stats.min === stats.max,

src/widgets/range-slider/range-slider.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default connectRangeSlider(defaultRendering);
3636
function defaultRendering({
3737
collapsible,
3838
cssClasses,
39-
onChange,
39+
refine,
4040
pips,
4141
range,
4242
shouldAutoHideContainer,
@@ -52,7 +52,7 @@ function defaultRendering({
5252
<Slider
5353
collapsible={collapsible}
5454
cssClasses={cssClasses}
55-
onChange={onChange}
55+
onChange={refine}
5656
pips={pips}
5757
range={range}
5858
shouldAutoHideContainer={shouldAutoHideContainer}

0 commit comments

Comments
 (0)