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