Commit 627c5447 authored by Illya Klymov's avatar Illya Klymov

Merge branch '220466-convert-jest-tests-to-use-vtu-in-spec-frontend-groups' into 'master'

Convert Jest tests to use VTU in 'spec/frontend/groups'

See merge request gitlab-org/gitlab!43521
parents 73c45fac 7993ea08
...@@ -53,6 +53,7 @@ export default { ...@@ -53,6 +53,7 @@ export default {
:aria-label="leaveBtnTitle" :aria-label="leaveBtnTitle"
data-container="body" data-container="body"
data-placement="bottom" data-placement="bottom"
data-testid="leave-group-btn"
class="leave-group btn btn-xs no-expand gl-text-gray-500 gl-ml-5" class="leave-group btn btn-xs no-expand gl-text-gray-500 gl-ml-5"
@click.prevent="onLeaveGroup" @click.prevent="onLeaveGroup"
> >
...@@ -66,6 +67,7 @@ export default { ...@@ -66,6 +67,7 @@ export default {
:aria-label="editBtnTitle" :aria-label="editBtnTitle"
data-container="body" data-container="body"
data-placement="bottom" data-placement="bottom"
data-testid="edit-group-btn"
class="edit-group btn btn-xs no-expand gl-text-gray-500 gl-ml-5" class="edit-group btn btn-xs no-expand gl-text-gray-500 gl-ml-5"
> >
<gl-icon name="settings" class="position-top-0 align-middle" /> <gl-icon name="settings" class="position-top-0 align-middle" />
......
...@@ -57,6 +57,7 @@ export default { ...@@ -57,6 +57,7 @@ export default {
:title="title" :title="title"
data-container="body" data-container="body"
> >
<gl-icon :name="iconName" /> <span v-if="isValuePresent" class="stat-value"> {{ value }} </span> <gl-icon :name="iconName" />
<span v-if="isValuePresent" class="stat-value" data-testid="itemStatValue"> {{ value }} </span>
</span> </span>
</template> </template>
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import { GlIcon } from '@gitlab/ui';
import mountComponent from 'helpers/vue_mount_component_helper'; import ItemActions from '~/groups/components/item_actions.vue';
import itemActionsComponent from '~/groups/components/item_actions.vue';
import eventHub from '~/groups/event_hub'; import eventHub from '~/groups/event_hub';
import { mockParentGroupItem, mockChildren } from '../mock_data'; import { mockParentGroupItem, mockChildren } from '../mock_data';
const createComponent = (group = mockParentGroupItem, parentGroup = mockChildren[0]) => { describe('ItemActions', () => {
const Component = Vue.extend(itemActionsComponent); let wrapper;
const parentGroup = mockChildren[0];
return mountComponent(Component, { const defaultProps = {
group, group: mockParentGroupItem,
parentGroup, parentGroup,
}); };
};
describe('ItemActionsComponent', () => { const createComponent = (props = {}) => {
let vm; wrapper = shallowMount(ItemActions, {
propsData: { ...defaultProps, ...props },
beforeEach(() => {
vm = createComponent();
}); });
};
afterEach(() => { afterEach(() => {
vm.$destroy(); if (wrapper) {
wrapper.destroy();
wrapper = null;
}
}); });
describe('methods', () => { const findEditGroupBtn = () => wrapper.find('[data-testid="edit-group-btn"]');
describe('onLeaveGroup', () => { const findEditGroupIcon = () => findEditGroupBtn().find(GlIcon);
it('emits `showLeaveGroupModal` event with `group` and `parentGroup` props', () => { const findLeaveGroupBtn = () => wrapper.find('[data-testid="leave-group-btn"]');
jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); const findLeaveGroupIcon = () => findLeaveGroupBtn().find(GlIcon);
vm.onLeaveGroup();
expect(eventHub.$emit).toHaveBeenCalledWith(
'showLeaveGroupModal',
vm.group,
vm.parentGroup,
);
});
});
});
describe('template', () => { describe('template', () => {
it('should render component template correctly', () => { it('renders component template correctly', () => {
expect(vm.$el.classList.contains('controls')).toBeTruthy(); createComponent();
});
it('should render Edit Group button with correct attribute values', () => { expect(wrapper.classes()).toContain('controls');
const group = { ...mockParentGroupItem }; });
group.canEdit = true;
const newVm = createComponent(group);
const editBtn = newVm.$el.querySelector('a.edit-group'); it('renders "Edit group" button with correct attribute values', () => {
const group = {
...mockParentGroupItem,
canEdit: true,
};
createComponent({ group });
expect(findEditGroupBtn().exists()).toBe(true);
expect(findEditGroupBtn().classes()).toContain('no-expand');
expect(findEditGroupBtn().attributes('href')).toBe(group.editPath);
expect(findEditGroupBtn().attributes('aria-label')).toBe('Edit group');
expect(findEditGroupBtn().attributes('data-original-title')).toBe('Edit group');
expect(findEditGroupIcon().exists()).toBe(true);
expect(findEditGroupIcon().props('name')).toBe('settings');
});
expect(editBtn).toBeDefined(); describe('`canLeave` is true', () => {
expect(editBtn.classList.contains('no-expand')).toBeTruthy(); const group = {
expect(editBtn.getAttribute('href')).toBe(group.editPath); ...mockParentGroupItem,
expect(editBtn.getAttribute('aria-label')).toBe('Edit group'); canLeave: true,
expect(editBtn.dataset.originalTitle).toBe('Edit group'); };
expect(editBtn.querySelectorAll('svg').length).not.toBe(0);
expect(editBtn.querySelector('svg').getAttribute('data-testid')).toBe('settings-icon');
newVm.$destroy(); beforeEach(() => {
createComponent({ group });
}); });
it('should render Leave Group button with correct attribute values', () => { it('renders "Leave this group" button with correct attribute values', () => {
const group = { ...mockParentGroupItem }; expect(findLeaveGroupBtn().exists()).toBe(true);
group.canLeave = true; expect(findLeaveGroupBtn().classes()).toContain('no-expand');
const newVm = createComponent(group); expect(findLeaveGroupBtn().attributes('href')).toBe(group.leavePath);
expect(findLeaveGroupBtn().attributes('aria-label')).toBe('Leave this group');
expect(findLeaveGroupBtn().attributes('data-original-title')).toBe('Leave this group');
expect(findLeaveGroupIcon().exists()).toBe(true);
expect(findLeaveGroupIcon().props('name')).toBe('leave');
});
const leaveBtn = newVm.$el.querySelector('a.leave-group'); it('emits event on "Leave this group" button click', () => {
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
expect(leaveBtn).toBeDefined(); findLeaveGroupBtn().trigger('click');
expect(leaveBtn.classList.contains('no-expand')).toBeTruthy();
expect(leaveBtn.getAttribute('href')).toBe(group.leavePath);
expect(leaveBtn.getAttribute('aria-label')).toBe('Leave this group');
expect(leaveBtn.dataset.originalTitle).toBe('Leave this group');
expect(leaveBtn.querySelectorAll('svg').length).not.toBe(0);
expect(leaveBtn.querySelector('svg').getAttribute('data-testid')).toBe('leave-icon');
newVm.$destroy(); expect(eventHub.$emit).toHaveBeenCalledWith('showLeaveGroupModal', group, parentGroup);
});
}); });
}); });
}); });
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import { GlIcon } from '@gitlab/ui';
import ItemCaret from '~/groups/components/item_caret.vue';
import mountComponent from 'helpers/vue_mount_component_helper'; describe('ItemCaret', () => {
import itemCaretComponent from '~/groups/components/item_caret.vue'; let wrapper;
const createComponent = (isGroupOpen = false) => { const defaultProps = {
const Component = Vue.extend(itemCaretComponent); isGroupOpen: false,
};
return mountComponent(Component, { const createComponent = (props = {}) => {
isGroupOpen, wrapper = shallowMount(ItemCaret, {
propsData: { ...defaultProps, ...props },
}); });
}; };
describe('ItemCaretComponent', () => {
let vm;
afterEach(() => { afterEach(() => {
vm.$destroy(); if (wrapper) {
wrapper.destroy();
wrapper = null;
}
}); });
const findAllGlIcons = () => wrapper.findAll(GlIcon);
const findGlIcon = () => wrapper.find(GlIcon);
describe('template', () => { describe('template', () => {
it('should render component template correctly', () => { it('renders component template correctly', () => {
vm = createComponent(); createComponent();
expect(vm.$el.classList.contains('folder-caret')).toBeTruthy();
expect(vm.$el.querySelectorAll('svg').length).toBe(1); expect(wrapper.classes()).toContain('folder-caret');
expect(findAllGlIcons()).toHaveLength(1);
}); });
it('should render caret down icon if `isGroupOpen` prop is `true`', () => { it.each`
vm = createComponent(true); isGroupOpen | icon
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('angle-down-icon'); ${true} | ${'angle-down'}
${false} | ${'angle-right'}
`('renders "$icon" icon when `isGroupOpen` is $isGroupOpen', ({ isGroupOpen, icon }) => {
createComponent({
isGroupOpen,
}); });
it('should render caret right icon if `isGroupOpen` prop is `false`', () => { expect(findGlIcon().props('name')).toBe(icon);
vm = createComponent();
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('angle-right-icon');
}); });
}); });
}); });
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import ItemStats from '~/groups/components/item_stats.vue';
import ItemStatsValue from '~/groups/components/item_stats_value.vue';
import mountComponent from 'helpers/vue_mount_component_helper'; import { mockParentGroupItem, ITEM_TYPE } from '../mock_data';
import itemStatsComponent from '~/groups/components/item_stats.vue';
import {
mockParentGroupItem,
ITEM_TYPE,
VISIBILITY_TYPE_ICON,
GROUP_VISIBILITY_TYPE,
PROJECT_VISIBILITY_TYPE,
} from '../mock_data';
const createComponent = (item = mockParentGroupItem) => { describe('ItemStats', () => {
const Component = Vue.extend(itemStatsComponent); let wrapper;
return mountComponent(Component, { const defaultProps = {
item, item: mockParentGroupItem,
}); };
};
describe('ItemStatsComponent', () => {
describe('computed', () => {
describe('visibilityIcon', () => {
it('should return icon class based on `item.visibility` value', () => {
Object.keys(VISIBILITY_TYPE_ICON).forEach(visibility => {
const item = { ...mockParentGroupItem, visibility };
const vm = createComponent(item);
expect(vm.visibilityIcon).toBe(VISIBILITY_TYPE_ICON[visibility]);
vm.$destroy();
});
});
});
describe('visibilityTooltip', () => {
it('should return tooltip string for Group based on `item.visibility` value', () => {
Object.keys(GROUP_VISIBILITY_TYPE).forEach(visibility => {
const item = { ...mockParentGroupItem, visibility, type: ITEM_TYPE.GROUP };
const vm = createComponent(item);
expect(vm.visibilityTooltip).toBe(GROUP_VISIBILITY_TYPE[visibility]); const createComponent = (props = {}) => {
vm.$destroy(); wrapper = shallowMount(ItemStats, {
propsData: { ...defaultProps, ...props },
}); });
}); };
it('should return tooltip string for Project based on `item.visibility` value', () => {
Object.keys(PROJECT_VISIBILITY_TYPE).forEach(visibility => {
const item = { ...mockParentGroupItem, visibility, type: ITEM_TYPE.PROJECT };
const vm = createComponent(item);
expect(vm.visibilityTooltip).toBe(PROJECT_VISIBILITY_TYPE[visibility]); afterEach(() => {
vm.$destroy(); if (wrapper) {
}); wrapper.destroy();
}); wrapper = null;
}
}); });
describe('isProject', () => { const findItemStatsValue = () => wrapper.find(ItemStatsValue);
it('should return boolean value representing whether `item.type` is Project or not', () => {
let item;
let vm;
item = { ...mockParentGroupItem, type: ITEM_TYPE.PROJECT };
vm = createComponent(item);
expect(vm.isProject).toBeTruthy();
vm.$destroy();
item = { ...mockParentGroupItem, type: ITEM_TYPE.GROUP };
vm = createComponent(item);
expect(vm.isProject).toBeFalsy();
vm.$destroy();
});
});
describe('isGroup', () => {
it('should return boolean value representing whether `item.type` is Group or not', () => {
let item;
let vm;
item = { ...mockParentGroupItem, type: ITEM_TYPE.GROUP };
vm = createComponent(item);
expect(vm.isGroup).toBeTruthy();
vm.$destroy();
item = { ...mockParentGroupItem, type: ITEM_TYPE.PROJECT };
vm = createComponent(item);
expect(vm.isGroup).toBeFalsy();
vm.$destroy();
});
});
});
describe('template', () => { describe('template', () => {
it('renders component container element correctly', () => { it('renders component container element correctly', () => {
const vm = createComponent(); createComponent();
expect(vm.$el.classList.contains('stats')).toBeTruthy();
vm.$destroy(); expect(wrapper.classes()).toContain('stats');
}); });
it('renders start count and last updated information for project item correctly', () => { it('renders start count and last updated information for project item correctly', () => {
const item = { ...mockParentGroupItem, type: ITEM_TYPE.PROJECT, starCount: 4 }; const item = {
const vm = createComponent(item); ...mockParentGroupItem,
type: ITEM_TYPE.PROJECT,
const projectStarIconEl = vm.$el.querySelector('.project-stars'); starCount: 4,
};
expect(projectStarIconEl).not.toBeNull(); createComponent({ item });
expect(projectStarIconEl.querySelectorAll('svg').length).toBeGreaterThan(0);
expect(projectStarIconEl.querySelectorAll('.stat-value').length).toBeGreaterThan(0);
expect(vm.$el.querySelectorAll('.last-updated').length).toBeGreaterThan(0);
vm.$destroy(); expect(findItemStatsValue().exists()).toBe(true);
expect(findItemStatsValue().props('cssClass')).toBe('project-stars');
expect(wrapper.contains('.last-updated')).toBe(true);
}); });
}); });
}); });
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import { GlIcon } from '@gitlab/ui';
import ItemStatsValue from '~/groups/components/item_stats_value.vue';
import mountComponent from 'helpers/vue_mount_component_helper'; describe('ItemStatsValue', () => {
import itemStatsValueComponent from '~/groups/components/item_stats_value.vue'; let wrapper;
const createComponent = ({ title, cssClass, iconName, tooltipPlacement, value }) => { const defaultProps = {
const Component = Vue.extend(itemStatsValueComponent);
return mountComponent(Component, {
title,
cssClass,
iconName,
tooltipPlacement,
value,
});
};
describe('ItemStatsValueComponent', () => {
describe('computed', () => {
let vm;
const itemConfig = {
title: 'Subgroups', title: 'Subgroups',
cssClass: 'number-subgroups', cssClass: 'number-subgroups',
iconName: 'folder', iconName: 'folder',
tooltipPlacement: 'left', tooltipPlacement: 'left',
}; };
describe('isValuePresent', () => { const createComponent = (props = {}) => {
it('returns true if non-empty `value` is present', () => { wrapper = shallowMount(ItemStatsValue, {
vm = createComponent({ ...itemConfig, value: 10 }); propsData: { ...defaultProps, ...props },
});
};
expect(vm.isValuePresent).toBeTruthy(); afterEach(() => {
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
}); });
it('returns false if empty `value` is present', () => { const findGlIcon = () => wrapper.find(GlIcon);
vm = createComponent(itemConfig); const findStatValue = () => wrapper.find('[data-testid="itemStatValue"]');
expect(vm.isValuePresent).toBeFalsy(); describe('template', () => {
}); describe('when `value` is not provided', () => {
it('does not render value count', () => {
createComponent();
afterEach(() => { expect(findStatValue().exists()).toBe(false);
vm.$destroy();
});
}); });
}); });
describe('template', () => { describe('when `value` is provided', () => {
let vm;
beforeEach(() => { beforeEach(() => {
vm = createComponent({ createComponent({
title: 'Subgroups',
cssClass: 'number-subgroups',
iconName: 'folder',
tooltipPlacement: 'left',
value: 10, value: 10,
}); });
}); });
afterEach(() => {
vm.$destroy();
});
it('renders component element correctly', () => { it('renders component element correctly', () => {
expect(vm.$el.classList.contains('number-subgroups')).toBeTruthy(); expect(wrapper.classes()).toContain('number-subgroups');
expect(vm.$el.querySelectorAll('svg').length).toBeGreaterThan(0);
expect(vm.$el.querySelectorAll('.stat-value').length).toBeGreaterThan(0);
}); });
it('renders element tooltip correctly', () => { it('renders element tooltip correctly', () => {
expect(vm.$el.dataset.originalTitle).toBe('Subgroups'); expect(wrapper.attributes('data-original-title')).toBe('Subgroups');
expect(vm.$el.dataset.placement).toBe('left'); expect(wrapper.attributes('data-placement')).toBe('left');
}); });
it('renders element icon correctly', () => { it('renders element icon correctly', () => {
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('folder-icon'); expect(findGlIcon().exists()).toBe(true);
expect(findGlIcon().props('name')).toBe('folder');
}); });
it('renders value count correctly', () => { it('renders value count correctly', () => {
expect(vm.$el.querySelector('.stat-value').innerText.trim()).toContain('10'); expect(findStatValue().classes()).toContain('stat-value');
expect(findStatValue().text()).toBe('10');
});
}); });
}); });
}); });
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import { GlIcon } from '@gitlab/ui';
import mountComponent from 'helpers/vue_mount_component_helper'; import ItemTypeIcon from '~/groups/components/item_type_icon.vue';
import itemTypeIconComponent from '~/groups/components/item_type_icon.vue';
import { ITEM_TYPE } from '../mock_data'; import { ITEM_TYPE } from '../mock_data';
const createComponent = (itemType = ITEM_TYPE.GROUP, isGroupOpen = false) => { describe('ItemTypeIcon', () => {
const Component = Vue.extend(itemTypeIconComponent); let wrapper;
return mountComponent(Component, { const defaultProps = {
itemType, itemType: ITEM_TYPE.GROUP,
isGroupOpen, isGroupOpen: false,
}); };
};
describe('ItemTypeIconComponent', () => { const createComponent = (props = {}) => {
describe('template', () => { wrapper = shallowMount(ItemTypeIcon, {
it('should render component template correctly', () => { propsData: { ...defaultProps, ...props },
const vm = createComponent();
expect(vm.$el.classList.contains('item-type-icon')).toBeTruthy();
vm.$destroy();
}); });
};
it('should render folder open or close icon based `isGroupOpen` prop value', () => { afterEach(() => {
let vm; if (wrapper) {
wrapper.destroy();
vm = createComponent(ITEM_TYPE.GROUP, true); wrapper = null;
}
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('folder-open-icon');
vm.$destroy();
vm = createComponent(ITEM_TYPE.GROUP);
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('folder-o-icon');
vm.$destroy();
}); });
it('should render bookmark icon based on `isProject` prop value', () => { const findGlIcon = () => wrapper.find(GlIcon);
let vm;
vm = createComponent(ITEM_TYPE.PROJECT);
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('bookmark-icon'); describe('template', () => {
vm.$destroy(); it('renders component template correctly', () => {
createComponent();
vm = createComponent(ITEM_TYPE.GROUP); expect(wrapper.classes()).toContain('item-type-icon');
});
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).not.toBe('bookmark-icon'); it.each`
vm.$destroy(); type | isGroupOpen | icon
${ITEM_TYPE.GROUP} | ${true} | ${'folder-open'}
${ITEM_TYPE.GROUP} | ${false} | ${'folder-o'}
${ITEM_TYPE.PROJECT} | ${true} | ${'bookmark'}
${ITEM_TYPE.PROJECT} | ${false} | ${'bookmark'}
`(
'shows "$icon" icon when `itemType` is "$type" and `isGroupOpen` is $isGroupOpen',
({ type, isGroupOpen, icon }) => {
createComponent({
itemType: type,
isGroupOpen,
}); });
expect(findGlIcon().props('name')).toBe(icon);
},
);
}); });
}); });
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