@mekari/mekari-ui-vue
Version:
--- General web components in Mekari. The components are made using vue.js as its framework. Styling of components on Mekari UI Vue uses [Mekari UI Toolkit](https://bitbucket.org/mid-kelola-indonesia/mekari-ui-toolkit/src/master/). Don't forget to import
263 lines (234 loc) • 8.96 kB
JavaScript
import MDropdown from './index.vue';
import MDropdownSearch from './components/DropdownSearch.vue';
import MDropdownTrigger from './components/DropdownTrigger.vue';
import MDropdownMenu from './components/DropdownMenu.vue';
import MDropdownItem from './components/DropdownItem.vue';
import MDropdownPlugin from '../../plugins/Dropdown';
import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
localVue.use(MDropdownPlugin);
describe('Mekari UI Dropdown Component: index.vue', () => {
let wrapper;
const dummyContent = [{
id: 1,
content: 'Content of dropdown 1',
children: [],
}];
const multiDropdownDummyContent = [
{
id: 1,
content: 'Content of dropdown 1',
children: [
{
id: 3,
content: 'Content 1 children with id 3',
children: [{
id: 4,
content: 'Content 3 children with id 4',
children: [],
}],
},
{
id: 5,
content: 'Content 1 children with id 5',
children: [{
id: 6,
content: 'Content 5 children with id 6',
children: [],
}],
},
],
},
{
id: 2,
content: 'Content of dropdown 2',
children: [],
},
];
const slotDummy = (action = 'mouseenter', slotName = 'menu-1', options = { isSelectingItem: true }) => `
<template #${slotName}="{ content, setItemAction, menuNumber, activeItemId, isChildrenActive }">
<m-dropdown-item
v-for="item in content" :key="item.id"
@${action}.native="setItemAction(item, menuNumber, $event, {
isSelectingItem: ${options.isSelectingItem},
isHiddenAfterAction: ${options.isHiddenAfterAction}
})"
:isActive="isChildrenActive && item.id === activeItemId"
>
{{ item.content }}
</m-dropdown-item>
</template>
`;
function defaultWrapper() {
return shallowMount(MDropdown, {
localVue,
propsData: {
content: dummyContent,
},
scopedSlots: {
'menu-1': slotDummy('mouseenter'),
},
stubs: {
'm-dropdown-item': MDropdownItem,
},
attachTo: document.body.querySelector('#shadow-element'),
});
}
beforeEach(() => {
const shadowElement = document.createElement('div');
shadowElement.id = 'shadow-element';
document.body.appendChild(shadowElement);
});
afterEach(() => {
wrapper.destroy();
jest.restoreAllMocks();
});
it('should match snapshot', () => {
wrapper = defaultWrapper();
expect(wrapper.element).toMatchSnapshot();
});
it('should toggle dropdown visibility after button trigger', async () => {
wrapper = defaultWrapper();
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(false);
wrapper.findComponent(MDropdownTrigger).vm.$emit('dropdown-trigger', true);
await wrapper.vm.$nextTick();
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(true);
wrapper.findComponent(MDropdownTrigger).vm.$emit('dropdown-trigger', false);
await wrapper.vm.$nextTick();
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(false);
wrapper.findComponent(MDropdownTrigger).vm.$emit('dropdown-trigger', true);
await wrapper.vm.$nextTick();
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(true);
});
it('should emit dropdown data if dropdown item clicked', async () => {
wrapper = defaultWrapper();
wrapper.setProps({ enableMultiLevel: true });
await wrapper.vm.$nextTick();
wrapper.findComponent(MDropdownTrigger).vm.$emit('dropdown-trigger', true);
await wrapper.vm.$nextTick();
wrapper.findComponent(MDropdownItem).trigger('mouseenter');
await wrapper.vm.$nextTick();
expect(wrapper.emitted('selected-dropdown')[0]).toEqual(dummyContent);
});
it('should call window addEventListener on mousedown', () => {
jest.spyOn(window, 'addEventListener').mockImplementationOnce();
wrapper = defaultWrapper();
wrapper.findComponent(MDropdownTrigger).trigger('mousedown');
expect(window.addEventListener).toHaveBeenCalledTimes(1);
});
it('should call window removeEventListener on vue destory', () => {
jest.spyOn(window, 'removeEventListener').mockImplementationOnce();
wrapper = defaultWrapper();
wrapper.destroy();
expect(window.removeEventListener).toHaveBeenCalledTimes(1);
});
it('should keep the dropdown menu shown after item clicked if isHiddenAfterAction props is false', async () => {
const slotOptions = {
isSelectingItem: false,
isHiddenAfterAction: false,
};
wrapper = shallowMount(MDropdown, {
localVue,
propsData: {
content: dummyContent,
},
scopedSlots: {
'menu-1': slotDummy('click', 'menu-1', slotOptions),
},
stubs: {
'm-dropdown-item': MDropdownItem,
},
attachTo: document.body.querySelector('#shadow-element'),
});
wrapper.findComponent(MDropdownTrigger).vm.$emit('dropdown-trigger', true);
await wrapper.vm.$nextTick();
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(true);
wrapper.findComponent(MDropdownItem).trigger('click');
await wrapper.vm.$nextTick();
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(true);
});
it('should hide the dropdown menu shown after item clicked if isHiddenAfterAction options is true', async () => {
const slotOptions = {
isSelectingItem: true,
isHiddenAfterAction: true,
};
wrapper = shallowMount(MDropdown, {
localVue,
propsData: {
enableMultiLevel: true,
content: multiDropdownDummyContent,
},
scopedSlots: {
'menu-1': slotDummy('click', 'menu-1', slotOptions),
'menu-2': slotDummy('click', 'menu-2', slotOptions),
},
stubs: {
'm-dropdown-item': MDropdownItem,
},
attachTo: document.body.querySelector('#shadow-element'),
});
wrapper.findComponent(MDropdownTrigger).vm.$emit('dropdown-trigger', true);
await wrapper.vm.$nextTick();
await wrapper.vm.$nextTick();
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(true);
wrapper.findAllComponents(MDropdownItem).at(0).trigger('click');
await wrapper.vm.$nextTick();
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(false);
});
const multiLevelWrapperWithSearch = () => (
shallowMount(MDropdown, {
localVue,
propsData: {
enableMultiLevel: true,
enableSearch: [true, false, true],
content: multiDropdownDummyContent,
},
scopedSlots: {
'menu-1': slotDummy('mouseenter', 'menu-1', { isSelectingItem: false }),
'menu-2': slotDummy('mouseenter', 'menu-2', { isSelectingItem: false }),
'menu-3': slotDummy('mouseenter', 'menu-3', {}),
},
stubs: {
'm-dropdown-item': MDropdownItem,
},
attachTo: document.body.querySelector('#shadow-element'),
})
);
it('should show search input if the enable search is set to true', async () => {
wrapper = multiLevelWrapperWithSearch();
wrapper.findComponent(MDropdownTrigger).vm.$emit('dropdown-trigger', true);
wrapper.findAllComponents(MDropdownItem).at(0).trigger('mouseenter');
await wrapper.vm.$nextTick();
expect(wrapper.findAllComponents(MDropdownSearch).length).toBe(2);
});
it('should show item based on search input', async () => {
wrapper = multiLevelWrapperWithSearch();
wrapper.findComponent(MDropdownTrigger).vm.$emit('dropdown-trigger', true);
wrapper.findAllComponents(MDropdownItem).at(0).trigger('mouseenter');
await wrapper.vm.$nextTick();
wrapper.findAllComponents(MDropdownSearch).at(0).vm.$emit('input', {
value: 'hehe',
inputId: 0,
});
await wrapper.vm.$nextTick();
expect(wrapper.findAllComponents(MDropdownMenu).at(0).findAllComponents(MDropdownItem).length).toBe(0);
wrapper.findAllComponents(MDropdownSearch).at(0).vm.$emit('input', {
value: 'Content',
inputId: 0,
});
await wrapper.vm.$nextTick();
expect(wrapper.findAllComponents(MDropdownMenu).at(0).findAllComponents(MDropdownItem).length).toBe(2);
});
it('should not show any item if content is empty', () => {
wrapper = shallowMount(MDropdown, { localVue });
wrapper.findComponent(MDropdownTrigger).trigger('mousedown');
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(false);
});
it('should update visibility of dropdown menu based on property toggleShowDropdown', async () => {
wrapper = defaultWrapper();
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(false);
wrapper.setProps({ toggleShowDropdown: true });
await wrapper.vm.$nextTick();
expect(wrapper.findComponent(MDropdownMenu).isVisible()).toBe(true);
});
});