vue-instantsearch 3.6.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/dist/vue-instantsearch.common.js +1 -1
- package/dist/vue-instantsearch.common.js.map +1 -1
- package/dist/vue-instantsearch.js +1 -1
- package/dist/vue-instantsearch.js.map +1 -1
- package/es/package.json.js +1 -1
- package/es/src/components/Breadcrumb.vue.js +1 -1
- package/es/src/components/Breadcrumb.vue.js.map +1 -1
- package/es/src/components/ClearRefinements.vue.js +1 -1
- package/es/src/components/ClearRefinements.vue.js.map +1 -1
- package/es/src/components/CurrentRefinements.vue.js +1 -1
- package/es/src/components/CurrentRefinements.vue.js.map +1 -1
- package/es/src/components/DynamicWidgets.js +2 -0
- package/es/src/components/DynamicWidgets.js.map +1 -0
- package/es/src/components/HierarchicalMenu.vue.js +1 -1
- package/es/src/components/HierarchicalMenu.vue.js.map +1 -1
- package/es/src/components/Highlighter.vue.js.map +1 -1
- package/es/src/components/Hits.vue.js +1 -1
- package/es/src/components/Hits.vue.js.map +1 -1
- package/es/src/components/HitsPerPage.vue.js +1 -1
- package/es/src/components/HitsPerPage.vue.js.map +1 -1
- package/es/src/components/InfiniteHits.vue.js +1 -1
- package/es/src/components/InfiniteHits.vue.js.map +1 -1
- package/es/src/components/InstantSearch.js +1 -1
- package/es/src/components/InstantSearch.js.map +1 -1
- package/es/src/components/Menu.vue.js +1 -1
- package/es/src/components/Menu.vue.js.map +1 -1
- package/es/src/components/MenuSelect.vue.js +1 -1
- package/es/src/components/MenuSelect.vue.js.map +1 -1
- package/es/src/components/NumericMenu.vue.js +1 -1
- package/es/src/components/NumericMenu.vue.js.map +1 -1
- package/es/src/components/Pagination.vue.js +1 -1
- package/es/src/components/Pagination.vue.js.map +1 -1
- package/es/src/components/QueryRuleContext.js +1 -1
- package/es/src/components/QueryRuleContext.js.map +1 -1
- package/es/src/components/QueryRuleCustomData.vue.js +1 -1
- package/es/src/components/QueryRuleCustomData.vue.js.map +1 -1
- package/es/src/components/RangeInput.vue.js +1 -1
- package/es/src/components/RangeInput.vue.js.map +1 -1
- package/es/src/components/RatingMenu.vue.js +1 -1
- package/es/src/components/RatingMenu.vue.js.map +1 -1
- package/es/src/components/RefinementList.vue.js +1 -1
- package/es/src/components/RefinementList.vue.js.map +1 -1
- package/es/src/components/SortBy.vue.js +1 -1
- package/es/src/components/SortBy.vue.js.map +1 -1
- package/es/src/components/ToggleRefinement.vue.js +1 -1
- package/es/src/components/ToggleRefinement.vue.js.map +1 -1
- package/es/src/instantsearch.js +1 -1
- package/es/src/mixins/widget.js +1 -1
- package/es/src/mixins/widget.js.map +1 -1
- package/es/src/util/createInstantSearchComponent.js +1 -1
- package/es/src/util/createInstantSearchComponent.js.map +1 -1
- package/es/src/util/createServerRootMixin.js +1 -1
- package/es/src/util/createServerRootMixin.js.map +1 -1
- package/es/src/widgets.js +1 -1
- package/package.json +5 -5
- package/src/__tests__/index.js +2 -0
- package/src/components/Breadcrumb.vue +3 -5
- package/src/components/ClearRefinements.vue +3 -7
- package/src/components/CurrentRefinements.vue +3 -7
- package/src/components/DynamicWidgets.js +87 -0
- package/src/components/HierarchicalMenu.vue +8 -11
- package/src/components/Highlighter.vue +16 -4
- package/src/components/Hits.vue +2 -3
- package/src/components/HitsPerPage.vue +1 -4
- package/src/components/InfiniteHits.vue +2 -3
- package/src/components/InstantSearch.js +11 -7
- package/src/components/Menu.vue +5 -8
- package/src/components/MenuSelect.vue +2 -3
- package/src/components/NumericMenu.vue +2 -3
- package/src/components/Pagination.vue +1 -1
- package/src/components/QueryRuleContext.js +1 -1
- package/src/components/QueryRuleCustomData.vue +1 -1
- package/src/components/RangeInput.vue +3 -0
- package/src/components/RatingMenu.vue +2 -1
- package/src/components/RefinementList.vue +8 -7
- package/src/components/SortBy.vue +1 -3
- package/src/components/ToggleRefinement.vue +1 -2
- package/src/components/__tests__/DynamicWidgets.js +419 -0
- package/src/components/__tests__/HierarchicalMenu.js +23 -0
- package/src/components/__tests__/Hits.js +22 -1
- package/src/components/__tests__/InfiniteHits.js +21 -0
- package/src/components/__tests__/InstantSearch-integration.js +155 -1
- package/src/components/__tests__/Menu.js +22 -0
- package/src/components/__tests__/MenuSelect.js +22 -0
- package/src/components/__tests__/NumericMenu.js +22 -0
- package/src/components/__tests__/RangeInput.js +22 -0
- package/src/components/__tests__/RatingMenu.js +23 -0
- package/src/components/__tests__/RefinementList.js +22 -0
- package/src/components/__tests__/ToggleRefinement.js +22 -0
- package/src/mixins/widget.js +1 -1
- package/src/util/__tests__/createServerRootMixin.test.js +229 -83
- package/src/util/createInstantSearchComponent.js +16 -0
- package/src/util/createServerRootMixin.js +40 -104
- package/src/util/testutils/helper.js +2 -2
- package/src/widgets.js +1 -0
|
@@ -224,6 +224,28 @@ it('calls the Panel mixin with `canRefine`', () => {
|
|
|
224
224
|
expect(wrapper.vm.mapStateToCanRefine({})).toBe(false);
|
|
225
225
|
});
|
|
226
226
|
|
|
227
|
+
it('exposes send-event method for insights middleware', () => {
|
|
228
|
+
const sendEvent = jest.fn();
|
|
229
|
+
__setState({
|
|
230
|
+
...defaultState,
|
|
231
|
+
sendEvent,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const wrapper = mount(MenuSelect, {
|
|
235
|
+
propsData: defaultProps,
|
|
236
|
+
scopedSlots: {
|
|
237
|
+
default: `
|
|
238
|
+
<div slot-scope="{ sendEvent }">
|
|
239
|
+
<button @click="sendEvent()">Send Event</button>
|
|
240
|
+
</div>
|
|
241
|
+
`,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
wrapper.find('button').trigger('click');
|
|
246
|
+
expect(sendEvent).toHaveBeenCalledTimes(1);
|
|
247
|
+
});
|
|
248
|
+
|
|
227
249
|
describe('custom item slot', () => {
|
|
228
250
|
// can not be <template>
|
|
229
251
|
// https://github.com/vuejs/vue-test-utils/pull/507
|
|
@@ -210,6 +210,28 @@ it('calls the Panel mixin with `hasNoResults`', () => {
|
|
|
210
210
|
expect(wrapper.vm.mapStateToCanRefine({})).toBe(false);
|
|
211
211
|
});
|
|
212
212
|
|
|
213
|
+
it('exposes send-event method for insights middleware', () => {
|
|
214
|
+
const sendEvent = jest.fn();
|
|
215
|
+
__setState({
|
|
216
|
+
...defaultState,
|
|
217
|
+
sendEvent,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const wrapper = mount(NumericMenu, {
|
|
221
|
+
propsData: defaultProps,
|
|
222
|
+
scopedSlots: {
|
|
223
|
+
default: `
|
|
224
|
+
<div slot-scope="{ sendEvent }">
|
|
225
|
+
<button @click="sendEvent()">Send Event</button>
|
|
226
|
+
</div>
|
|
227
|
+
`,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
wrapper.find('button').trigger('click');
|
|
232
|
+
expect(sendEvent).toHaveBeenCalledTimes(1);
|
|
233
|
+
});
|
|
234
|
+
|
|
213
235
|
describe('custom default render', () => {
|
|
214
236
|
const defaultScopedSlot = `
|
|
215
237
|
<ul
|
|
@@ -281,6 +281,28 @@ it('calls the Panel mixin with `range`', () => {
|
|
|
281
281
|
expect(wrapper.vm.mapStateToCanRefine({})).toBe(false);
|
|
282
282
|
});
|
|
283
283
|
|
|
284
|
+
it('exposes send-event method for insights middleware', () => {
|
|
285
|
+
const sendEvent = jest.fn();
|
|
286
|
+
__setState({
|
|
287
|
+
...defaultState,
|
|
288
|
+
sendEvent,
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
const wrapper = mount(RangeInput, {
|
|
292
|
+
propsData: defaultProps,
|
|
293
|
+
scopedSlots: {
|
|
294
|
+
default: `
|
|
295
|
+
<div slot-scope="{ sendEvent }">
|
|
296
|
+
<button @click="sendEvent()">Send Event</button>
|
|
297
|
+
</div>
|
|
298
|
+
`,
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
wrapper.find('button').trigger('click');
|
|
303
|
+
expect(sendEvent).toHaveBeenCalledTimes(1);
|
|
304
|
+
});
|
|
305
|
+
|
|
284
306
|
describe('refinement', () => {
|
|
285
307
|
it('uses the value of the inputs when the form is submited', () => {
|
|
286
308
|
const refine = jest.fn();
|
|
@@ -148,3 +148,26 @@ it('calls the Panel mixin with `hasNoResults`', () => {
|
|
|
148
148
|
|
|
149
149
|
expect(wrapper.vm.mapStateToCanRefine({})).toBe(false);
|
|
150
150
|
});
|
|
151
|
+
|
|
152
|
+
it('exposes send-event method for insights middleware', () => {
|
|
153
|
+
const sendEvent = jest.fn();
|
|
154
|
+
__setState({
|
|
155
|
+
createURL: () => '#',
|
|
156
|
+
items: [],
|
|
157
|
+
sendEvent,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const wrapper = mount(RatingMenu, {
|
|
161
|
+
propsData: defaultProps,
|
|
162
|
+
scopedSlots: {
|
|
163
|
+
default: `
|
|
164
|
+
<div slot-scope="{ sendEvent }">
|
|
165
|
+
<button @click="sendEvent()">Send Event</button>
|
|
166
|
+
</div>
|
|
167
|
+
`,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
wrapper.find('button').trigger('click');
|
|
172
|
+
expect(sendEvent).toHaveBeenCalledTimes(1);
|
|
173
|
+
});
|
|
@@ -188,3 +188,25 @@ it('calls the Panel mixin with `canRefine`', () => {
|
|
|
188
188
|
|
|
189
189
|
expect(wrapper.vm.mapStateToCanRefine({})).toBe(false);
|
|
190
190
|
});
|
|
191
|
+
|
|
192
|
+
it('exposes send-event method for insights middleware', () => {
|
|
193
|
+
const sendEvent = jest.fn();
|
|
194
|
+
__setState({
|
|
195
|
+
...defaultState,
|
|
196
|
+
sendEvent,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const wrapper = mount(RefinementList, {
|
|
200
|
+
propsData: { attribute: 'something' },
|
|
201
|
+
scopedSlots: {
|
|
202
|
+
default: `
|
|
203
|
+
<div slot-scope="{ sendEvent }">
|
|
204
|
+
<button @click="sendEvent()">Send Event</button>
|
|
205
|
+
</div>
|
|
206
|
+
`,
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
wrapper.find('button').trigger('click');
|
|
211
|
+
expect(sendEvent).toHaveBeenCalledTimes(1);
|
|
212
|
+
});
|
|
@@ -195,6 +195,28 @@ it('calls the Panel mixin with `value.count`', () => {
|
|
|
195
195
|
expect(wrapper.vm.mapStateToCanRefine({})).toBe(false);
|
|
196
196
|
});
|
|
197
197
|
|
|
198
|
+
it('exposes send-event method for insights middleware', () => {
|
|
199
|
+
const sendEvent = jest.fn();
|
|
200
|
+
__setState({
|
|
201
|
+
...defaultState,
|
|
202
|
+
sendEvent,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const wrapper = mount(Toggle, {
|
|
206
|
+
propsData: defaultProps,
|
|
207
|
+
scopedSlots: {
|
|
208
|
+
default: `
|
|
209
|
+
<div slot-scope="{ sendEvent }">
|
|
210
|
+
<button @click="sendEvent()">Send Event</button>
|
|
211
|
+
</div>
|
|
212
|
+
`,
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
wrapper.find('button').trigger('click');
|
|
217
|
+
expect(sendEvent).toHaveBeenCalledTimes(1);
|
|
218
|
+
});
|
|
219
|
+
|
|
198
220
|
describe('custom default render', () => {
|
|
199
221
|
const defaultScopedSlot = `
|
|
200
222
|
<a
|
package/src/mixins/widget.js
CHANGED
|
@@ -30,7 +30,7 @@ export const createWidgetMixin = ({ connector } = {}) => ({
|
|
|
30
30
|
this.getParentIndex().addWidgets([this.widget]);
|
|
31
31
|
|
|
32
32
|
if (
|
|
33
|
-
this.instantSearchInstance.
|
|
33
|
+
this.instantSearchInstance._initialResults &&
|
|
34
34
|
!this.instantSearchInstance.started
|
|
35
35
|
) {
|
|
36
36
|
if (typeof this.instantSearchInstance.__forceRender !== 'function') {
|
|
@@ -10,11 +10,7 @@ import SearchBox from '../../components/SearchBox.vue';
|
|
|
10
10
|
import { createWidgetMixin } from '../../mixins/widget';
|
|
11
11
|
import { createFakeClient } from '../testutils/client';
|
|
12
12
|
import { createSerializedState } from '../testutils/helper';
|
|
13
|
-
import {
|
|
14
|
-
SearchResults,
|
|
15
|
-
SearchParameters,
|
|
16
|
-
AlgoliaSearchHelper,
|
|
17
|
-
} from 'algoliasearch-helper';
|
|
13
|
+
import { SearchParameters, SearchResults } from 'algoliasearch-helper';
|
|
18
14
|
|
|
19
15
|
jest.unmock('instantsearch.js/es');
|
|
20
16
|
|
|
@@ -54,9 +50,11 @@ describe('createServerRootMixin', () => {
|
|
|
54
50
|
}),
|
|
55
51
|
],
|
|
56
52
|
})
|
|
57
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
).toThrowErrorMatchingInlineSnapshot(`
|
|
54
|
+
"The \`searchClient\` option is required.
|
|
55
|
+
|
|
56
|
+
See documentation: https://www.algolia.com/doc/api-reference/widgets/instantsearch/js/"
|
|
57
|
+
`);
|
|
60
58
|
});
|
|
61
59
|
|
|
62
60
|
it('requires indexName', () => {
|
|
@@ -70,9 +68,11 @@ describe('createServerRootMixin', () => {
|
|
|
70
68
|
}),
|
|
71
69
|
],
|
|
72
70
|
})
|
|
73
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
).toThrowErrorMatchingInlineSnapshot(`
|
|
72
|
+
"The \`indexName\` option is required.
|
|
73
|
+
|
|
74
|
+
See documentation: https://www.algolia.com/doc/api-reference/widgets/instantsearch/js/"
|
|
75
|
+
`);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
it('creates an instantsearch instance on "data"', () => {
|
|
@@ -246,6 +246,7 @@ Array [
|
|
|
246
246
|
h(SearchBox),
|
|
247
247
|
]);
|
|
248
248
|
},
|
|
249
|
+
|
|
249
250
|
serverPrefetch() {
|
|
250
251
|
return this.instantsearch.findResultsState(this);
|
|
251
252
|
},
|
|
@@ -388,7 +389,7 @@ Array [
|
|
|
388
389
|
this.instantsearch.mainIndex.getWidgets().map(w => w.$$type)
|
|
389
390
|
).toEqual(['ais.configure']);
|
|
390
391
|
|
|
391
|
-
expect(res.hello.
|
|
392
|
+
expect(res.hello.state.hitsPerPage).toBe(100);
|
|
392
393
|
})
|
|
393
394
|
// jest throws an error we need to catch, since stuck in the flow
|
|
394
395
|
.catch(e => {
|
|
@@ -423,7 +424,7 @@ Array [
|
|
|
423
424
|
|
|
424
425
|
expect.assertions(2);
|
|
425
426
|
|
|
426
|
-
const App =
|
|
427
|
+
const App = {
|
|
427
428
|
mixins: [
|
|
428
429
|
forceIsServerMixin,
|
|
429
430
|
createServerRootMixin({
|
|
@@ -431,11 +432,8 @@ Array [
|
|
|
431
432
|
indexName: 'hello',
|
|
432
433
|
}),
|
|
433
434
|
],
|
|
434
|
-
render
|
|
435
|
-
|
|
436
|
-
this.$scopedSlots.default({ test: true }),
|
|
437
|
-
]);
|
|
438
|
-
},
|
|
435
|
+
render: h =>
|
|
436
|
+
h(InstantSearchSsr, {}, [this.$scopedSlots.default({ test: true })]),
|
|
439
437
|
serverPrefetch() {
|
|
440
438
|
return (
|
|
441
439
|
this.instantsearch
|
|
@@ -453,26 +451,23 @@ Array [
|
|
|
453
451
|
})
|
|
454
452
|
);
|
|
455
453
|
},
|
|
456
|
-
}
|
|
454
|
+
};
|
|
457
455
|
|
|
458
456
|
const wrapper = new Vue({
|
|
459
457
|
mixins: [forceIsServerMixin],
|
|
460
|
-
render
|
|
461
|
-
|
|
458
|
+
render: h =>
|
|
459
|
+
h(App, {
|
|
462
460
|
scopedSlots: {
|
|
463
461
|
default({ test }) {
|
|
464
462
|
if (test) {
|
|
465
463
|
return h(Configure, {
|
|
466
|
-
|
|
467
|
-
hitsPerPage: 100,
|
|
468
|
-
},
|
|
464
|
+
hitsPerPage: 100,
|
|
469
465
|
});
|
|
470
466
|
}
|
|
471
467
|
return null;
|
|
472
468
|
},
|
|
473
469
|
},
|
|
474
|
-
})
|
|
475
|
-
},
|
|
470
|
+
}),
|
|
476
471
|
});
|
|
477
472
|
|
|
478
473
|
await renderToString(wrapper);
|
|
@@ -519,63 +514,76 @@ Array [
|
|
|
519
514
|
|
|
520
515
|
await renderToString(wrapper);
|
|
521
516
|
});
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
describe('hydrate', () => {
|
|
525
|
-
it('sets __initialSearchResults', () => {
|
|
526
|
-
const serialized = createSerializedState();
|
|
527
517
|
|
|
518
|
+
it('searches only once', async () => {
|
|
519
|
+
const searchClient = createFakeClient();
|
|
528
520
|
const app = {
|
|
529
521
|
mixins: [
|
|
522
|
+
forceIsServerMixin,
|
|
530
523
|
createServerRootMixin({
|
|
531
|
-
searchClient
|
|
524
|
+
searchClient,
|
|
532
525
|
indexName: 'hello',
|
|
533
526
|
}),
|
|
534
527
|
],
|
|
535
|
-
render
|
|
536
|
-
|
|
528
|
+
render: h =>
|
|
529
|
+
/**
|
|
530
|
+
* This code triggers this warning in Vue 3:
|
|
531
|
+
* > Non-function value encountered for default slot. Prefer function slots for better performance.
|
|
532
|
+
*
|
|
533
|
+
* To fix it, replace the third argument
|
|
534
|
+
* > [h(...), h(...)]
|
|
535
|
+
* with
|
|
536
|
+
* > { default: () => [h(...), h(...)] }
|
|
537
|
+
*
|
|
538
|
+
* but it's not important (and not compatible in vue2), we're leaving it as-is.
|
|
539
|
+
*/
|
|
540
|
+
h(InstantSearchSsr, {}, [
|
|
537
541
|
h(Configure, {
|
|
538
542
|
attrs: {
|
|
539
543
|
hitsPerPage: 100,
|
|
540
544
|
},
|
|
541
545
|
}),
|
|
542
546
|
h(SearchBox),
|
|
543
|
-
])
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
created() {
|
|
547
|
-
this.instantsearch.hydrate({
|
|
548
|
-
__identifier: 'stringified',
|
|
549
|
-
hello: serialized,
|
|
550
|
-
});
|
|
547
|
+
]),
|
|
548
|
+
serverPrefetch() {
|
|
549
|
+
return this.instantsearch.findResultsState(this);
|
|
551
550
|
},
|
|
552
551
|
};
|
|
553
552
|
|
|
554
|
-
const {
|
|
555
|
-
|
|
556
|
-
|
|
553
|
+
const wrapper = new Vue({
|
|
554
|
+
mixins: [forceIsServerMixin],
|
|
555
|
+
render: h => h(app),
|
|
556
|
+
});
|
|
557
557
|
|
|
558
|
-
|
|
559
|
-
expect.objectContaining({ hello: expect.any(SearchResults) })
|
|
560
|
-
);
|
|
558
|
+
await renderToString(wrapper);
|
|
561
559
|
|
|
562
|
-
expect(
|
|
563
|
-
|
|
564
|
-
|
|
560
|
+
expect(searchClient.search).toHaveBeenCalledTimes(1);
|
|
561
|
+
expect(searchClient.search.mock.calls[0][0]).toMatchInlineSnapshot(`
|
|
562
|
+
Array [
|
|
563
|
+
Object {
|
|
564
|
+
"indexName": "hello",
|
|
565
|
+
"params": Object {
|
|
566
|
+
"facets": Array [],
|
|
567
|
+
"hitsPerPage": 100,
|
|
568
|
+
"query": "",
|
|
569
|
+
"tagFilters": "",
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
]
|
|
573
|
+
`);
|
|
565
574
|
});
|
|
575
|
+
});
|
|
566
576
|
|
|
567
|
-
|
|
577
|
+
describe('hydrate', () => {
|
|
578
|
+
it('sets _initialResults', () => {
|
|
568
579
|
const serialized = createSerializedState();
|
|
569
|
-
const nonSerialized = new SearchResults(
|
|
570
|
-
new SearchParameters(serialized._state),
|
|
571
|
-
serialized._rawResults
|
|
572
|
-
);
|
|
573
580
|
|
|
574
|
-
|
|
581
|
+
let instantsearch;
|
|
582
|
+
const app = new Vue({
|
|
575
583
|
mixins: [
|
|
576
584
|
createServerRootMixin({
|
|
577
585
|
searchClient: createFakeClient(),
|
|
578
|
-
indexName: '
|
|
586
|
+
indexName: 'hello',
|
|
579
587
|
}),
|
|
580
588
|
],
|
|
581
589
|
render(h) {
|
|
@@ -590,27 +598,35 @@ Array [
|
|
|
590
598
|
},
|
|
591
599
|
// in test, beforeCreated doesn't have $data yet, but IRL it does
|
|
592
600
|
created() {
|
|
601
|
+
instantsearch = this.instantsearch;
|
|
593
602
|
this.instantsearch.hydrate({
|
|
594
|
-
|
|
603
|
+
hello: serialized,
|
|
595
604
|
});
|
|
596
605
|
},
|
|
597
|
-
};
|
|
606
|
+
});
|
|
598
607
|
|
|
599
|
-
|
|
600
|
-
vm: { instantsearch },
|
|
601
|
-
} = mount(app);
|
|
608
|
+
mount(app);
|
|
602
609
|
|
|
603
|
-
expect(instantsearch.
|
|
604
|
-
expect.objectContaining({
|
|
610
|
+
expect(instantsearch._initialResults).toEqual(
|
|
611
|
+
expect.objectContaining({
|
|
612
|
+
hello: {
|
|
613
|
+
state: expect.any(Object),
|
|
614
|
+
results: expect.any(Object),
|
|
615
|
+
},
|
|
616
|
+
})
|
|
605
617
|
);
|
|
606
618
|
|
|
607
|
-
expect(instantsearch.
|
|
619
|
+
expect(instantsearch._initialResults.hello).toEqual(
|
|
620
|
+
expect.objectContaining(serialized)
|
|
621
|
+
);
|
|
608
622
|
});
|
|
609
623
|
|
|
610
624
|
it('inits the main index', () => {
|
|
611
625
|
const serialized = createSerializedState();
|
|
612
626
|
|
|
613
|
-
|
|
627
|
+
let instantsearch;
|
|
628
|
+
|
|
629
|
+
const app = new Vue({
|
|
614
630
|
mixins: [
|
|
615
631
|
createServerRootMixin({
|
|
616
632
|
searchClient: createFakeClient(),
|
|
@@ -627,28 +643,30 @@ Array [
|
|
|
627
643
|
h(SearchBox),
|
|
628
644
|
]);
|
|
629
645
|
},
|
|
630
|
-
|
|
646
|
+
created() {
|
|
647
|
+
instantsearch = this.instantsearch;
|
|
648
|
+
},
|
|
649
|
+
});
|
|
631
650
|
|
|
632
|
-
|
|
633
|
-
vm: { instantsearch },
|
|
634
|
-
} = mount(app);
|
|
651
|
+
mount(app);
|
|
635
652
|
|
|
636
653
|
expect(instantsearch.mainIndex.getHelper()).toBe(null);
|
|
637
654
|
|
|
638
655
|
instantsearch.hydrate({
|
|
639
|
-
__identifier: 'stringified',
|
|
640
656
|
hello: serialized,
|
|
641
657
|
});
|
|
642
658
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
659
|
+
expect(instantsearch.mainIndex.getHelper().constructor.name).toBe(
|
|
660
|
+
'AlgoliaSearchHelper'
|
|
661
|
+
);
|
|
646
662
|
});
|
|
647
663
|
|
|
648
664
|
it('sets helper & mainHelper', () => {
|
|
649
665
|
const serialized = createSerializedState();
|
|
650
666
|
|
|
651
|
-
|
|
667
|
+
let instantsearch;
|
|
668
|
+
|
|
669
|
+
const app = new Vue({
|
|
652
670
|
mixins: [
|
|
653
671
|
createServerRootMixin({
|
|
654
672
|
searchClient: createFakeClient(),
|
|
@@ -665,22 +683,96 @@ Array [
|
|
|
665
683
|
h(SearchBox),
|
|
666
684
|
]);
|
|
667
685
|
},
|
|
668
|
-
|
|
686
|
+
created() {
|
|
687
|
+
instantsearch = this.instantsearch;
|
|
688
|
+
},
|
|
689
|
+
});
|
|
669
690
|
|
|
670
|
-
|
|
671
|
-
vm: { instantsearch },
|
|
672
|
-
} = mount(app);
|
|
691
|
+
mount(app);
|
|
673
692
|
|
|
674
693
|
expect(instantsearch.helper).toBe(null);
|
|
675
694
|
expect(instantsearch.mainHelper).toBe(null);
|
|
676
695
|
|
|
677
696
|
instantsearch.hydrate({
|
|
678
|
-
__identifier: 'stringified',
|
|
679
697
|
hello: serialized,
|
|
680
698
|
});
|
|
681
699
|
|
|
682
|
-
expect(instantsearch.helper).
|
|
683
|
-
expect(instantsearch.mainHelper).
|
|
700
|
+
expect(instantsearch.helper.constructor.name).toBe('AlgoliaSearchHelper');
|
|
701
|
+
expect(instantsearch.mainHelper.constructor.name).toBe(
|
|
702
|
+
'AlgoliaSearchHelper'
|
|
703
|
+
);
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
it('works when component is at root (and therefore has no $vnode)', async () => {
|
|
707
|
+
const searchClient = createFakeClient();
|
|
708
|
+
let mainIndex;
|
|
709
|
+
|
|
710
|
+
const app = {
|
|
711
|
+
render: h =>
|
|
712
|
+
/**
|
|
713
|
+
* This code triggers this warning in Vue 3:
|
|
714
|
+
* > Non-function value encountered for default slot. Prefer function slots for better performance.
|
|
715
|
+
*
|
|
716
|
+
* To fix it, replace the third argument
|
|
717
|
+
* > [h(...), h(...)]
|
|
718
|
+
* with
|
|
719
|
+
* > { default: () => [h(...), h(...)] }
|
|
720
|
+
*
|
|
721
|
+
* but it's not important (and not compatible in vue2), we're leaving it as-is.
|
|
722
|
+
*/
|
|
723
|
+
h(InstantSearchSsr, {}, [
|
|
724
|
+
h(Configure, {
|
|
725
|
+
attrs: {
|
|
726
|
+
hitsPerPage: 100,
|
|
727
|
+
},
|
|
728
|
+
}),
|
|
729
|
+
h(SearchBox),
|
|
730
|
+
]),
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
const wrapper = new Vue({
|
|
734
|
+
mixins: [
|
|
735
|
+
forceIsServerMixin,
|
|
736
|
+
createServerRootMixin({
|
|
737
|
+
searchClient,
|
|
738
|
+
indexName: 'hello',
|
|
739
|
+
}),
|
|
740
|
+
],
|
|
741
|
+
serverPrefetch() {
|
|
742
|
+
return this.instantsearch.findResultsState(this);
|
|
743
|
+
},
|
|
744
|
+
created() {
|
|
745
|
+
mainIndex = this.instantsearch.mainIndex;
|
|
746
|
+
},
|
|
747
|
+
render: h => h(app),
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
await renderToString(wrapper);
|
|
751
|
+
|
|
752
|
+
expect(mainIndex.getWidgetState()).toMatchInlineSnapshot(`
|
|
753
|
+
Object {
|
|
754
|
+
"hello": Object {
|
|
755
|
+
"configure": Object {
|
|
756
|
+
"hitsPerPage": 100,
|
|
757
|
+
},
|
|
758
|
+
},
|
|
759
|
+
}
|
|
760
|
+
`);
|
|
761
|
+
|
|
762
|
+
expect(searchClient.search).toHaveBeenCalledTimes(1);
|
|
763
|
+
expect(searchClient.search.mock.calls[0][0]).toMatchInlineSnapshot(`
|
|
764
|
+
Array [
|
|
765
|
+
Object {
|
|
766
|
+
"indexName": "hello",
|
|
767
|
+
"params": Object {
|
|
768
|
+
"facets": Array [],
|
|
769
|
+
"hitsPerPage": 100,
|
|
770
|
+
"query": "",
|
|
771
|
+
"tagFilters": "",
|
|
772
|
+
},
|
|
773
|
+
},
|
|
774
|
+
]
|
|
775
|
+
`);
|
|
684
776
|
});
|
|
685
777
|
});
|
|
686
778
|
|
|
@@ -727,6 +819,7 @@ Array [
|
|
|
727
819
|
results: expect.anything(),
|
|
728
820
|
}),
|
|
729
821
|
]),
|
|
822
|
+
parent: expect.anything(),
|
|
730
823
|
state: expect.anything(),
|
|
731
824
|
instantSearchInstance: expect.anything(),
|
|
732
825
|
},
|
|
@@ -735,6 +828,7 @@ Object {
|
|
|
735
828
|
"createURL": [Function],
|
|
736
829
|
"helper": Anything,
|
|
737
830
|
"instantSearchInstance": Anything,
|
|
831
|
+
"parent": Anything,
|
|
738
832
|
"results": Anything,
|
|
739
833
|
"scopedResults": ArrayContaining [
|
|
740
834
|
ObjectContaining {
|
|
@@ -753,6 +847,58 @@ Object {
|
|
|
753
847
|
);
|
|
754
848
|
});
|
|
755
849
|
|
|
850
|
+
it('uses the results passed to hydrate for rendering', () => {
|
|
851
|
+
let instantSearchInstance;
|
|
852
|
+
mount({
|
|
853
|
+
mixins: [
|
|
854
|
+
createServerRootMixin({
|
|
855
|
+
searchClient: createFakeClient(),
|
|
856
|
+
indexName: 'lol',
|
|
857
|
+
}),
|
|
858
|
+
],
|
|
859
|
+
created() {
|
|
860
|
+
instantSearchInstance = this.instantsearch;
|
|
861
|
+
},
|
|
862
|
+
render() {},
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
const widget = {
|
|
866
|
+
init: jest.fn(),
|
|
867
|
+
render: jest.fn(),
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
const resultsState = createSerializedState();
|
|
871
|
+
const state = new SearchParameters(resultsState.state);
|
|
872
|
+
const results = new SearchResults(state, resultsState.results);
|
|
873
|
+
|
|
874
|
+
instantSearchInstance.hydrate({
|
|
875
|
+
lol: resultsState,
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
instantSearchInstance.__forceRender(
|
|
879
|
+
widget,
|
|
880
|
+
instantSearchInstance.mainIndex
|
|
881
|
+
);
|
|
882
|
+
|
|
883
|
+
expect(widget.init).toHaveBeenCalledTimes(0);
|
|
884
|
+
expect(widget.render).toHaveBeenCalledTimes(1);
|
|
885
|
+
|
|
886
|
+
const renderArgs = widget.render.mock.calls[0][0];
|
|
887
|
+
|
|
888
|
+
expect(renderArgs).toEqual(
|
|
889
|
+
expect.objectContaining({
|
|
890
|
+
state,
|
|
891
|
+
results,
|
|
892
|
+
scopedResults: [
|
|
893
|
+
expect.objectContaining({
|
|
894
|
+
indexId: 'lol',
|
|
895
|
+
results,
|
|
896
|
+
}),
|
|
897
|
+
],
|
|
898
|
+
})
|
|
899
|
+
);
|
|
900
|
+
});
|
|
901
|
+
|
|
756
902
|
describe('createURL', () => {
|
|
757
903
|
it('returns # if instantsearch has no routing', () => {
|
|
758
904
|
const app = new Vue({
|
|
@@ -34,6 +34,22 @@ export const createInstantSearchComponent = component =>
|
|
|
34
34
|
// private InstantSearch.js API:
|
|
35
35
|
this.instantSearchInstance._searchFunction = searchFunction;
|
|
36
36
|
},
|
|
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
|
+
},
|
|
37
53
|
},
|
|
38
54
|
created() {
|
|
39
55
|
const searchClient = this.instantSearchInstance.client;
|