uiv
Version:
Bootstrap 3 components implemented by Vue.
336 lines (315 loc) • 13.1 kB
JavaScript
import {
createWrapper,
nextTick,
triggerEvent,
windowClick,
} from '../../__test__/utils';
import Dropdown from './Dropdown';
function appendToBodyVm() {
return createWrapper(`<div><dropdown append-to-body>
<btn class="dropdown-toggle">Dropdown <span class="caret"></span></btn>
<template #dropdown>
<li><a role="button">Action</a></li>
<li><a role="button">Another action</a></li>
<li><a role="button">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a role="button">Separated link</a></li>
</template>
</dropdown>
<!-- dropdown with append-to-body + menu-right -->
<dropdown append-to-body menu-right>
<btn class="dropdown-toggle">Menu-Right <span class="caret"></span></btn>
<template #dropdown>
<li><a role="button">Action</a></li>
<li><a role="button">Another action</a></li>
<li><a role="button">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a role="button">Separated link</a></li>
</template>
</dropdown>
<!-- dropdown with append-to-body + dropup -->
<dropdown append-to-body dropup>
<btn class="dropdown-toggle">Dropup <span class="caret"></span></btn>
<template #dropdown>
<li><a role="button">Action</a></li>
<li><a role="button">Another action</a></li>
<li><a role="button">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a role="button">Separated link</a></li>
</template>
</dropdown></div>`);
}
function baseVm() {
return createWrapper(`<div><dropdown ref="dropdown">
<btn type="primary" class="dropdown-toggle">Dropdown <span class="caret"></span></btn>
<template #dropdown>
<li><a role="button">Action</a></li>
<li><a role="button">Another action</a></li>
<li><a role="button">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a role="button">Separated link</a></li>
</template>
</dropdown>
<dropdown>
<btn type="info">Split Button</btn>
<btn type="info" class="dropdown-toggle"><span class="caret"></span></btn>
<template #dropdown>
<li><a role="button">Action</a></li>
<li><a role="button">Another action</a></li>
<li><a role="button">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a role="button">Separated link</a></li>
</template>
</dropdown></div>`);
}
async function assertKeyboardNav(
trigger,
wrapper,
index,
keyCode,
called = true
) {
const spy = jest.spyOn(wrapper.findAll('li > a')[index].element, 'focus');
await triggerEvent(trigger, `keydown.${keyCode}`);
if (called) {
expect(spy).toBeCalled();
} else {
expect(spy).not.toBeCalled();
}
spy.mockRestore();
// wrapper.find('li > a').removeAttr('focus')
// wrapper.find('li > a').at(index).attr('focus', true)
}
describe('Dropdown', () => {
it('should be able to open dropdown on trigger click', async () => {
const wrapper = baseVm();
const dropdown = wrapper.find('.dropdown');
const trigger = dropdown.find('button');
expect(dropdown.element.tagName.toLowerCase()).toEqual('div');
expect(dropdown.classes()).not.toContain('open');
await triggerEvent(trigger, 'click');
await nextTick();
expect(dropdown.classes()).toContain('open');
});
it('should be able to close dropdown using keyboard esc', async () => {
const wrapper = baseVm();
const dropdown = wrapper.find('.dropdown');
const trigger = dropdown.find('button');
expect(dropdown.element.tagName.toLowerCase()).toEqual('div');
expect(dropdown.classes()).not.toContain('open');
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).toContain('open');
await triggerEvent(trigger, 'keydown.esc');
expect(dropdown.classes()).not.toContain('open');
});
it('should be able to navigate between items using keyboard up & down', async () => {
const wrapper = baseVm();
const dropdown = wrapper.find('.dropdown');
const trigger = dropdown.find('button');
expect(dropdown.element.tagName.toLowerCase()).toEqual('div');
expect(dropdown.classes()).not.toContain('open');
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).toContain('open');
await assertKeyboardNav(trigger, dropdown, 0, 'down');
await assertKeyboardNav(trigger, dropdown, 1, 'down');
await assertKeyboardNav(trigger, dropdown, 0, 'up');
await assertKeyboardNav(trigger, dropdown, 0, 'up', false);
await assertKeyboardNav(trigger, dropdown, 1, 'down');
await assertKeyboardNav(trigger, dropdown, 2, 'down');
await assertKeyboardNav(trigger, dropdown, 3, 'down');
await assertKeyboardNav(trigger, dropdown, 3, 'down', false);
});
it('should not be able to navigate between items using keyboard up & down when dropdown is not open', async () => {
const wrapper = baseVm();
const dropdown = wrapper.find('.dropdown');
const trigger = dropdown.find('button');
expect(dropdown.element.tagName.toLowerCase()).toEqual('div');
expect(dropdown.classes()).not.toContain('open');
await assertKeyboardNav(trigger, dropdown, 0, 'down', false);
});
it('should be able to navigate between items and select with keyboard enter', async () => {
const wrapper = baseVm();
const dropdown = wrapper.find('.dropdown');
const trigger = dropdown.find('button');
expect(dropdown.element.tagName.toLowerCase()).toEqual('div');
expect(dropdown.classes()).not.toContain('open');
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).toContain('open');
await assertKeyboardNav(trigger, dropdown, 0, 'down');
const spy = jest.spyOn(dropdown.findAll('li > a')[0].element, 'click');
await triggerEvent(trigger, 'keydown.enter');
expect(spy).toBeCalled();
});
it('should ignore other keys when open', async () => {
const wrapper = baseVm();
const dropdown = wrapper.find('.dropdown');
const trigger = dropdown.find('button');
expect(dropdown.element.tagName.toLowerCase()).toEqual('div');
expect(dropdown.classes()).not.toContain('open');
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).toContain('open');
await assertKeyboardNav(trigger, dropdown, 0, 'down');
await assertKeyboardNav(trigger, dropdown, 1, 'left', false);
});
it('should be able to close dropdown on trigger click', async () => {
const wrapper = baseVm();
const dropdown = wrapper.find('.dropdown');
const trigger = dropdown.find('button');
expect(dropdown.element.tagName.toLowerCase()).toEqual('div');
expect(dropdown.classes()).not.toContain('open');
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).toContain('open');
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).not.toContain('open');
});
it('should be able to close dropdown on window click', async () => {
const wrapper = baseVm();
const dropdown = wrapper.find('.dropdown');
const trigger = dropdown.find('button');
expect(dropdown.element.tagName.toLowerCase()).toEqual('div');
expect(dropdown.classes()).not.toContain('open');
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).toContain('open');
windowClick(document.body);
await nextTick();
expect(dropdown.classes()).not.toContain('open');
});
it('should not close dropdown on self click if not-close-elements contains component ref and with append-to-body', async () => {
const wrapper = createWrapper(
`<dropdown v-model="show" ref="test" append-to-body :not-close-elements="eles">
<button class="btn btn-default dropdown-toggle" type="button">
<span>Dropdown 1</span><span class="caret"></span>
</button>
<template #dropdown>
<li ref="li1"><a href="#">Action</a></li>
<li ref="li2"><a href="#">Action2</a></li>
</template>
</dropdown>`,
{
show: true,
eles: [],
},
{
mounted() {
this.eles.push(this.$refs.li1);
},
}
);
await nextTick();
const dropdown = wrapper;
expect(dropdown.element.tagName.toLowerCase()).toEqual('div');
expect(dropdown.classes()).toContain('open');
windowClick(wrapper.vm.$refs.li1);
await nextTick();
expect(dropdown.classes()).toContain('open');
windowClick(document.body);
await nextTick();
expect(dropdown.classes()).not.toContain('open');
wrapper.vm.show = true;
await nextTick();
windowClick(wrapper.vm.$refs.li2);
await nextTick();
expect(dropdown.classes()).not.toContain('open');
});
it('should be able to open dropdown append to body on trigger click', async () => {
const wrapper = appendToBodyVm();
const dropdown = wrapper.find('.dropdown');
const trigger = dropdown.find('button');
expect(dropdown.classes()).not.toContain('open');
// console.log(wrapper.html())
expect(dropdown.find('.dropdown-menu')).toBeDefined();
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).toContain('open');
expect(document.querySelectorAll('body>.dropdown-menu').length).toEqual(1);
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).not.toContain('open');
expect(dropdown.find('.dropdown-menu')).toBeDefined();
});
it('should be able to use dropup style', async () => {
const wrapper = createWrapper(`<div><dropdown dropup>
<btn class="dropdown-toggle">Dropup <span class="caret"></span></btn>
<template #dropdown>
<li><a role="button">Action</a></li>
<li><a role="button">Another action</a></li>
<li><a role="button">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a role="button">Separated link</a></li>
</template>
</dropdown></div>`);
await nextTick();
const dropup = wrapper.find('.dropup');
expect(dropup.classes()).not.toContain('open');
expect(dropup.find('.dropdown-menu')).toBeDefined();
});
it('should be able to use menu-right style', async () => {
const wrapper = createWrapper(`<div><dropdown menu-right>
<btn class="dropdown-toggle">Menu-Right <span class="caret"></span></btn>
<template #dropdown>
<li><a role="button">Action</a></li>
<li><a role="button">Another action</a></li>
<li><a role="button">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a role="button">Separated link</a></li>
</template>
</dropdown></div>`);
await nextTick();
const menuRight = wrapper.find('.dropdown');
expect(menuRight.find('.dropdown-menu').classes()).toContain(
'dropdown-menu-right'
);
});
it('should be able to open dropdown append to body & menu-right on trigger click', async () => {
const wrapper = appendToBodyVm();
const dropdown = wrapper.findAll('.dropdown')[1];
const trigger = dropdown.find('button');
expect(dropdown.classes()).not.toContain('open');
expect(dropdown.findAll('.dropdown-menu-right').length).toEqual(1);
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).toContain('open');
expect(
document.querySelectorAll('body > .dropdown-menu-right').length
).toEqual(1);
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).not.toContain('open');
expect(dropdown.find('.dropdown-menu-right')).toBeDefined();
});
it('should be able to open dropdown append to body & dropup on trigger click', async () => {
const wrapper = appendToBodyVm();
const dropdown = wrapper.find('.dropup');
const trigger = dropdown.find('button');
expect(dropdown.classes()).not.toContain('open');
expect(dropdown.findAll('.dropdown-menu').length).toEqual(1);
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).toContain('open');
expect(document.querySelectorAll('body>.dropdown-menu').length).toEqual(1);
await triggerEvent(trigger, 'click');
expect(dropdown.classes()).not.toContain('open');
expect(dropdown.find('.dropdown-menu')).toBeDefined();
});
it('should be able to open dropdown on init', async () => {
const wrapper = createWrapper(
'<dropdown v-model="show"><button class="btn btn-default dropdown-toggle" type="button"><span>Dropdown 1</span><span class="caret"></span></button><template #dropdown><li><a href="#">Action</a></li></template></dropdown>',
{
show: true,
}
);
await nextTick();
const dropdown = wrapper;
expect(dropdown.classes()).toContain('open');
});
it('should be able to disable dropdown', async () => {
const wrapper = createWrapper(
'<dropdown v-model="show" disabled><button class="btn btn-default dropdown-toggle" type="button"><span>Dropdown 1</span><span class="caret"></span></button><template #dropdown><li><a href="#">Action</a></li></template></dropdown>',
{
show: true,
}
);
await nextTick();
const dropdown = wrapper;
expect(dropdown.classes()).not.toContain('open');
});
it('should be able to init with no trigger', async () => {
const wrapper = createWrapper('<dropdown/>');
await nextTick();
});
});