Skip to content

Commit 8e3c406

Browse files
author
Eunjae Lee
authoredApr 1, 2021
feat(middleware): add unuse method (#4708)
* feat(middleware): add unuse method * fix lint error * ad unuse to mocked instant search * update names * update test case for consistency
1 parent 97c5ce4 commit 8e3c406

File tree

3 files changed

+84
-11
lines changed

3 files changed

+84
-11
lines changed
 

‎src/lib/InstantSearch.ts

+29-11
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ class InstantSearch extends EventEmitter {
154154
public _createURL: CreateURL<UiState>;
155155
public _searchFunction?: InstantSearchOptions['searchFunction'];
156156
public _mainHelperSearch?: AlgoliaSearchHelper['search'];
157-
public middleware: MiddlewareDefinition[] = [];
157+
public middleware: Array<{
158+
creator: Middleware;
159+
instance: MiddlewareDefinition;
160+
}> = [];
158161
public sendEventToInsights: (event: InsightsEvent) => void;
159162

160163
public constructor(options: InstantSearchOptions) {
@@ -263,14 +266,14 @@ See ${createDocumentationLink({
263266

264267
/**
265268
* Hooks a middleware into the InstantSearch lifecycle.
266-
*
267-
* This method is considered as experimental and is subject to change in
268-
* minor versions.
269269
*/
270270
public use(...middleware: Middleware[]): this {
271271
const newMiddlewareList = middleware.map(fn => {
272272
const newMiddleware = fn({ instantSearchInstance: this });
273-
this.middleware.push(newMiddleware);
273+
this.middleware.push({
274+
creator: fn,
275+
instance: newMiddleware,
276+
});
274277
return newMiddleware;
275278
});
276279

@@ -285,6 +288,21 @@ See ${createDocumentationLink({
285288
return this;
286289
}
287290

291+
/**
292+
* Removes a middleware from the InstantSearch lifecycle.
293+
*/
294+
public unuse(...middlewareToUnuse: Middleware[]): this {
295+
this.middleware
296+
.filter(m => middlewareToUnuse.includes(m.creator))
297+
.forEach(m => m.instance.unsubscribe());
298+
299+
this.middleware = this.middleware.filter(
300+
m => !middlewareToUnuse.includes(m.creator)
301+
);
302+
303+
return this;
304+
}
305+
288306
// @major we shipped with EXPERIMENTAL_use, but have changed that to just `use` now
289307
public EXPERIMENTAL_use(...middleware: Middleware[]): this {
290308
warning(
@@ -456,8 +474,8 @@ See ${createDocumentationLink({
456474
uiState: this._initialUiState,
457475
});
458476

459-
this.middleware.forEach(m => {
460-
m.subscribe();
477+
this.middleware.forEach(({ instance }) => {
478+
instance.subscribe();
461479
});
462480

463481
mainHelper.search();
@@ -497,8 +515,8 @@ See ${createDocumentationLink({
497515
this.mainHelper = null;
498516
this.helper = null;
499517

500-
this.middleware.forEach(m => {
501-
m.unsubscribe();
518+
this.middleware.forEach(({ instance }) => {
519+
instance.unsubscribe();
502520
});
503521
}
504522

@@ -576,8 +594,8 @@ See ${createDocumentationLink({
576594
public onInternalStateChange = defer(() => {
577595
const nextUiState = this.mainIndex.getWidgetUiState({});
578596

579-
this.middleware.forEach(m => {
580-
m.onStateChange({
597+
this.middleware.forEach(({ instance }) => {
598+
instance.onStateChange({
581599
uiState: nextUiState,
582600
});
583601
});

‎src/lib/__tests__/InstantSearch-test.js

+54
Original file line numberDiff line numberDiff line change
@@ -1576,6 +1576,60 @@ describe('use', () => {
15761576
});
15771577
});
15781578

1579+
describe('unuse', () => {
1580+
it('unsubscribes middleware', async () => {
1581+
const indexName = 'indexName';
1582+
const searchClient = createSearchClient();
1583+
const search = new InstantSearch({
1584+
indexName,
1585+
searchClient,
1586+
});
1587+
const middlewareSpy1 = {
1588+
onStateChange: jest.fn(),
1589+
subscribe: jest.fn(),
1590+
unsubscribe: jest.fn(),
1591+
};
1592+
const middleware1 = jest.fn(() => middlewareSpy1);
1593+
const middlewareSpy2 = {
1594+
onStateChange: jest.fn(),
1595+
subscribe: jest.fn(),
1596+
unsubscribe: jest.fn(),
1597+
};
1598+
const middleware2 = jest.fn(() => middlewareSpy2);
1599+
1600+
search.addWidgets([connectSearchBox(noop)({})]);
1601+
search.use(middleware1, middleware2);
1602+
search.start();
1603+
1604+
await runAllMicroTasks();
1605+
1606+
expect(middlewareSpy1.subscribe).toHaveBeenCalledTimes(1);
1607+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledTimes(0);
1608+
expect(middlewareSpy2.subscribe).toHaveBeenCalledTimes(1);
1609+
expect(middlewareSpy2.onStateChange).toHaveBeenCalledTimes(0);
1610+
1611+
search.renderState[indexName].searchBox.refine('cat');
1612+
await runAllMicroTasks();
1613+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledTimes(1);
1614+
expect(middlewareSpy2.onStateChange).toHaveBeenCalledTimes(1);
1615+
1616+
search.renderState[indexName].searchBox.refine('is');
1617+
await runAllMicroTasks();
1618+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledTimes(2);
1619+
expect(middlewareSpy2.onStateChange).toHaveBeenCalledTimes(2);
1620+
1621+
search.unuse(middleware1);
1622+
1623+
expect(middlewareSpy1.unsubscribe).toHaveBeenCalledTimes(1);
1624+
expect(middlewareSpy2.unsubscribe).toHaveBeenCalledTimes(0);
1625+
1626+
search.renderState[indexName].searchBox.refine('good');
1627+
await runAllMicroTasks();
1628+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledTimes(2);
1629+
expect(middlewareSpy2.onStateChange).toHaveBeenCalledTimes(3);
1630+
});
1631+
});
1632+
15791633
describe('setUiState', () => {
15801634
beforeEach(() => {
15811635
warning.cache = {};

‎test/mock/createInstantSearch.ts

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const createInstantSearch = (
5151
removeWidgets: jest.fn(),
5252
use: jest.fn(),
5353
EXPERIMENTAL_use: jest.fn(),
54+
unuse: jest.fn(),
5455
// methods from EventEmitter
5556
addListener: jest.fn(),
5657
removeListener: jest.fn(),

0 commit comments

Comments
 (0)
Please sign in to comment.