Commit 7296c119 authored by Justin Ho's avatar Justin Ho

Convert spec/frontend/groups to use VTU

- No changes to existing code apart from adding of
data-testid.
- Removed / re-organized some specs to fit newer
conventions.
parent 16fdd83b
...@@ -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="leaveGroupBtn"
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="editGroupBtn"
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', () => {
let vm;
beforeEach(() => { const createComponent = (props = {}) => {
vm = createComponent(); wrapper = shallowMount(ItemActions, {
}); propsData: { ...defaultProps, ...props },
});
};
afterEach(() => { afterEach(() => {
vm.$destroy(); if (wrapper) {
wrapper.destroy();
wrapper = null;
}
}); });
describe('methods', () => { const findEditGroupBtn = () => wrapper.find('[data-testid="editGroupBtn"]');
describe('onLeaveGroup', () => { const findEditGroupIcon = () => findEditGroupBtn().find(GlIcon);
it('emits `showLeaveGroupModal` event with `group` and `parentGroup` props', () => { const findLeaveGroupBtn = () => wrapper.find('[data-testid="leaveGroupBtn"]');
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('should render 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('should render caret down icon if `isGroupOpen` prop is `true`', () => {
vm = createComponent(true); createComponent({
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('angle-down-icon'); isGroupOpen: true,
});
expect(findGlIcon().props('name')).toBe('angle-down');
}); });
it('should render caret right icon if `isGroupOpen` prop is `false`', () => { it('should render caret right icon if `isGroupOpen` prop is `false`', () => {
vm = createComponent(); createComponent();
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('angle-right-icon');
expect(findGlIcon().props('name')).toBe('angle-right');
}); });
}); });
}); });
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]); const createComponent = (props = {}) => {
vm.$destroy(); wrapper = shallowMount(ItemStats, {
}); propsData: { ...defaultProps, ...props },
});
}); });
};
describe('visibilityTooltip', () => { afterEach(() => {
it('should return tooltip string for Group based on `item.visibility` value', () => { if (wrapper) {
Object.keys(GROUP_VISIBILITY_TYPE).forEach(visibility => { wrapper.destroy();
const item = { ...mockParentGroupItem, visibility, type: ITEM_TYPE.GROUP }; wrapper = null;
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();
});
});
}); });
const findItemStatsValue = () => wrapper.find(ItemStatsValue);
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(); expect(wrapper.classes()).toContain('stats');
vm.$destroy();
}); });
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); title: 'Subgroups',
cssClass: 'number-subgroups',
iconName: 'folder',
tooltipPlacement: 'left',
};
return mountComponent(Component, { const createComponent = (props = {}) => {
title, wrapper = shallowMount(ItemStatsValue, {
cssClass, propsData: { ...defaultProps, ...props },
iconName, });
tooltipPlacement, };
value,
afterEach(() => {
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
}); });
};
describe('ItemStatsValueComponent', () => { const findGlIcon = () => wrapper.find(GlIcon);
describe('computed', () => { const findStatValue = () => wrapper.find('[data-testid="itemStatValue"]');
let vm;
const itemConfig = {
title: 'Subgroups',
cssClass: 'number-subgroups',
iconName: 'folder',
tooltipPlacement: 'left',
};
describe('isValuePresent', () => { describe('template', () => {
it('returns true if non-empty `value` is present', () => { describe('when `value` is not provided', () => {
vm = createComponent({ ...itemConfig, value: 10 }); it('does not render value count', () => {
createComponent();
expect(vm.isValuePresent).toBeTruthy(); expect(findStatValue().exists()).toBe(false);
}); });
});
it('returns false if empty `value` is present', () => { describe('when `value` is provided', () => {
vm = createComponent(itemConfig); beforeEach(() => {
createComponent({
expect(vm.isValuePresent).toBeFalsy(); value: 10,
});
}); });
afterEach(() => { it('renders component element correctly', () => {
vm.$destroy(); expect(wrapper.classes()).toContain('number-subgroups');
}); });
});
});
describe('template', () => { it('renders element tooltip correctly', () => {
let vm; expect(wrapper.attributes('data-original-title')).toBe('Subgroups');
beforeEach(() => { expect(wrapper.attributes('data-placement')).toBe('left');
vm = createComponent({
title: 'Subgroups',
cssClass: 'number-subgroups',
iconName: 'folder',
tooltipPlacement: 'left',
value: 10,
}); });
});
afterEach(() => { it('renders element icon correctly', () => {
vm.$destroy(); expect(findGlIcon().exists()).toBe(true);
}); expect(findGlIcon().props('name')).toBe('folder');
});
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 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, {
itemType,
isGroupOpen,
});
};
describe('ItemTypeIconComponent', () => { const defaultProps = {
describe('template', () => { itemType: ITEM_TYPE.GROUP,
it('should render component template correctly', () => { isGroupOpen: false,
const vm = createComponent(); };
expect(vm.$el.classList.contains('item-type-icon')).toBeTruthy(); const createComponent = (props = {}) => {
vm.$destroy(); wrapper = shallowMount(ItemTypeIcon, {
propsData: { ...defaultProps, ...props },
}); });
};
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'); const findGlIcon = () => wrapper.find(GlIcon);
vm.$destroy();
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'); expect(wrapper.classes()).toContain('item-type-icon');
vm.$destroy();
}); });
it('should render bookmark icon based on `isProject` prop value', () => { it.each`
let vm; type | isGroupOpen | icon
${ITEM_TYPE.GROUP} | ${true} | ${'folder-open'}
vm = createComponent(ITEM_TYPE.PROJECT); ${ITEM_TYPE.GROUP} | ${false} | ${'folder-o'}
${ITEM_TYPE.PROJECT} | ${true} | ${'bookmark'}
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('bookmark-icon'); ${ITEM_TYPE.PROJECT} | ${false} | ${'bookmark'}
vm.$destroy(); `(
'shows "$icon" icon when `itemType` is "$type" and `isGroupOpen` is $isGroupOpen',
vm = createComponent(ITEM_TYPE.GROUP); ({ type, isGroupOpen, icon }) => {
createComponent({
expect(vm.$el.querySelector('svg').getAttribute('data-testid')).not.toBe('bookmark-icon'); itemType: type,
vm.$destroy(); 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