diff --git a/src/util/__tests__/createServerRootMixin.test.js b/src/util/__tests__/createServerRootMixin.test.js index 200b5bffc..afec17dc7 100644 --- a/src/util/__tests__/createServerRootMixin.test.js +++ b/src/util/__tests__/createServerRootMixin.test.js @@ -362,6 +362,163 @@ Array [ await renderToString(wrapper); }); + + it('forwards slots', async done => { + const searchClient = createFakeClient(); + + expect.assertions(2); + + const App = Vue.component('App', { + mixins: [ + forceIsServerMixin, + createServerRootMixin({ + searchClient, + indexName: 'hello', + }), + ], + render(h) { + return h(InstantSearchSsr, {}, this.$slots.default); + }, + serverPrefetch() { + return ( + this.instantsearch + .findResultsState(this) + .then(res => { + expect( + this.instantsearch.mainIndex.getWidgets().map(w => w.$$type) + ).toEqual(['ais.configure']); + + expect(res.hello._state.hitsPerPage).toBe(100); + }) + // jest throws an error we need to catch, since stuck in the flow + .catch(e => { + done.fail(e); + }) + ); + }, + }); + + const wrapper = new Vue({ + mixins: [forceIsServerMixin], + render(h) { + return h(App, [ + h('template', { slot: 'default' }, [ + h(Configure, { + attrs: { + hitsPerPage: 100, + }, + }), + ]), + ]); + }, + }); + + await renderToString(wrapper); + done(); + }); + + // TODO: forwarding of scoped slots doesn't yet work. + it.skip('forwards scoped slots', async done => { + const searchClient = createFakeClient(); + + expect.assertions(2); + + const App = Vue.component('App', { + mixins: [ + forceIsServerMixin, + createServerRootMixin({ + searchClient, + indexName: 'hello', + }), + ], + render(h) { + return h(InstantSearchSsr, {}, [ + this.$scopedSlots.default({ test: true }), + ]); + }, + serverPrefetch() { + return ( + this.instantsearch + .findResultsState(this) + .then(res => { + expect( + this.instantsearch.mainIndex.getWidgets().map(w => w.$$type) + ).toEqual(['ais.configure']); + + expect(res.hello._state.hitsPerPage).toBe(100); + }) + // jest throws an error we need to catch, since stuck in the flow + .catch(e => { + done.fail(e); + }) + ); + }, + }); + + const wrapper = new Vue({ + mixins: [forceIsServerMixin], + render(h) { + return h(App, { + scopedSlots: { + default({ test }) { + if (test) { + return h(Configure, { + attrs: { + hitsPerPage: 100, + }, + }); + } + return null; + }, + }, + }); + }, + }); + + await renderToString(wrapper); + done(); + }); + + it('forwards root', async () => { + const searchClient = createFakeClient(); + + // there are two renders of App, each with an assertion + expect.assertions(2); + + const App = Vue.component('App', { + mixins: [ + forceIsServerMixin, + createServerRootMixin({ + searchClient, + indexName: 'hello', + }), + ], + render(h) { + expect(this.$root).toBe(wrapper); + + return h(InstantSearchSsr, {}, [ + h(Configure, { + attrs: { + hitsPerPage: 100, + }, + }), + h(SearchBox), + ]); + }, + serverPrefetch() { + return this.instantsearch.findResultsState(this); + }, + }); + + const wrapper = new Vue({ + mixins: [forceIsServerMixin], + render(h) { + return h(App); + }, + }); + + await renderToString(wrapper); + }); }); describe('hydrate', () => { diff --git a/src/util/createServerRootMixin.js b/src/util/createServerRootMixin.js index 883817007..527048c49 100644 --- a/src/util/createServerRootMixin.js +++ b/src/util/createServerRootMixin.js @@ -88,6 +88,11 @@ function augmentInstantSearch(instantSearchOptions, searchClient, indexName) { propsData: componentInstance.$options.propsData, }); + // https://stackoverflow.com/a/48195006/3185307 + app.$slots = componentInstance.$slots; + + app.$root = componentInstance.$root; + app.$options.serverPrefetch = []; app.instantsearch.helper = helper; @@ -160,6 +165,12 @@ function augmentInstantSearch(instantSearchOptions, searchClient, indexName) { const results = search.__initialSearchResults[parent.getIndexId()]; + // this happens when a different InstantSearch gets rendered initially, + // after the hydrate finished. There's thus no initial results available. + if (!results) { + return; + } + const state = results._state; // helper gets created in init, but that means it doesn't get the injected