Commit 92b40a04 authored by Miguel Rincon's avatar Miguel Rincon

Merge branch 'justin_ho-remove-legacy-mount-component-helper-in-sidebar' into 'master'

Replace `mountComponent` helper in `vue_shared/components/sidebar` specs

See merge request gitlab-org/gitlab!73459
parents 245b3021 ad8017de
...@@ -40,7 +40,7 @@ export default { ...@@ -40,7 +40,7 @@ export default {
</script> </script>
<template> <template>
<div v-gl-tooltip.left.viewport :class="containerClass" :title="tooltipText" @click="click"> <div v-gl-tooltip.left.viewport="tooltipText" :class="containerClass" @click="click">
<gl-icon v-if="showIcon" name="calendar" /> <gl-icon v-if="showIcon" name="calendar" />
<slot> <slot>
<span> {{ text }} </span> <span> {{ text }} </span>
......
...@@ -43,12 +43,7 @@ export default { ...@@ -43,12 +43,7 @@ export default {
</script> </script>
<template> <template>
<div <div v-gl-tooltip.left.viewport="labelsList" class="sidebar-collapsed-icon" @click="handleClick">
v-gl-tooltip.left.viewport
:title="labelsList"
class="sidebar-collapsed-icon"
@click="handleClick"
>
<gl-icon name="labels" /> <gl-icon name="labels" />
<span>{{ labels.length }}</span> <span>{{ labels.length }}</span>
</div> </div>
......
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import mountComponent from 'helpers/vue_mount_component_helper'; import { GlIcon } from '@gitlab/ui';
import collapsedCalendarIcon from '~/vue_shared/components/sidebar/collapsed_calendar_icon.vue'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
describe('collapsedCalendarIcon', () => { import CollapsedCalendarIcon from '~/vue_shared/components/sidebar/collapsed_calendar_icon.vue';
let vm;
beforeEach(() => { describe('CollapsedCalendarIcon', () => {
const CollapsedCalendarIcon = Vue.extend(collapsedCalendarIcon); let wrapper;
vm = mountComponent(CollapsedCalendarIcon, {
containerClass: 'test-class', const defaultProps = {
text: 'text', containerClass: 'test-class',
showIcon: false, text: 'text',
tooltipText: 'tooltip text',
showIcon: false,
};
const createComponent = ({ props = {} } = {}) => {
wrapper = shallowMount(CollapsedCalendarIcon, {
propsData: { ...defaultProps, ...props },
directives: {
GlTooltip: createMockDirective(),
},
}); });
};
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
}); });
it('should add class to container', () => { const findGlIcon = () => wrapper.findComponent(GlIcon);
expect(vm.$el.classList.contains('test-class')).toEqual(true); const getTooltip = () => getBinding(wrapper.element, 'gl-tooltip');
it('adds class to container', () => {
expect(wrapper.classes()).toContain(defaultProps.containerClass);
});
it('does not render calendar icon when showIcon is false', () => {
expect(findGlIcon().exists()).toBe(false);
});
it('renders calendar icon when showIcon is true', () => {
createComponent({
props: { showIcon: true },
});
expect(findGlIcon().exists()).toBe(true);
}); });
it('should hide calendar icon if showIcon', () => { it('renders text', () => {
expect(vm.$el.querySelector('[data-testid="calendar-icon"]')).toBeNull(); expect(wrapper.text()).toBe(defaultProps.text);
}); });
it('should render text', () => { it('renders tooltipText as tooltip', () => {
expect(vm.$el.querySelector('span').innerText.trim()).toEqual('text'); expect(getTooltip().value).toBe(defaultProps.tooltipText);
}); });
it('should emit click event when container is clicked', () => { it('emits click event when container is clicked', async () => {
const click = jest.fn(); wrapper.trigger('click');
vm.$on('click', click);
vm.$el.click(); await wrapper.vm.$nextTick();
expect(click).toHaveBeenCalled(); expect(wrapper.emitted('click')[0]).toBeDefined();
}); });
}); });
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import mountComponent from 'helpers/vue_mount_component_helper';
import collapsedGroupedDatePicker from '~/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue'; import CollapsedGroupedDatePicker from '~/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue';
import CollapsedCalendarIcon from '~/vue_shared/components/sidebar/collapsed_calendar_icon.vue';
describe('collapsedGroupedDatePicker', () => {
let vm; describe('CollapsedGroupedDatePicker', () => {
beforeEach(() => { let wrapper;
const CollapsedGroupedDatePicker = Vue.extend(collapsedGroupedDatePicker);
vm = mountComponent(CollapsedGroupedDatePicker, { const defaultProps = {
showToggleSidebar: true, showToggleSidebar: true,
};
const minDate = new Date('07/17/2016');
const maxDate = new Date('07/17/2017');
const createComponent = ({ props = {} } = {}) => {
wrapper = shallowMount(CollapsedGroupedDatePicker, {
propsData: { ...defaultProps, ...props },
}); });
};
afterEach(() => {
wrapper.destroy();
}); });
describe('toggleCollapse events', () => { const findCollapsedCalendarIcon = () => wrapper.findComponent(CollapsedCalendarIcon);
beforeEach((done) => { const findAllCollapsedCalendarIcons = () => wrapper.findAllComponents(CollapsedCalendarIcon);
jest.spyOn(vm, 'toggleSidebar').mockImplementation(() => {});
vm.minDate = new Date('07/17/2016');
Vue.nextTick(done);
});
describe('toggleCollapse events', () => {
it('should emit when collapsed-calendar-icon is clicked', () => { it('should emit when collapsed-calendar-icon is clicked', () => {
vm.$el.querySelector('.sidebar-collapsed-icon').click(); createComponent();
expect(vm.toggleSidebar).toHaveBeenCalled(); findCollapsedCalendarIcon().trigger('click');
expect(wrapper.emitted('toggleCollapse')[0]).toBeDefined();
}); });
}); });
describe('minDate and maxDate', () => { describe('minDate and maxDate', () => {
beforeEach((done) => {
vm.minDate = new Date('07/17/2016');
vm.maxDate = new Date('07/17/2017');
Vue.nextTick(done);
});
it('should render both collapsed-calendar-icon', () => { it('should render both collapsed-calendar-icon', () => {
const icons = vm.$el.querySelectorAll('.sidebar-collapsed-icon'); createComponent({
props: {
expect(icons.length).toEqual(2); minDate,
expect(icons[0].innerText.trim()).toEqual('Jul 17 2016'); maxDate,
expect(icons[1].innerText.trim()).toEqual('Jul 17 2017'); },
});
const icons = findAllCollapsedCalendarIcons();
expect(icons.length).toBe(2);
expect(icons.at(0).text()).toBe('Jul 17 2016');
expect(icons.at(1).text()).toBe('Jul 17 2017');
}); });
}); });
describe('minDate', () => { describe('minDate', () => {
beforeEach((done) => {
vm.minDate = new Date('07/17/2016');
Vue.nextTick(done);
});
it('should render minDate in collapsed-calendar-icon', () => { it('should render minDate in collapsed-calendar-icon', () => {
const icons = vm.$el.querySelectorAll('.sidebar-collapsed-icon'); createComponent({
props: {
minDate,
},
});
const icons = findAllCollapsedCalendarIcons();
expect(icons.length).toEqual(1); expect(icons.length).toBe(1);
expect(icons[0].innerText.trim()).toEqual('From Jul 17 2016'); expect(icons.at(0).text()).toBe('From Jul 17 2016');
}); });
}); });
describe('maxDate', () => { describe('maxDate', () => {
beforeEach((done) => {
vm.maxDate = new Date('07/17/2017');
Vue.nextTick(done);
});
it('should render maxDate in collapsed-calendar-icon', () => { it('should render maxDate in collapsed-calendar-icon', () => {
const icons = vm.$el.querySelectorAll('.sidebar-collapsed-icon'); createComponent({
props: {
expect(icons.length).toEqual(1); maxDate,
expect(icons[0].innerText.trim()).toEqual('Until Jul 17 2017'); },
});
const icons = findAllCollapsedCalendarIcons();
expect(icons.length).toBe(1);
expect(icons.at(0).text()).toBe('Until Jul 17 2017');
}); });
}); });
describe('no dates', () => { describe('no dates', () => {
beforeEach(() => {
createComponent();
});
it('should render None', () => { it('should render None', () => {
const icons = vm.$el.querySelectorAll('.sidebar-collapsed-icon'); const icons = findAllCollapsedCalendarIcons();
expect(icons.length).toEqual(1); expect(icons.length).toBe(1);
expect(icons[0].innerText.trim()).toEqual('None'); expect(icons.at(0).text()).toBe('None');
}); });
it('should have tooltip as `Start and due date`', () => { it('should have tooltip as `Start and due date`', () => {
const icons = vm.$el.querySelectorAll('.sidebar-collapsed-icon'); const icons = findAllCollapsedCalendarIcons();
expect(icons[0].title).toBe('Start and due date'); expect(icons.at(0).props('tooltipText')).toBe('Start and due date');
}); });
}); });
}); });
import { GlLoadingIcon } from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import DatePicker from '~/vue_shared/components/pikaday.vue'; import DatePicker from '~/vue_shared/components/pikaday.vue';
import SidebarDatePicker from '~/vue_shared/components/sidebar/date_picker.vue'; import SidebarDatePicker from '~/vue_shared/components/sidebar/date_picker.vue';
...@@ -5,14 +6,8 @@ import SidebarDatePicker from '~/vue_shared/components/sidebar/date_picker.vue'; ...@@ -5,14 +6,8 @@ import SidebarDatePicker from '~/vue_shared/components/sidebar/date_picker.vue';
describe('SidebarDatePicker', () => { describe('SidebarDatePicker', () => {
let wrapper; let wrapper;
const mountComponent = (propsData = {}, data = {}) => { const createComponent = (propsData = {}, data = {}) => {
if (wrapper) {
throw new Error('tried to call mountComponent without d');
}
wrapper = mount(SidebarDatePicker, { wrapper = mount(SidebarDatePicker, {
stubs: {
DatePicker: true,
},
propsData, propsData,
data: () => data, data: () => data,
}); });
...@@ -20,87 +15,93 @@ describe('SidebarDatePicker', () => { ...@@ -20,87 +15,93 @@ describe('SidebarDatePicker', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
}); });
const findDatePicker = () => wrapper.findComponent(DatePicker);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findEditButton = () => wrapper.find('.title .btn-blank');
const findRemoveButton = () => wrapper.find('.value-content .btn-blank');
const findSidebarToggle = () => wrapper.find('.title .gutter-toggle');
const findValueContent = () => wrapper.find('.value-content');
it('should emit toggleCollapse when collapsed toggle sidebar is clicked', () => { it('should emit toggleCollapse when collapsed toggle sidebar is clicked', () => {
mountComponent(); createComponent();
wrapper.find('.issuable-sidebar-header .gutter-toggle').element.click(); wrapper.find('.issuable-sidebar-header .gutter-toggle').trigger('click');
expect(wrapper.emitted('toggleCollapse')).toEqual([[]]); expect(wrapper.emitted('toggleCollapse')).toEqual([[]]);
}); });
it('should render collapsed-calendar-icon', () => { it('should render collapsed-calendar-icon', () => {
mountComponent(); createComponent();
expect(wrapper.find('.sidebar-collapsed-icon').element).toBeDefined(); expect(wrapper.find('.sidebar-collapsed-icon').exists()).toBe(true);
}); });
it('should render value when not editing', () => { it('should render value when not editing', () => {
mountComponent(); createComponent();
expect(wrapper.find('.value-content').element).toBeDefined(); expect(findValueContent().exists()).toBe(true);
}); });
it('should render None if there is no selectedDate', () => { it('should render None if there is no selectedDate', () => {
mountComponent(); createComponent();
expect(wrapper.find('.value-content span').text().trim()).toEqual('None'); expect(findValueContent().text()).toBe('None');
}); });
it('should render date-picker when editing', () => { it('should render date-picker when editing', () => {
mountComponent({}, { editing: true }); createComponent({}, { editing: true });
expect(wrapper.find(DatePicker).element).toBeDefined(); expect(findDatePicker().exists()).toBe(true);
}); });
it('should render label', () => { it('should render label', () => {
const label = 'label'; const label = 'label';
mountComponent({ label }); createComponent({ label });
expect(wrapper.find('.title').text().trim()).toEqual(label); expect(wrapper.find('.title').text()).toBe(label);
}); });
it('should render loading-icon when isLoading', () => { it('should render loading-icon when isLoading', () => {
mountComponent({ isLoading: true }); createComponent({ isLoading: true });
expect(wrapper.find('.gl-spinner').element).toBeDefined(); expect(findLoadingIcon().exists()).toBe(true);
}); });
describe('editable', () => { describe('editable', () => {
beforeEach(() => { beforeEach(() => {
mountComponent({ editable: true }); createComponent({ editable: true });
}); });
it('should render edit button', () => { it('should render edit button', () => {
expect(wrapper.find('.title .btn-blank').text().trim()).toEqual('Edit'); expect(findEditButton().text()).toBe('Edit');
}); });
it('should enable editing when edit button is clicked', async () => { it('should enable editing when edit button is clicked', async () => {
wrapper.find('.title .btn-blank').element.click(); findEditButton().trigger('click');
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
expect(wrapper.vm.editing).toEqual(true); expect(wrapper.vm.editing).toBe(true);
}); });
}); });
it('should render date if selectedDate', () => { it('should render date if selectedDate', () => {
mountComponent({ selectedDate: new Date('07/07/2017') }); createComponent({ selectedDate: new Date('07/07/2017') });
expect(wrapper.find('.value-content strong').text().trim()).toEqual('Jul 7, 2017'); expect(wrapper.find('.value-content strong').text()).toBe('Jul 7, 2017');
}); });
describe('selectedDate and editable', () => { describe('selectedDate and editable', () => {
beforeEach(() => { beforeEach(() => {
mountComponent({ selectedDate: new Date('07/07/2017'), editable: true }); createComponent({ selectedDate: new Date('07/07/2017'), editable: true });
}); });
it('should render remove button if selectedDate and editable', () => { it('should render remove button if selectedDate and editable', () => {
expect(wrapper.find('.value-content .btn-blank').text().trim()).toEqual('remove'); expect(findRemoveButton().text()).toBe('remove');
}); });
it('should emit saveDate with null when remove button is clicked', () => { it('should emit saveDate with null when remove button is clicked', () => {
wrapper.find('.value-content .btn-blank').element.click(); findRemoveButton().trigger('click');
expect(wrapper.emitted('saveDate')).toEqual([[null]]); expect(wrapper.emitted('saveDate')).toEqual([[null]]);
}); });
...@@ -108,15 +109,15 @@ describe('SidebarDatePicker', () => { ...@@ -108,15 +109,15 @@ describe('SidebarDatePicker', () => {
describe('showToggleSidebar', () => { describe('showToggleSidebar', () => {
beforeEach(() => { beforeEach(() => {
mountComponent({ showToggleSidebar: true }); createComponent({ showToggleSidebar: true });
}); });
it('should render toggle-sidebar when showToggleSidebar', () => { it('should render toggle-sidebar when showToggleSidebar', () => {
expect(wrapper.find('.title .gutter-toggle').element).toBeDefined(); expect(findSidebarToggle().exists()).toBe(true);
}); });
it('should emit toggleCollapse when toggle sidebar is clicked', () => { it('should emit toggleCollapse when toggle sidebar is clicked', () => {
wrapper.find('.title .gutter-toggle').element.click(); findSidebarToggle().trigger('click');
expect(wrapper.emitted('toggleCollapse')).toEqual([[]]); expect(wrapper.emitted('toggleCollapse')).toEqual([[]]);
}); });
......
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import { GlIcon } from '@gitlab/ui';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import DropdownValueCollapsedComponent from '~/vue_shared/components/sidebar/labels_select_vue/dropdown_value_collapsed.vue';
import mountComponent from 'helpers/vue_mount_component_helper'; import { mockCollapsedLabels as mockLabels, mockRegularLabel } from './mock_data';
import dropdownValueCollapsedComponent from '~/vue_shared/components/sidebar/labels_select_vue/dropdown_value_collapsed.vue';
import { mockCollapsedLabels as mockLabels } from './mock_data'; describe('DropdownValueCollapsedComponent', () => {
let wrapper;
const createComponent = (labels = mockLabels) => {
const Component = Vue.extend(dropdownValueCollapsedComponent);
return mountComponent(Component, { const defaultProps = {
labels, labels: [],
}); };
};
describe('DropdownValueCollapsedComponent', () => { const mockManyLabels = [...mockLabels, ...mockLabels, ...mockLabels];
let vm;
beforeEach(() => { const createComponent = ({ props = {} } = {}) => {
vm = createComponent(); wrapper = shallowMount(DropdownValueCollapsedComponent, {
}); propsData: { ...defaultProps, ...props },
directives: {
GlTooltip: createMockDirective(),
},
});
};
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
}); });
describe('computed', () => { const findGlIcon = () => wrapper.findComponent(GlIcon);
describe('labelsList', () => { const getTooltip = () => getBinding(wrapper.element, 'gl-tooltip');
it('returns default text when `labels` prop is empty array', () => {
const vmEmptyLabels = createComponent([]);
expect(vmEmptyLabels.labelsList).toBe('Labels'); describe('template', () => {
vmEmptyLabels.$destroy(); it('renders tags icon element', () => {
}); createComponent();
it('returns labels names separated by coma when `labels` prop has more than one item', () => {
const labels = mockLabels.concat(mockLabels);
const vmMoreLabels = createComponent(labels);
const expectedText = labels.map((label) => label.title).join(', '); expect(findGlIcon().exists()).toBe(true);
});
expect(vmMoreLabels.labelsList).toBe(expectedText); it('emits onValueClick event on click', async () => {
vmMoreLabels.$destroy(); createComponent();
});
it('returns labels names separated by coma with remaining labels count and `and more` phrase when `labels` prop has more than five items', () => { wrapper.trigger('click');
const mockMoreLabels = Object.assign([], mockLabels);
for (let i = 0; i < 6; i += 1) {
mockMoreLabels.unshift(mockLabels[0]);
}
const vmMoreLabels = createComponent(mockMoreLabels); await wrapper.vm.$nextTick();
const expectedText = `${mockMoreLabels expect(wrapper.emitted('onValueClick')[0]).toBeDefined();
.slice(0, 5) });
.map((label) => label.title)
.join(', ')}, and ${mockMoreLabels.length - 5} more`;
expect(vmMoreLabels.labelsList).toBe(expectedText); describe.each`
vmMoreLabels.$destroy(); scenario | labels | expectedResult | expectedText
${'`labels` is empty'} | ${[]} | ${'default text'} | ${'Labels'}
${'`labels` has 1 item'} | ${[mockRegularLabel]} | ${'label name'} | ${'Foo Label'}
${'`labels` has 2 items'} | ${mockLabels} | ${'comma separated label names'} | ${'Foo Label, Foo::Bar'}
${'`labels` has more than 5 items'} | ${mockManyLabels} | ${'comma separated label names with "and more" phrase'} | ${'Foo Label, Foo::Bar, Foo Label, Foo::Bar, Foo Label, and 1 more'}
`('when $scenario', ({ labels, expectedResult, expectedText }) => {
beforeEach(() => {
createComponent({
props: {
labels,
},
});
}); });
it('returns first label name when `labels` prop has only one item present', () => { it('renders labels count', () => {
const text = mockLabels.map((label) => label.title).join(', '); expect(wrapper.text()).toBe(`${labels.length}`);
expect(vm.labelsList).toBe(text);
}); });
});
});
describe('methods', () => {
describe('handleClick', () => {
it('emits onValueClick event on component', () => {
jest.spyOn(vm, '$emit').mockImplementation(() => {});
vm.handleClick();
expect(vm.$emit).toHaveBeenCalledWith('onValueClick'); it(`renders "${expectedResult}" as tooltip`, () => {
expect(getTooltip().value).toBe(expectedText);
}); });
}); });
}); });
describe('template', () => {
it('renders component container element with tooltip`', () => {
expect(vm.$el.title).toBe(vm.labelsList);
});
it('renders tags icon element', () => {
expect(vm.$el.querySelector('[data-testid="labels-icon"]')).not.toBeNull();
});
it('renders labels count', () => {
expect(vm.$el.querySelector('span').innerText.trim()).toBe(`${vm.labels.length}`);
});
});
}); });
import Vue from 'vue'; import { GlButton } from '@gitlab/ui';
import mountComponent from 'helpers/vue_mount_component_helper'; import { mount, shallowMount } from '@vue/test-utils';
import toggleSidebar from '~/vue_shared/components/sidebar/toggle_sidebar.vue';
import ToggleSidebar from '~/vue_shared/components/sidebar/toggle_sidebar.vue';
describe('toggleSidebar', () => {
let vm; describe('ToggleSidebar', () => {
beforeEach(() => { let wrapper;
const ToggleSidebar = Vue.extend(toggleSidebar);
vm = mountComponent(ToggleSidebar, { const defaultProps = {
collapsed: true, collapsed: true,
};
const createComponent = ({ mountFn = shallowMount, props = {} } = {}) => {
wrapper = mountFn(ToggleSidebar, {
propsData: { ...defaultProps, ...props },
}); });
};
afterEach(() => {
wrapper.destroy();
}); });
const findGlButton = () => wrapper.findComponent(GlButton);
it('should render the "chevron-double-lg-left" icon when collapsed', () => { it('should render the "chevron-double-lg-left" icon when collapsed', () => {
expect(vm.$el.querySelector('[data-testid="chevron-double-lg-left-icon"]')).not.toBeNull(); createComponent();
expect(findGlButton().props('icon')).toBe('chevron-double-lg-left');
}); });
it('should render the "chevron-double-lg-right" icon when expanded', async () => { it('should render the "chevron-double-lg-right" icon when expanded', async () => {
vm.collapsed = false; createComponent({ props: { collapsed: false } });
await Vue.nextTick();
expect(vm.$el.querySelector('[data-testid="chevron-double-lg-right-icon"]')).not.toBeNull(); expect(findGlButton().props('icon')).toBe('chevron-double-lg-right');
}); });
it('should emit toggle event when button clicked', () => { it('should emit toggle event when button clicked', async () => {
const toggle = jest.fn(); createComponent({ mountFn: mount });
vm.$on('toggle', toggle);
vm.$el.click(); findGlButton().trigger('click');
await wrapper.vm.$nextTick();
expect(toggle).toHaveBeenCalled(); expect(wrapper.emitted('toggle')[0]).toBeDefined();
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment