@davidrouyer/vue-instantsearch
Version:
👀 Lightning-fast Algolia search for Vue apps
748 lines (618 loc) • 16.3 kB
JavaScript
import { mount } from '@vue/test-utils';
import { __setState } from '../../mixins/widget';
import HierarchicalMenu from '../HierarchicalMenu.vue';
jest.mock('../../mixins/widget');
jest.mock('../../mixins/panel');
const apple = {
label: 'Apple',
value: 'Apple',
isRefined: false,
count: 80,
data: null,
};
const macbook = {
label: 'MacBook',
value: 'Apple > MacBook',
isRefined: false,
count: 40,
data: null,
};
const iphone = {
label: 'iPhone',
value: 'Apple > iPhone',
isRefined: false,
count: 20,
data: null,
};
const ipad = {
label: 'iPad',
value: 'Apple > iPad',
isRefined: false,
count: 20,
data: null,
};
const macbook13 = {
label: 'MacBook 13"',
value: 'Apple > MacBook > MacBook 13"',
isRefined: false,
count: 20,
data: null,
};
const macbook15 = {
label: 'MacBook 15"',
value: 'Apple > MacBook > MacBook 15"',
isRefined: false,
count: 10,
data: null,
};
const macbook12 = {
label: 'MacBook 12',
value: 'Apple > MacBook > MacBook',
isRefined: false,
count: 10,
data: null,
};
const samsung = {
label: 'Samsung',
value: 'Samsung',
isRefined: false,
count: 40,
data: null,
};
const galaxy = {
label: 'Galaxy',
value: 'Samsung > Galaxy',
isRefined: false,
count: 30,
data: null,
};
const note = {
label: 'Note',
value: 'Samsung > Note',
isRefined: false,
count: 10,
data: null,
};
const microsoft = {
label: 'Microsoft',
value: 'Microsoft',
isRefined: false,
count: 20,
data: null,
};
const defaultState = {
items: [
{
...apple,
data: [
iphone,
ipad,
{
...macbook,
data: [macbook13, macbook15, macbook12],
},
],
},
{
...samsung,
data: [galaxy, note],
},
microsoft,
],
refine: () => {},
createURL: () => {},
isShowingMore: false,
canToggleShowMore: true,
toggleShowMore: () => {},
};
const defaultProps = {
attributes: ['categories.lvl0', 'categories.lvl1', 'categories.lvl2'],
};
it('accepts an attributes prop', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
});
expect(wrapper.vm.widgetParams.attributes).toEqual([
'categories.lvl0',
'categories.lvl1',
'categories.lvl2',
]);
});
it('accepts a limit prop (without showMore)', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
showMore: false,
limit: 2,
showMoreLimit: 5,
},
});
expect(wrapper.vm.widgetParams.limit).toBe(2);
});
it('accepts a showMoreLimit prop (with showMore)', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
showMore: true,
limit: 2,
showMoreLimit: 5,
},
});
expect(wrapper.vm.widgetParams.showMoreLimit).toBe(5);
});
it('accepts a separator prop', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
separator: ' --> ',
},
});
expect(wrapper.vm.widgetParams.separator).toBe(' --> ');
});
it('accepts a rootPath prop', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
rootPath: 'Apple > MacBook',
},
});
expect(wrapper.vm.widgetParams.rootPath).toBe('Apple > MacBook');
});
it('accepts a showParentLevel prop', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
showParentLevel: false,
},
});
expect(wrapper.vm.widgetParams.showParentLevel).toBe(false);
});
it('accepts a sortBy prop', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
sortBy: ['count:asc'],
},
});
expect(wrapper.vm.widgetParams.sortBy).toEqual(['count:asc']);
});
it('accepts a transformItems prop', () => {
__setState({
...defaultState,
});
const transformItems = () => {};
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
transformItems,
},
});
expect(wrapper.vm.widgetParams.transformItems).toBe(transformItems);
});
describe('default render', () => {
it('renders correctly', () => {
__setState({ ...defaultState });
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
});
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly without refinement', () => {
__setState({
...defaultState,
items: [],
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
});
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly the parent of sub categories', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
});
expect(wrapper.findAll('.ais-HierarchicalMenu-item--parent')).toHaveLength(
3 // 2 Apple + 1 Samsung
);
});
it('renders correctly the list of sub categories', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
});
expect(wrapper.findAll('.ais-HierarchicalMenu-list--lvl0')).toHaveLength(1);
expect(wrapper.findAll('.ais-HierarchicalMenu-list--lvl1')).toHaveLength(2);
expect(wrapper.findAll('.ais-HierarchicalMenu-list--lvl2')).toHaveLength(1);
expect(wrapper.findAll('.ais-HierarchicalMenu-list--child')).toHaveLength(
3 // 2 Apple + 1 Samsung
);
});
it('renders correctly with a URL for the href', () => {
__setState({
...defaultState,
createURL: value => `/categories/${value}`,
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
});
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly a sub categories selected', () => {
__setState({
...defaultState,
items: [
{
...apple,
isRefined: true,
data: [
iphone,
ipad,
{
...macbook,
isRefined: true,
data: [macbook13, macbook15, macbook12],
},
],
},
{
...samsung,
data: [galaxy, note],
},
microsoft,
],
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
});
expect(
wrapper.findAll('.ais-HierarchicalMenu-item--selected')
).toHaveLength(2);
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly with show more disabled', () => {
__setState({
...defaultState,
canToggleShowMore: false,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
showMore: true,
},
});
const button = wrapper.find('button');
expect(button.attributes().disabled).toBe('disabled');
expect(button.classes()).toContain(
'ais-HierarchicalMenu-showMore--disabled'
);
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly with show more label', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
showMore: true,
},
});
const showMoreButton = wrapper.find('.ais-HierarchicalMenu-showMore');
expect(showMoreButton.text()).toBe('Show more');
expect(showMoreButton.html()).toMatchSnapshot();
});
it('renders correctly with show more label toggled', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
showMore: true,
limit: 1,
},
});
const button = wrapper.find('button');
button.trigger('click');
wrapper.setData({
state: {
isShowingMore: true,
},
});
expect(button.text()).toBe('Show less');
expect(button.html()).toMatchSnapshot();
});
it('calls refine on link click', () => {
const refine = jest.fn();
__setState({
...defaultState,
refine,
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
});
wrapper
.find('.ais-HierarchicalMenu-list--lvl2')
.findAll('a')
.at(1)
.trigger('click');
expect(refine).toHaveBeenCalledTimes(1);
expect(refine).toHaveBeenCalledWith('Apple > MacBook > MacBook 15"');
});
it('calls toggleShowMore on button click', () => {
const toggleShowMore = jest.fn();
__setState({
...defaultState,
toggleShowMore,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
showMore: true,
limit: 1,
},
});
wrapper.find('button').trigger('click');
expect(toggleShowMore).toHaveBeenCalledTimes(1);
});
it('calls the Panel mixin with `items.length`', () => {
__setState({ ...defaultState });
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
});
const mapStateToCanRefine = () =>
wrapper.vm.mapStateToCanRefine(wrapper.vm.state);
expect(mapStateToCanRefine()).toBe(true);
wrapper.setData({
state: {
items: [],
},
});
expect(mapStateToCanRefine()).toBe(false);
});
});
describe('custom default render', () => {
const defaultScopedSlot = `
<div
slot-scope="state"
:class="[!state.canRefine && 'no-refinement']"
>
<ol>
<li
v-for="item in state.items"
:key="item.value"
>
<a
:href="state.createURL(item.value)"
@click.prevent="state.refine(item.value)"
>
{{item.label}} - {{item.count}}
</a>
<ol v-if="item.data">
<li
v-for="child in item.data"
:key="child.value"
>
<a
:href="state.createURL(child.value)"
@click.prevent="state.refine(child.value)"
>
{{child.label}} - {{child.count}}
</a>
</li>
</ol>
</li>
</ol>
<button
:disabled="!state.canToggleShowMore"
@click.prevent="state.toggleShowMore"
>
{{ state.isShowingMore ? 'View less' : 'View more' }}
</button>
</div>
`;
it('renders correctly', () => {
__setState({ ...defaultState });
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
scopedSlots: {
default: defaultScopedSlot,
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly without refinement', () => {
__setState({
...defaultState,
items: [],
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
scopedSlots: {
default: defaultScopedSlot,
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly with an URL for the href', () => {
__setState({
...defaultState,
createURL: value => `/categories/${value.replace(/ > /g, '/')}`,
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
scopedSlots: {
default: defaultScopedSlot,
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly with a limit', () => {
__setState({
...defaultState,
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
limit: 1,
},
scopedSlots: {
default: defaultScopedSlot,
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly with a show more button toggled', () => {
__setState({
...defaultState,
toggleShowMore: () => {
wrapper.setData({
state: {
isShowingMore: true,
},
});
},
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
limit: 1,
},
scopedSlots: {
default: defaultScopedSlot,
},
});
expect(wrapper.find('button').text()).toBe('View more');
expect(wrapper.html()).toMatchSnapshot();
wrapper.find('button').trigger('click');
expect(wrapper.find('button').text()).toBe('View less');
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly with a disabled show more button', () => {
__setState({
...defaultState,
canToggleShowMore: false,
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
scopedSlots: {
default: defaultScopedSlot,
},
});
expect(wrapper.find('button').attributes().disabled).toBe('disabled');
expect(wrapper.html()).toMatchSnapshot();
});
it('calls refine on link click', () => {
const refine = jest.fn();
__setState({
...defaultState,
refine,
});
const wrapper = mount(HierarchicalMenu, {
propsData: defaultProps,
scopedSlots: {
default: defaultScopedSlot,
},
});
wrapper
.findAll('ol')
.at(1)
.findAll('a')
.at(2)
.trigger('click');
expect(refine).toHaveBeenCalledTimes(1);
expect(refine).toHaveBeenCalledWith('Apple > MacBook');
});
it('calls toggleShowMore on button click', () => {
__setState({
...defaultState,
toggleShowMore: () => {
wrapper.setData({ state: { isShowingMore: true } });
},
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
showMore: true,
limit: 1,
},
scopedSlots: {
default: defaultScopedSlot,
},
});
expect(wrapper.vm.state.isShowingMore).toBe(false);
wrapper.find('button').trigger('click');
expect(wrapper.vm.state.isShowingMore).toBe(true);
});
});
describe('custom showMoreLabel render', () => {
const showMoreLabelScopedSlot = `
<span slot-scope="{ isShowingMore }">
{{ isShowingMore ? 'Voir moins' : 'Voir plus' }}
</span>
`;
it('renders correctly with a custom show more label', () => {
__setState({ ...defaultState });
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
showMore: true,
limit: 1,
},
scopedSlots: {
showMoreLabel: showMoreLabelScopedSlot,
},
});
expect(wrapper.find('.ais-HierarchicalMenu-showMore').text()).toBe(
'Voir plus'
);
expect(wrapper.html()).toMatchSnapshot();
});
it('renders correctly with a custom show more label toggled', () => {
__setState({
...defaultState,
toggleShowMore: () => wrapper.setData({ state: { isShowingMore: true } }),
});
const wrapper = mount(HierarchicalMenu, {
propsData: {
...defaultProps,
showMore: true,
limit: 1,
},
scopedSlots: {
showMoreLabel: showMoreLabelScopedSlot,
},
});
wrapper.find('button').trigger('click');
expect(wrapper.find('.ais-HierarchicalMenu-showMore').text()).toBe(
'Voir moins'
);
expect(wrapper.html()).toMatchSnapshot();
});
});