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

Commit

Permalink
fix(ssr): forward slots of the AisInstantSearchSsr component (#898)
Browse files Browse the repository at this point in the history
* fix(ssr): forward slots of the AisInstantSearchSsr component

The clone created in findResultsState also manually needs to forward slots, or the data won't be available.

* Update src/util/createServerRootMixin.js

* chore: also forward root

* scoped slots doesn't work, add tests
  • Loading branch information
Haroenv authored Dec 18, 2020
1 parent 98d7e46 commit 60b595e
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 0 deletions.
157 changes: 157 additions & 0 deletions src/util/__tests__/createServerRootMixin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
11 changes: 11 additions & 0 deletions src/util/createServerRootMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 60b595e

Please sign in to comment.