UNPKG

vue-instantsearch

Version:

👀 Lightning-fast Algolia search for Vue apps

828 lines (692 loc) • 17.8 kB
import { mount } from '../../../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: () => {}, sendEvent: () => {}, }; 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).toBeDisabled(); expect(button.classes()).toContain( 'ais-HierarchicalMenu-showMore--disabled' ); expect(wrapper.htmlCompat()).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', async () => { __setState({ ...defaultState, }); const wrapper = mount(HierarchicalMenu, { propsData: { ...defaultProps, showMore: true, limit: 1, }, }); const button = wrapper.find('button'); await button.trigger('click'); await wrapper.setData({ state: { isShowingMore: true, }, }); expect(button.text()).toBe('Show less'); expect(button.html()).toMatchSnapshot(); }); it('calls refine on link click', async () => { const refine = jest.fn(); __setState({ ...defaultState, refine, }); const wrapper = mount(HierarchicalMenu, { propsData: defaultProps, }); await wrapper .find( '.ais-HierarchicalMenu-list--lvl2 .ais-HierarchicalMenu-item:nth-child(2) a' ) .trigger('click'); expect(refine).toHaveBeenCalledTimes(1); expect(refine).toHaveBeenCalledWith('Apple > MacBook > MacBook 15"'); }); it('calls toggleShowMore on button click', async () => { const toggleShowMore = jest.fn(); __setState({ ...defaultState, toggleShowMore, }); const wrapper = mount(HierarchicalMenu, { propsData: { ...defaultProps, showMore: true, limit: 1, }, }); await wrapper.find('button').trigger('click'); expect(toggleShowMore).toHaveBeenCalledTimes(1); }); }); it('calls the Panel mixin with `items.length`', async () => { __setState({ ...defaultState }); const wrapper = mount(HierarchicalMenu, { propsData: defaultProps, }); const mapStateToCanRefine = () => wrapper.vm.mapStateToCanRefine(wrapper.vm.state); expect(mapStateToCanRefine()).toBe(true); await wrapper.setData({ state: { items: [] } }); expect(mapStateToCanRefine()).toBe(false); expect(wrapper.vm.mapStateToCanRefine({})).toBe(false); }); it('exposes send-event method for insights middleware', async () => { const sendEvent = jest.fn(); __setState({ ...defaultState, sendEvent, }); const wrapper = mount({ components: { HierarchicalMenu }, data() { return { props: defaultProps }; }, template: ` <HierarchicalMenu v-bind="props"> <template v-slot="{ sendEvent }"> <div> <button @click="sendEvent()">Send Event</button> </div> </template> </HierarchicalMenu> `, }); await wrapper.find('button').trigger('click'); expect(sendEvent).toHaveBeenCalledTimes(1); }); describe('custom default render', () => { const defaultSlot = ` <template v-slot="state"> <div :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> </template> `; it('renders correctly', () => { __setState({ ...defaultState }); const wrapper = mount({ components: { HierarchicalMenu }, data() { return { props: defaultProps }; }, template: ` <HierarchicalMenu v-bind="props"> ${defaultSlot} </HierarchicalMenu> `, }); expect(wrapper.html()).toMatchSnapshot(); }); it('renders correctly without refinement', () => { __setState({ ...defaultState, items: [], }); const wrapper = mount({ components: { HierarchicalMenu }, data() { return { props: defaultProps }; }, template: ` <HierarchicalMenu v-bind="props"> ${defaultSlot} </HierarchicalMenu> `, }); expect(wrapper.html()).toMatchSnapshot(); }); it('renders correctly with an URL for the href', () => { __setState({ ...defaultState, createURL: value => `/categories/${value.replace(/ > /g, '/')}`, }); const wrapper = mount({ components: { HierarchicalMenu }, data() { return { props: defaultProps }; }, template: ` <HierarchicalMenu v-bind="props"> ${defaultSlot} </HierarchicalMenu> `, }); expect(wrapper.html()).toMatchSnapshot(); }); it('renders correctly with a limit', () => { __setState({ ...defaultState, }); const props = { ...defaultProps, limit: 1, }; const wrapper = mount({ components: { HierarchicalMenu }, data() { return { props }; }, template: ` <HierarchicalMenu v-bind="props"> ${defaultSlot} </HierarchicalMenu> `, }); expect(wrapper.html()).toMatchSnapshot(); }); it('renders correctly with a show more button toggled', async () => { __setState({ ...defaultState, toggleShowMore: () => { const component = wrapper.findComponent(HierarchicalMenu); component.setData({ state: { isShowingMore: true } }); }, }); const props = { ...defaultProps, limit: 1, }; const wrapper = mount({ components: { HierarchicalMenu }, data() { return { props }; }, template: ` <HierarchicalMenu v-bind="props"> ${defaultSlot} </HierarchicalMenu> `, }); expect(wrapper.find('button').text()).toBe('View more'); expect(wrapper.html()).toMatchSnapshot(); await 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({ components: { HierarchicalMenu }, data() { return { props: defaultProps }; }, template: ` <HierarchicalMenu v-bind="props"> ${defaultSlot} </HierarchicalMenu> `, }); expect(wrapper.find('button')).toBeDisabled(); expect(wrapper.htmlCompat()).toMatchSnapshot(); }); it('calls refine on link click', async () => { const refine = jest.fn(); __setState({ ...defaultState, refine, }); const wrapper = mount({ components: { HierarchicalMenu }, data() { return { props: defaultProps }; }, template: ` <HierarchicalMenu v-bind="props"> ${defaultSlot} </HierarchicalMenu> `, }); await wrapper.find('ol ol li:nth-child(3) a').trigger('click'); expect(refine).toHaveBeenCalledTimes(1); expect(refine).toHaveBeenCalledWith('Apple > MacBook'); }); it('calls toggleShowMore on button click', async () => { __setState({ ...defaultState, toggleShowMore: () => { const component = wrapper.findComponent(HierarchicalMenu); component.setData({ state: { isShowingMore: true } }); }, }); const props = { ...defaultProps, showMore: true, limit: 1, }; const wrapper = mount({ components: { HierarchicalMenu }, data() { return { props }; }, template: ` <HierarchicalMenu v-bind="props"> ${defaultSlot} </HierarchicalMenu> `, }); expect(wrapper.find('button').text()).toEqual('View more'); await wrapper.find('button').trigger('click'); expect(wrapper.find('button').text()).toEqual('View less'); }); }); describe('custom showMoreLabel render', () => { const showMoreLabelSlot = ` <template v-slot:showMoreLabel="{ isShowingMore }"> <span> {{ isShowingMore ? 'Voir moins' : 'Voir plus' }} </span> </template> `; it('renders correctly with a custom show more label', () => { __setState({ ...defaultState }); const props = { ...defaultProps, showMore: true, limit: 1, }; const wrapper = mount({ components: { HierarchicalMenu }, data() { return { props }; }, template: ` <HierarchicalMenu v-bind="props"> ${showMoreLabelSlot} </HierarchicalMenu> `, }); expect(wrapper.find('.ais-HierarchicalMenu-showMore').text()).toBe( 'Voir plus' ); expect(wrapper.html()).toMatchSnapshot(); }); it('renders correctly with a custom show more label toggled', async () => { __setState({ ...defaultState, toggleShowMore: () => { const component = wrapper.findComponent(HierarchicalMenu); component.setData({ state: { isShowingMore: true } }); }, }); const props = { ...defaultProps, showMore: true, limit: 1, }; const wrapper = mount({ components: { HierarchicalMenu }, data() { return { props }; }, template: ` <HierarchicalMenu v-bind="props"> ${showMoreLabelSlot} </HierarchicalMenu> `, }); await wrapper.find('button').trigger('click'); expect(wrapper.find('.ais-HierarchicalMenu-showMore').text()).toBe( 'Voir moins' ); expect(wrapper.html()).toMatchSnapshot(); }); });