Skip to content

Commit 3234b12

Browse files
Maxime Jantonbobylito
authored andcommitted
fix(InstantSearch.dispose): dont call getConfiguration of URLSync widget (#2604)
1 parent fff6322 commit 3234b12

File tree

2 files changed

+48
-12
lines changed

2 files changed

+48
-12
lines changed

src/lib/InstantSearch.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,11 @@ Usage: instantsearch({
181181
// re-compute remaining widgets to the state
182182
// in a case two widgets were using the same configuration but we removed one
183183
if (nextState) {
184-
this.searchParameters = this.widgets.reduce(enhanceConfiguration({}), {
185-
...nextState,
186-
});
184+
// We dont want to re-add URlSync `getConfiguration` widget
185+
// it can throw errors since it may re-add SearchParameters about something unmounted
186+
this.searchParameters = this.widgets
187+
.filter(w => w.constructor.name !== 'URLSync')
188+
.reduce(enhanceConfiguration({}), { ...nextState });
187189

188190
this.helper.setState(this.searchParameters);
189191
}
@@ -272,11 +274,7 @@ Usage: instantsearch({
272274
* @return {undefined} This method does not return anything
273275
*/
274276
dispose() {
275-
this.removeWidgets(
276-
this.widgets
277-
.slice()
278-
.sort(widget => (widget.constructor.name === 'URLSync' ? -1 : 1))
279-
);
277+
this.removeWidgets(this.widgets);
280278
}
281279

282280
createURL(params) {

src/lib/__tests__/InstantSearch-test.js

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -369,12 +369,12 @@ describe('InstantSearch lifecycle', () => {
369369
facets: ['categories'],
370370
maxValuesPerFacet: 10,
371371
},
372-
dispose = sinon.spy()
372+
dispose = jest.fn()
373373
) {
374374
const widget = {
375-
getConfiguration: sinon.stub().returns(widgetGetConfiguration),
376-
init: sinon.spy(),
377-
render: sinon.spy(),
375+
getConfiguration: jest.fn(() => widgetGetConfiguration),
376+
init: jest.fn(),
377+
render: jest.fn(),
378378
dispose,
379379
};
380380

@@ -526,6 +526,44 @@ describe('InstantSearch lifecycle', () => {
526526
expect(search.searchParameters.numericRefinements).toEqual({});
527527
expect(search.searchParameters.disjunctiveFacets).toEqual([]);
528528
});
529+
530+
it('should unmount a widget without calling URLSync wiget getConfiguration', () => {
531+
// fake url-sync widget
532+
const spy = jest.fn();
533+
534+
class URLSync {
535+
constructor() {
536+
this.getConfiguration = spy;
537+
this.init = jest.fn();
538+
this.render = jest.fn();
539+
this.dispose = jest.fn();
540+
}
541+
}
542+
543+
const urlSyncWidget = new URLSync();
544+
expect(urlSyncWidget.constructor.name).toEqual('URLSync');
545+
546+
search.addWidget(urlSyncWidget);
547+
548+
// add fake widget to dispose
549+
// that returns a `nextState` while dispose
550+
const widget1 = registerWidget(
551+
undefined,
552+
jest.fn(({ state: nextState }) => nextState)
553+
);
554+
555+
const widget2 = registerWidget();
556+
search.start();
557+
558+
// remove widget1
559+
search.removeWidget(widget1);
560+
561+
// it should have been called only once after start();
562+
expect(spy).toHaveBeenCalledTimes(1);
563+
564+
// but widget2 getConfiguration() should have been called twice
565+
expect(widget2.getConfiguration).toHaveBeenCalledTimes(2);
566+
});
529567
});
530568

531569
describe('When adding widgets after start', () => {

0 commit comments

Comments
 (0)