Skip to content
This repository was archived by the owner on Dec 30, 2022. It is now read-only.

Commit 513017a

Browse files
author
Eunjae Lee
authored
feat(middlewares): add middlewares prop to ais-instant-search (#939)
* feat(middlewares): add middlewares prop to ais-instant-search * unsubscribe removed middlewares * update bundlesize * update instantsearch.js
1 parent 864e6c7 commit 513017a

File tree

5 files changed

+181
-7
lines changed

5 files changed

+181
-7
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
},
4747
"dependencies": {
4848
"algoliasearch-helper": "^3.1.0",
49-
"instantsearch.js": "^4.16.1"
49+
"instantsearch.js": "^4.20.0"
5050
},
5151
"peerDependencies": {
5252
"algoliasearch": ">= 3.32.0 < 5",
@@ -114,7 +114,7 @@
114114
"bundlesize": [
115115
{
116116
"path": "./dist/vue-instantsearch.js",
117-
"maxSize": "52.50 kB"
117+
"maxSize": "52.75 kB"
118118
},
119119
{
120120
"path": "./dist/vue-instantsearch.common.js",

src/components/InstantSearch.js

+4
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ export default createInstantSearchComponent({
6969
return false;
7070
},
7171
},
72+
middlewares: {
73+
type: Array,
74+
default: null,
75+
},
7276
},
7377
data() {
7478
return {

src/components/__tests__/InstantSearch-integration.js

+155-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import Vue from 'vue';
12
import { mount } from '@vue/test-utils';
23
import InstantSearch from '../InstantSearch';
34
import { createWidgetMixin } from '../../mixins/widget';
45
import { createFakeClient } from '../../util/testutils/client';
5-
6+
import SearchBox from '../SearchBox.vue';
67
jest.unmock('instantsearch.js/es');
78

9+
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
10+
811
it('child widgets get added to its parent instantsearch', () => {
912
const widgetInstance = {
1013
render() {},
@@ -32,3 +35,154 @@ it('child widgets get added to its parent instantsearch', () => {
3235
widgetInstance
3336
);
3437
});
38+
39+
describe('middlewares', () => {
40+
const createFakeMiddleware = () => {
41+
const middlewareSpy = {
42+
onStateChange: jest.fn(),
43+
subscribe: jest.fn(),
44+
unsubscribe: jest.fn(),
45+
};
46+
const middleware = jest.fn(() => middlewareSpy);
47+
48+
return [middleware, middlewareSpy];
49+
};
50+
51+
it('subscribes middlewares', async () => {
52+
const [middleware, middlewareSpy] = createFakeMiddleware();
53+
54+
mount(InstantSearch, {
55+
propsData: {
56+
searchClient: createFakeClient(),
57+
indexName: 'indexName',
58+
middlewares: [middleware],
59+
},
60+
});
61+
await Vue.nextTick();
62+
63+
expect(middlewareSpy.subscribe).toHaveBeenCalledTimes(1);
64+
});
65+
66+
it('subscribes newly added middleware', async () => {
67+
const [middleware1, middlewareSpy1] = createFakeMiddleware();
68+
69+
const wrapper = mount({
70+
components: {
71+
AisInstantSearch: InstantSearch,
72+
AisSearchBox: SearchBox,
73+
},
74+
template: `
75+
<ais-instant-search
76+
:search-client="searchClient"
77+
:index-name="indexName"
78+
:middlewares="middlewares"
79+
>
80+
<ais-search-box />
81+
</ais-instant-search>
82+
`,
83+
data() {
84+
return {
85+
searchClient: createFakeClient(),
86+
indexName: 'indexName',
87+
middlewares: [middleware1],
88+
};
89+
},
90+
});
91+
92+
await wait(20);
93+
expect(middlewareSpy1.subscribe).toHaveBeenCalledTimes(1);
94+
95+
await wrapper.find('input').setValue('a');
96+
await Vue.nextTick();
97+
98+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledTimes(1);
99+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledWith({
100+
uiState: { indexName: { query: 'a' } },
101+
});
102+
103+
const [middleware2, middlewareSpy2] = createFakeMiddleware();
104+
wrapper.setData({
105+
middlewares: [middleware1, middleware2],
106+
});
107+
await Vue.nextTick();
108+
109+
expect(middlewareSpy2.subscribe).toHaveBeenCalledTimes(1);
110+
expect(middlewareSpy2.onStateChange).toHaveBeenCalledTimes(0);
111+
112+
await wrapper.find('input').setValue('b');
113+
await Vue.nextTick();
114+
115+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledTimes(2);
116+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledWith({
117+
uiState: { indexName: { query: 'b' } },
118+
});
119+
expect(middlewareSpy2.onStateChange).toHaveBeenCalledTimes(1);
120+
expect(middlewareSpy2.onStateChange).toHaveBeenCalledWith({
121+
uiState: { indexName: { query: 'b' } },
122+
});
123+
124+
expect(middlewareSpy1.unsubscribe).toHaveBeenCalledTimes(0);
125+
expect(middlewareSpy2.unsubscribe).toHaveBeenCalledTimes(0);
126+
});
127+
128+
it('unsubscribes removed middleware', async () => {
129+
const [middleware1, middlewareSpy1] = createFakeMiddleware();
130+
const [middleware2, middlewareSpy2] = createFakeMiddleware();
131+
132+
const wrapper = mount({
133+
components: {
134+
AisInstantSearch: InstantSearch,
135+
AisSearchBox: SearchBox,
136+
},
137+
template: `
138+
<ais-instant-search
139+
:search-client="searchClient"
140+
:index-name="indexName"
141+
:middlewares="middlewares"
142+
>
143+
<ais-search-box />
144+
</ais-instant-search>
145+
`,
146+
data() {
147+
return {
148+
searchClient: createFakeClient(),
149+
indexName: 'indexName',
150+
middlewares: [middleware1, middleware2],
151+
};
152+
},
153+
});
154+
155+
await wait(20);
156+
expect(middlewareSpy1.subscribe).toHaveBeenCalledTimes(1);
157+
expect(middlewareSpy2.subscribe).toHaveBeenCalledTimes(1);
158+
159+
await wrapper.find('input').setValue('a');
160+
await Vue.nextTick();
161+
162+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledTimes(1);
163+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledWith({
164+
uiState: { indexName: { query: 'a' } },
165+
});
166+
expect(middlewareSpy2.onStateChange).toHaveBeenCalledTimes(1);
167+
expect(middlewareSpy2.onStateChange).toHaveBeenCalledWith({
168+
uiState: { indexName: { query: 'a' } },
169+
});
170+
171+
wrapper.setData({
172+
middlewares: [middleware1],
173+
});
174+
await Vue.nextTick();
175+
176+
expect(middlewareSpy1.unsubscribe).toHaveBeenCalledTimes(0);
177+
expect(middlewareSpy2.unsubscribe).toHaveBeenCalledTimes(1);
178+
179+
await wrapper.find('input').setValue('b');
180+
await Vue.nextTick();
181+
182+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledTimes(2);
183+
expect(middlewareSpy1.onStateChange).toHaveBeenCalledWith({
184+
uiState: { indexName: { query: 'b' } },
185+
});
186+
expect(middlewareSpy2.onStateChange).toHaveBeenCalledTimes(1);
187+
});
188+
});

src/util/createInstantSearchComponent.js

+16
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,22 @@ export const createInstantSearchComponent = component =>
3434
// private InstantSearch.js API:
3535
this.instantSearchInstance._searchFunction = searchFunction;
3636
},
37+
middlewares: {
38+
immediate: true,
39+
handler(next, prev) {
40+
(prev || [])
41+
.filter(middleware => (next || []).indexOf(middleware) === -1)
42+
.forEach(middlewareToRemove => {
43+
this.instantSearchInstance.unuse(middlewareToRemove);
44+
});
45+
46+
(next || [])
47+
.filter(middleware => (prev || []).indexOf(middleware) === -1)
48+
.forEach(middlewareToAdd => {
49+
this.instantSearchInstance.use(middlewareToAdd);
50+
});
51+
},
52+
},
3753
},
3854
created() {
3955
const searchClient = this.instantSearchInstance.client;

yarn.lock

+4-4
Original file line numberDiff line numberDiff line change
@@ -7892,10 +7892,10 @@ instantsearch.css@7.3.1:
78927892
resolved "https://registry.yarnpkg.com/instantsearch.css/-/instantsearch.css-7.3.1.tgz#7ab74a8f355091ae040947a9cf5438f379026622"
78937893
integrity sha512-/kaMDna5D+Q9mImNBHEhb9HgHATDOFKYii7N1Iwvrj+lmD9gBJLqVhUw67gftq2O0QI330pFza+CRscIwB1wQQ==
78947894

7895-
instantsearch.js@^4.16.1:
7896-
version "4.16.1"
7897-
resolved "https://registry.yarnpkg.com/instantsearch.js/-/instantsearch.js-4.16.1.tgz#78e00d2256c89693a94f58ebfc5f0864953b7ec8"
7898-
integrity sha512-NfwNOb+Ftj7Y+h6lW7iCd5SXWKIHQZ981ldSddEHbgTexbdJEyxgWhaF8c3HajCySp8wZPD2gj9KpNQy/BsUgQ==
7895+
instantsearch.js@^4.20.0:
7896+
version "4.20.0"
7897+
resolved "https://registry.yarnpkg.com/instantsearch.js/-/instantsearch.js-4.20.0.tgz#e7ed763a8380384ff59a88f3b56a01c5dedf0fca"
7898+
integrity sha512-fO3oqt/WEsUvdx8LB9Fm/MH9pLbl3gHV3ALnFOvbwdIpg+HRe5zZv3C/bE8E0SuTbZo2C6Fxg6rC0MEMTxNVGA==
78997899
dependencies:
79007900
"@types/googlemaps" "^3.39.6"
79017901
algoliasearch-helper "^3.4.4"

0 commit comments

Comments
 (0)