2020-03-04 15:08:09 +00:00
|
|
|
import Vuex from 'vuex';
|
|
|
|
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
|
|
|
|
2020-05-12 15:10:33 +00:00
|
|
|
import { GlButton, GlLoadingIcon, GlSearchBoxByType, GlLink } from '@gitlab/ui';
|
2020-03-04 15:08:09 +00:00
|
|
|
import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes';
|
2020-05-22 18:08:21 +00:00
|
|
|
import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue';
|
2020-03-04 15:08:09 +00:00
|
|
|
import DropdownContentsLabelsView from '~/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue';
|
2020-05-12 15:10:33 +00:00
|
|
|
import LabelItem from '~/vue_shared/components/sidebar/labels_select_vue/label_item.vue';
|
2020-03-04 15:08:09 +00:00
|
|
|
|
|
|
|
import defaultState from '~/vue_shared/components/sidebar/labels_select_vue/store/state';
|
|
|
|
import mutations from '~/vue_shared/components/sidebar/labels_select_vue/store/mutations';
|
|
|
|
import * as actions from '~/vue_shared/components/sidebar/labels_select_vue/store/actions';
|
|
|
|
import * as getters from '~/vue_shared/components/sidebar/labels_select_vue/store/getters';
|
|
|
|
|
|
|
|
import { mockConfig, mockLabels, mockRegularLabel } from './mock_data';
|
|
|
|
|
|
|
|
const localVue = createLocalVue();
|
|
|
|
localVue.use(Vuex);
|
|
|
|
|
|
|
|
describe('DropdownContentsLabelsView', () => {
|
|
|
|
let wrapper;
|
|
|
|
|
2020-07-29 18:09:50 +00:00
|
|
|
const createComponent = (initialState = mockConfig) => {
|
|
|
|
const store = new Vuex.Store({
|
|
|
|
getters,
|
|
|
|
mutations,
|
|
|
|
state: {
|
|
|
|
...defaultState(),
|
|
|
|
footerCreateLabelTitle: 'Create label',
|
|
|
|
footerManageLabelTitle: 'Manage labels',
|
|
|
|
},
|
|
|
|
actions: {
|
|
|
|
...actions,
|
|
|
|
fetchLabels: jest.fn(),
|
|
|
|
},
|
2020-05-05 12:09:31 +00:00
|
|
|
});
|
2020-07-29 18:09:50 +00:00
|
|
|
|
|
|
|
store.dispatch('setInitialState', initialState);
|
|
|
|
store.dispatch('receiveLabelsSuccess', mockLabels);
|
|
|
|
|
|
|
|
wrapper = shallowMount(DropdownContentsLabelsView, {
|
|
|
|
localVue,
|
|
|
|
store,
|
2020-07-15 21:09:26 +00:00
|
|
|
});
|
2020-07-29 18:09:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent();
|
2020-03-04 15:08:09 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
wrapper.destroy();
|
2020-07-29 18:09:50 +00:00
|
|
|
wrapper = null;
|
2020-03-04 15:08:09 +00:00
|
|
|
});
|
|
|
|
|
2020-07-29 18:09:50 +00:00
|
|
|
const findDropdownContent = () => wrapper.find('[data-testid="dropdown-content"]');
|
|
|
|
const findDropdownTitle = () => wrapper.find('[data-testid="dropdown-title"]');
|
|
|
|
const findDropdownFooter = () => wrapper.find('[data-testid="dropdown-footer"]');
|
|
|
|
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
|
|
|
|
|
2020-03-04 15:08:09 +00:00
|
|
|
describe('computed', () => {
|
|
|
|
describe('visibleLabels', () => {
|
|
|
|
it('returns matching labels filtered with `searchKey`', () => {
|
|
|
|
wrapper.setData({
|
|
|
|
searchKey: 'bug',
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(wrapper.vm.visibleLabels.length).toBe(1);
|
|
|
|
expect(wrapper.vm.visibleLabels[0].title).toBe('Bug');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns all labels when `searchKey` is empty', () => {
|
|
|
|
wrapper.setData({
|
|
|
|
searchKey: '',
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(wrapper.vm.visibleLabels.length).toBe(mockLabels.length);
|
|
|
|
});
|
|
|
|
});
|
2020-07-29 18:09:50 +00:00
|
|
|
|
|
|
|
describe('showListContainer', () => {
|
|
|
|
it.each`
|
|
|
|
variant | loading | showList
|
|
|
|
${'sidebar'} | ${false} | ${true}
|
|
|
|
${'sidebar'} | ${true} | ${false}
|
|
|
|
${'not-sidebar'} | ${true} | ${true}
|
|
|
|
${'not-sidebar'} | ${false} | ${true}
|
|
|
|
`(
|
|
|
|
'returns $showList if `state.variant` is "$variant" and `labelsFetchInProgress` is $loading',
|
|
|
|
({ variant, loading, showList }) => {
|
|
|
|
createComponent({ ...mockConfig, variant });
|
|
|
|
wrapper.vm.$store.state.labelsFetchInProgress = loading;
|
|
|
|
|
|
|
|
expect(wrapper.vm.showListContainer).toBe(showList);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
});
|
2020-03-04 15:08:09 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
describe('methods', () => {
|
|
|
|
describe('isLabelSelected', () => {
|
|
|
|
it('returns true when provided `label` param is one of the selected labels', () => {
|
|
|
|
expect(wrapper.vm.isLabelSelected(mockRegularLabel)).toBe(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns false when provided `label` param is not one of the selected labels', () => {
|
|
|
|
expect(wrapper.vm.isLabelSelected(mockLabels[2])).toBe(false);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('handleKeyDown', () => {
|
|
|
|
it('decreases `currentHighlightItem` value by 1 when Up arrow key is pressed', () => {
|
|
|
|
wrapper.setData({
|
|
|
|
currentHighlightItem: 1,
|
|
|
|
});
|
|
|
|
|
|
|
|
wrapper.vm.handleKeyDown({
|
|
|
|
keyCode: UP_KEY_CODE,
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(wrapper.vm.currentHighlightItem).toBe(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('increases `currentHighlightItem` value by 1 when Down arrow key is pressed', () => {
|
|
|
|
wrapper.setData({
|
|
|
|
currentHighlightItem: 1,
|
|
|
|
});
|
|
|
|
|
|
|
|
wrapper.vm.handleKeyDown({
|
|
|
|
keyCode: DOWN_KEY_CODE,
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(wrapper.vm.currentHighlightItem).toBe(2);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('calls action `updateSelectedLabels` with currently highlighted label when Enter key is pressed', () => {
|
|
|
|
jest.spyOn(wrapper.vm, 'updateSelectedLabels').mockImplementation();
|
|
|
|
wrapper.setData({
|
|
|
|
currentHighlightItem: 1,
|
|
|
|
});
|
|
|
|
|
|
|
|
wrapper.vm.handleKeyDown({
|
|
|
|
keyCode: ENTER_KEY_CODE,
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(wrapper.vm.updateSelectedLabels).toHaveBeenCalledWith([
|
|
|
|
{
|
|
|
|
...mockLabels[1],
|
|
|
|
set: true,
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('calls action `toggleDropdownContents` when Esc key is pressed', () => {
|
|
|
|
jest.spyOn(wrapper.vm, 'toggleDropdownContents').mockImplementation();
|
|
|
|
wrapper.setData({
|
|
|
|
currentHighlightItem: 1,
|
|
|
|
});
|
|
|
|
|
|
|
|
wrapper.vm.handleKeyDown({
|
|
|
|
keyCode: ESC_KEY_CODE,
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(wrapper.vm.toggleDropdownContents).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('calls action `scrollIntoViewIfNeeded` in next tick when any key is pressed', () => {
|
|
|
|
jest.spyOn(wrapper.vm, 'scrollIntoViewIfNeeded').mockImplementation();
|
|
|
|
wrapper.setData({
|
|
|
|
currentHighlightItem: 1,
|
|
|
|
});
|
|
|
|
|
|
|
|
wrapper.vm.handleKeyDown({
|
|
|
|
keyCode: DOWN_KEY_CODE,
|
|
|
|
});
|
|
|
|
|
|
|
|
return wrapper.vm.$nextTick(() => {
|
|
|
|
expect(wrapper.vm.scrollIntoViewIfNeeded).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('handleLabelClick', () => {
|
2020-05-05 12:09:31 +00:00
|
|
|
beforeEach(() => {
|
2020-03-04 15:08:09 +00:00
|
|
|
jest.spyOn(wrapper.vm, 'updateSelectedLabels').mockImplementation();
|
2020-05-05 12:09:31 +00:00
|
|
|
});
|
2020-03-04 15:08:09 +00:00
|
|
|
|
2020-05-05 12:09:31 +00:00
|
|
|
it('calls action `updateSelectedLabels` with provided `label` param', () => {
|
2020-03-04 15:08:09 +00:00
|
|
|
wrapper.vm.handleLabelClick(mockRegularLabel);
|
|
|
|
|
|
|
|
expect(wrapper.vm.updateSelectedLabels).toHaveBeenCalledWith([mockRegularLabel]);
|
|
|
|
});
|
2020-05-05 12:09:31 +00:00
|
|
|
|
|
|
|
it('calls action `toggleDropdownContents` when `state.allowMultiselect` is false', () => {
|
|
|
|
jest.spyOn(wrapper.vm, 'toggleDropdownContents');
|
|
|
|
wrapper.vm.$store.state.allowMultiselect = false;
|
|
|
|
|
|
|
|
wrapper.vm.handleLabelClick(mockRegularLabel);
|
|
|
|
|
|
|
|
expect(wrapper.vm.toggleDropdownContents).toHaveBeenCalled();
|
|
|
|
});
|
2020-03-04 15:08:09 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('template', () => {
|
|
|
|
it('renders component container element with class `labels-select-contents-list`', () => {
|
|
|
|
expect(wrapper.attributes('class')).toContain('labels-select-contents-list');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('renders gl-loading-icon component when `labelsFetchInProgress` prop is true', () => {
|
|
|
|
wrapper.vm.$store.dispatch('requestLabels');
|
|
|
|
|
|
|
|
return wrapper.vm.$nextTick(() => {
|
2020-07-29 18:09:50 +00:00
|
|
|
const loadingIconEl = findLoadingIcon();
|
2020-03-04 15:08:09 +00:00
|
|
|
|
|
|
|
expect(loadingIconEl.exists()).toBe(true);
|
|
|
|
expect(loadingIconEl.attributes('class')).toContain('labels-fetch-loading');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('renders dropdown title element', () => {
|
2020-07-29 18:09:50 +00:00
|
|
|
const titleEl = findDropdownTitle();
|
2020-03-04 15:08:09 +00:00
|
|
|
|
|
|
|
expect(titleEl.exists()).toBe(true);
|
|
|
|
expect(titleEl.text()).toBe('Assign labels');
|
|
|
|
});
|
|
|
|
|
2020-05-05 12:09:31 +00:00
|
|
|
it('does not render dropdown title element when `state.variant` is "standalone"', () => {
|
2020-07-29 18:09:50 +00:00
|
|
|
createComponent({ ...mockConfig, variant: 'standalone' });
|
|
|
|
expect(findDropdownTitle().exists()).toBe(false);
|
2020-05-05 12:09:31 +00:00
|
|
|
});
|
|
|
|
|
2020-07-15 21:09:26 +00:00
|
|
|
it('renders dropdown title element when `state.variant` is "embedded"', () => {
|
2020-07-29 18:09:50 +00:00
|
|
|
createComponent({ ...mockConfig, variant: 'embedded' });
|
|
|
|
expect(findDropdownTitle().exists()).toBe(true);
|
2020-07-15 21:09:26 +00:00
|
|
|
});
|
|
|
|
|
2020-03-04 15:08:09 +00:00
|
|
|
it('renders dropdown close button element', () => {
|
2020-07-29 18:09:50 +00:00
|
|
|
const closeButtonEl = findDropdownTitle().find(GlButton);
|
2020-03-04 15:08:09 +00:00
|
|
|
|
|
|
|
expect(closeButtonEl.exists()).toBe(true);
|
2020-05-05 12:09:31 +00:00
|
|
|
expect(closeButtonEl.props('icon')).toBe('close');
|
2020-03-04 15:08:09 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('renders label search input element', () => {
|
|
|
|
const searchInputEl = wrapper.find(GlSearchBoxByType);
|
|
|
|
|
|
|
|
expect(searchInputEl.exists()).toBe(true);
|
|
|
|
expect(searchInputEl.attributes('autofocus')).toBe('true');
|
|
|
|
});
|
|
|
|
|
2020-05-22 18:08:21 +00:00
|
|
|
it('renders smart-virtual-list element', () => {
|
|
|
|
expect(wrapper.find(SmartVirtualList).exists()).toBe(true);
|
|
|
|
});
|
|
|
|
|
2020-03-04 15:08:09 +00:00
|
|
|
it('renders label elements for all labels', () => {
|
2020-05-12 15:10:33 +00:00
|
|
|
expect(wrapper.findAll(LabelItem)).toHaveLength(mockLabels.length);
|
2020-03-04 15:08:09 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('renders label element with "is-focused" when value of `currentHighlightItem` is more than -1', () => {
|
|
|
|
wrapper.setData({
|
|
|
|
currentHighlightItem: 0,
|
|
|
|
});
|
|
|
|
|
|
|
|
return wrapper.vm.$nextTick(() => {
|
2020-07-29 18:09:50 +00:00
|
|
|
const labelItemEl = findDropdownContent().find(LabelItem);
|
2020-03-04 15:08:09 +00:00
|
|
|
|
2020-05-12 15:10:33 +00:00
|
|
|
expect(labelItemEl.props('highlight')).toBe(true);
|
2020-03-04 15:08:09 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('renders element containing "No matching results" when `searchKey` does not match with any label', () => {
|
|
|
|
wrapper.setData({
|
|
|
|
searchKey: 'abc',
|
|
|
|
});
|
|
|
|
|
|
|
|
return wrapper.vm.$nextTick(() => {
|
2020-07-29 18:09:50 +00:00
|
|
|
const noMatchEl = findDropdownContent().find('li');
|
2020-03-04 15:08:09 +00:00
|
|
|
|
2020-05-12 15:10:33 +00:00
|
|
|
expect(noMatchEl.isVisible()).toBe(true);
|
2020-03-04 15:08:09 +00:00
|
|
|
expect(noMatchEl.text()).toContain('No matching results');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2020-07-29 18:09:50 +00:00
|
|
|
it('renders empty content while loading', () => {
|
|
|
|
wrapper.vm.$store.state.labelsFetchInProgress = true;
|
|
|
|
|
|
|
|
return wrapper.vm.$nextTick(() => {
|
|
|
|
const dropdownContent = findDropdownContent();
|
|
|
|
|
|
|
|
expect(dropdownContent.exists()).toBe(true);
|
|
|
|
expect(dropdownContent.isVisible()).toBe(false);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2020-03-04 15:08:09 +00:00
|
|
|
it('renders footer list items', () => {
|
2020-07-29 18:09:50 +00:00
|
|
|
const footerLinks = findDropdownFooter().findAll(GlLink);
|
|
|
|
const createLabelLink = footerLinks.at(0);
|
|
|
|
const manageLabelsLink = footerLinks.at(1);
|
2020-05-05 12:09:31 +00:00
|
|
|
|
|
|
|
expect(createLabelLink.exists()).toBe(true);
|
|
|
|
expect(createLabelLink.text()).toBe('Create label');
|
2020-03-04 15:08:09 +00:00
|
|
|
expect(manageLabelsLink.exists()).toBe(true);
|
|
|
|
expect(manageLabelsLink.text()).toBe('Manage labels');
|
|
|
|
});
|
2020-05-05 12:09:31 +00:00
|
|
|
|
|
|
|
it('does not render "Create label" footer link when `state.allowLabelCreate` is `false`', () => {
|
|
|
|
wrapper.vm.$store.state.allowLabelCreate = false;
|
|
|
|
|
|
|
|
return wrapper.vm.$nextTick(() => {
|
2020-07-29 18:09:50 +00:00
|
|
|
const createLabelLink = findDropdownFooter()
|
2020-05-05 12:09:31 +00:00
|
|
|
.findAll(GlLink)
|
|
|
|
.at(0);
|
|
|
|
|
|
|
|
expect(createLabelLink.text()).not.toBe('Create label');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('does not render footer list items when `state.variant` is "standalone"', () => {
|
2020-07-29 18:09:50 +00:00
|
|
|
createComponent({ ...mockConfig, variant: 'standalone' });
|
|
|
|
expect(findDropdownFooter().exists()).toBe(false);
|
2020-05-05 12:09:31 +00:00
|
|
|
});
|
2020-07-15 21:09:26 +00:00
|
|
|
|
|
|
|
it('renders footer list items when `state.variant` is "embedded"', () => {
|
2020-07-29 18:09:50 +00:00
|
|
|
expect(findDropdownFooter().exists()).toBe(true);
|
2020-07-15 21:09:26 +00:00
|
|
|
});
|
2020-03-04 15:08:09 +00:00
|
|
|
});
|
|
|
|
});
|