vue-instantsearch-ssr
Version:
👀 Lightning-fast Algolia search for Vue apps
336 lines (280 loc) • 8.66 kB
JavaScript
import { mount } from '../../../test/utils';
import { createWidgetMixin } from '../widget';
const createFakeComponent = (props = {}) => ({
render: () => null,
...props,
});
const createFakeInstance = () => ({
addWidgets: jest.fn(),
removeWidgets: jest.fn(),
mainIndex: createFakeIndexWidget(),
started: true,
});
const createFakeIndexWidget = () => ({
addWidgets: jest.fn(),
removeWidgets: jest.fn(),
});
describe('on root index', () => {
it('adds a widget on create', () => {
const instance = createFakeInstance();
const widget = { render: () => {} };
const factory = jest.fn(() => widget);
const connector = jest.fn(() => factory);
const widgetParams = {
attribute: 'brand',
};
const Test = createFakeComponent({
mixins: [createWidgetMixin({ connector })],
computed: {
widgetParams() {
return widgetParams;
},
},
});
mount(Test, {
provide: {
$_ais_instantSearchInstance: instance,
},
});
expect(connector).toHaveBeenCalled();
expect(factory).toHaveBeenCalledWith(widgetParams);
expect(instance.mainIndex.addWidgets).toHaveBeenCalledWith([widget]);
});
it('removes a widget on destroy', () => {
const instance = createFakeInstance();
const widget = {
render: () => {},
dispose: () => {},
};
const factory = jest.fn(() => widget);
const connector = jest.fn(() => factory);
const Test = createFakeComponent({
mixins: [createWidgetMixin({ connector })],
});
const widgetParams = {
attribute: 'brand',
};
const wrapper = mount(Test, {
provide: {
$_ais_instantSearchInstance: instance,
},
data: () => ({
widgetParams,
}),
});
expect(instance.mainIndex.addWidgets).toHaveBeenCalledWith([widget]);
wrapper.destroy();
expect(instance.mainIndex.removeWidgets).toHaveBeenCalledWith([widget]);
});
it('updates widget on widget params change', async () => {
const instance = createFakeInstance();
const widget = {
render: () => {},
dispose: () => {},
};
const factory = jest.fn(() => widget);
const connector = jest.fn(() => factory);
const widgetParams = {
attribute: 'brand',
};
const Test = createFakeComponent({
mixins: [createWidgetMixin({ connector })],
data: () => ({
widgetParams,
}),
});
const nextWidgetParams = {
attribute: 'price',
};
const wrapper = mount(Test, {
provide: {
$_ais_instantSearchInstance: instance,
},
});
// Simulate render
await wrapper.setData({
state: { items: [] },
});
expect(instance.mainIndex.addWidgets).toHaveBeenCalledTimes(1);
expect(instance.mainIndex.addWidgets).toHaveBeenCalledWith([widget]);
// Simulate widget params update
await wrapper.setData({
widgetParams: nextWidgetParams,
});
expect(wrapper.vm.state).toBe(null);
expect(instance.mainIndex.removeWidgets).toHaveBeenCalledTimes(1);
expect(instance.mainIndex.removeWidgets).toHaveBeenCalledWith([widget]);
expect(factory).toHaveBeenCalledTimes(2);
expect(factory).toHaveBeenCalledWith(nextWidgetParams);
expect(instance.mainIndex.addWidgets).toHaveBeenCalledTimes(2);
expect(instance.mainIndex.addWidgets).toHaveBeenCalledWith([widget]);
});
it('updates local state on connector render', () => {
const instance = createFakeInstance();
const widget = { render: () => {} };
const factory = jest.fn(() => widget);
const connector = jest.fn(() => factory);
const Test = createFakeComponent({
mixins: [createWidgetMixin({ connector })],
});
const widgetParams = {
attribute: 'brand',
};
const state = {
items: [],
};
const wrapper = mount(Test, {
provide: {
$_ais_instantSearchInstance: instance,
},
data: () => ({
widgetParams,
}),
});
// Simulate init
connector.mock.calls[0][0](state, true);
// Avoid to update the state on first render
// otherwise we have a flash from empty state
// to the next state
expect(wrapper.vm.state).toBe(null);
// Simulate render
connector.mock.calls[0][0](state, false);
expect(wrapper.vm.state).toEqual(state);
});
});
describe('on child index', () => {
it('adds a widget on create', () => {
const instance = createFakeInstance();
const indexWidget = createFakeIndexWidget();
const widget = { render: () => {} };
const factory = jest.fn(() => widget);
const connector = jest.fn(() => factory);
const widgetParams = {
attribute: 'brand',
};
const Test = createFakeComponent({
mixins: [createWidgetMixin({ connector })],
computed: {
widgetParams() {
return widgetParams;
},
},
});
mount(Test, {
provide: {
$_ais_instantSearchInstance: instance,
$_ais_getParentIndex: () => indexWidget,
},
});
expect(connector).toHaveBeenCalled();
expect(factory).toHaveBeenCalledWith(widgetParams);
expect(indexWidget.addWidgets).toHaveBeenCalledWith([widget]);
});
it('removes a widget on destroy', () => {
const instance = createFakeInstance();
const indexWidget = createFakeIndexWidget();
const widget = {
render: () => {},
dispose: () => {},
};
const factory = jest.fn(() => widget);
const connector = jest.fn(() => factory);
const Test = createFakeComponent({
mixins: [createWidgetMixin({ connector })],
});
const widgetParams = {
attribute: 'brand',
};
const wrapper = mount(Test, {
provide: {
$_ais_instantSearchInstance: instance,
$_ais_getParentIndex: () => indexWidget,
},
data: () => ({
widgetParams,
}),
});
expect(indexWidget.addWidgets).toHaveBeenCalledWith([widget]);
wrapper.destroy();
expect(indexWidget.removeWidgets).toHaveBeenCalledWith([widget]);
});
it('updates widget on widget params change', async () => {
const instance = createFakeInstance();
const indexWidget = createFakeIndexWidget();
const widget = {
render: () => {},
dispose: () => {},
};
const factory = jest.fn(() => widget);
const connector = jest.fn(() => factory);
const widgetParams = {
attribute: 'brand',
};
const Test = createFakeComponent({
mixins: [createWidgetMixin({ connector })],
data: () => ({
widgetParams,
}),
});
const nextWidgetParams = {
attribute: 'price',
};
const wrapper = mount(Test, {
provide: {
$_ais_instantSearchInstance: instance,
$_ais_getParentIndex: () => indexWidget,
},
});
// Simulate render
await wrapper.setData({
state: { items: [] },
});
expect(indexWidget.addWidgets).toHaveBeenCalledTimes(1);
expect(indexWidget.addWidgets).toHaveBeenCalledWith([widget]);
// Simulate widget params update
await wrapper.setData({
widgetParams: nextWidgetParams,
});
expect(wrapper.vm.state).toBe(null);
expect(indexWidget.removeWidgets).toHaveBeenCalledTimes(1);
expect(indexWidget.removeWidgets).toHaveBeenCalledWith([widget]);
expect(factory).toHaveBeenCalledTimes(2);
expect(factory).toHaveBeenCalledWith(nextWidgetParams);
expect(indexWidget.addWidgets).toHaveBeenCalledTimes(2);
expect(indexWidget.addWidgets).toHaveBeenCalledWith([widget]);
});
it('updates local state on connector render', () => {
const instance = createFakeInstance();
const indexWidget = createFakeIndexWidget();
const widget = { render: () => {} };
const factory = jest.fn(() => widget);
const connector = jest.fn(() => factory);
const widgetParams = {
attribute: 'brand',
};
const Test = createFakeComponent({
mixins: [createWidgetMixin({ connector })],
data: () => ({
widgetParams,
}),
});
const state = {
items: [],
};
const wrapper = mount(Test, {
provide: {
$_ais_instantSearchInstance: instance,
$_ais_getParentIndex: () => indexWidget,
},
});
// Simulate init
connector.mock.calls[0][0](state, true);
// Avoid to update the state on first render
// otherwise we have a flash from empty state
// to the next state
expect(wrapper.vm.state).toBe(null);
// Simulate render
connector.mock.calls[0][0](state, false);
expect(wrapper.vm.state).toEqual(state);
});
});