Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/groups')
-rw-r--r--spec/frontend/groups/components/app_spec.js124
-rw-r--r--spec/frontend/groups/components/item_actions_spec.js89
-rw-r--r--spec/frontend/groups/members/index_spec.js13
-rw-r--r--spec/frontend/groups/mock_data.js5
4 files changed, 105 insertions, 126 deletions
diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js
index 5d34bc48ed5..691f8896d74 100644
--- a/spec/frontend/groups/components/app_spec.js
+++ b/spec/frontend/groups/components/app_spec.js
@@ -2,6 +2,8 @@ import '~/flash';
import $ from 'jquery';
import Vue from 'vue';
import AxiosMockAdapter from 'axios-mock-adapter';
+import { GlModal, GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
import appComponent from '~/groups/components/app.vue';
@@ -23,47 +25,51 @@ import {
mockPageInfo,
} from '../mock_data';
-const createComponent = (hideProjects = false) => {
- const Component = Vue.extend(appComponent);
- const store = new GroupsStore(false);
- const service = new GroupsService(mockEndpoint);
-
- store.state.pageInfo = mockPageInfo;
-
- return new Component({
- propsData: {
- store,
- service,
- hideProjects,
- },
- });
+const $toast = {
+ show: jest.fn(),
};
describe('AppComponent', () => {
+ let wrapper;
let vm;
let mock;
let getGroupsSpy;
+ const store = new GroupsStore(false);
+ const service = new GroupsService(mockEndpoint);
+
+ const createShallowComponent = (hideProjects = false) => {
+ store.state.pageInfo = mockPageInfo;
+ wrapper = shallowMount(appComponent, {
+ propsData: {
+ store,
+ service,
+ hideProjects,
+ },
+ mocks: {
+ $toast,
+ },
+ });
+ vm = wrapper.vm;
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
beforeEach(() => {
mock = new AxiosMockAdapter(axios);
mock.onGet('/dashboard/groups.json').reply(200, mockGroups);
Vue.component('group-folder', groupFolderComponent);
Vue.component('group-item', groupItemComponent);
- vm = createComponent();
+ createShallowComponent();
getGroupsSpy = jest.spyOn(vm.service, 'getGroups');
return vm.$nextTick();
});
describe('computed', () => {
- beforeEach(() => {
- vm.$mount();
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
describe('groups', () => {
it('should return list of groups from store', () => {
jest.spyOn(vm.store, 'getGroups').mockImplementation(() => {});
@@ -88,14 +94,6 @@ describe('AppComponent', () => {
});
describe('methods', () => {
- beforeEach(() => {
- vm.$mount();
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
describe('fetchGroups', () => {
it('should call `getGroups` with all the params provided', () => {
return vm
@@ -284,29 +282,15 @@ describe('AppComponent', () => {
it('updates props which show modal confirmation dialog', () => {
const group = { ...mockParentGroupItem };
- expect(vm.showModal).toBe(false);
expect(vm.groupLeaveConfirmationMessage).toBe('');
vm.showLeaveGroupModal(group, mockParentGroupItem);
- expect(vm.showModal).toBe(true);
expect(vm.groupLeaveConfirmationMessage).toBe(
`Are you sure you want to leave the "${group.fullName}" group?`,
);
});
});
- describe('hideLeaveGroupModal', () => {
- it('hides modal confirmation which is shown before leaving the group', () => {
- const group = { ...mockParentGroupItem };
- vm.showLeaveGroupModal(group, mockParentGroupItem);
-
- expect(vm.showModal).toBe(true);
- vm.hideLeaveGroupModal();
-
- expect(vm.showModal).toBe(false);
- });
- });
-
describe('leaveGroup', () => {
let groupItem;
let childGroupItem;
@@ -324,18 +308,16 @@ describe('AppComponent', () => {
const notice = `You left the "${childGroupItem.fullName}" group.`;
jest.spyOn(vm.service, 'leaveGroup').mockResolvedValue({ data: { notice } });
jest.spyOn(vm.store, 'removeGroup');
- jest.spyOn(window, 'Flash').mockImplementation(() => {});
jest.spyOn($, 'scrollTo').mockImplementation(() => {});
vm.leaveGroup();
- expect(vm.showModal).toBe(false);
expect(vm.targetGroup.isBeingRemoved).toBe(true);
expect(vm.service.leaveGroup).toHaveBeenCalledWith(vm.targetGroup.leavePath);
return waitForPromises().then(() => {
expect($.scrollTo).toHaveBeenCalledWith(0);
expect(vm.store.removeGroup).toHaveBeenCalledWith(vm.targetGroup, vm.targetParentGroup);
- expect(window.Flash).toHaveBeenCalledWith(notice, 'notice');
+ expect($toast.show).toHaveBeenCalledWith(notice);
});
});
@@ -417,8 +399,7 @@ describe('AppComponent', () => {
it('should bind event listeners on eventHub', () => {
jest.spyOn(eventHub, '$on').mockImplementation(() => {});
- const newVm = createComponent();
- newVm.$mount();
+ createShallowComponent();
return vm.$nextTick().then(() => {
expect(eventHub.$on).toHaveBeenCalledWith('fetchPage', expect.any(Function));
@@ -426,25 +407,20 @@ describe('AppComponent', () => {
expect(eventHub.$on).toHaveBeenCalledWith('showLeaveGroupModal', expect.any(Function));
expect(eventHub.$on).toHaveBeenCalledWith('updatePagination', expect.any(Function));
expect(eventHub.$on).toHaveBeenCalledWith('updateGroups', expect.any(Function));
- newVm.$destroy();
});
});
it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `false`', () => {
- const newVm = createComponent();
- newVm.$mount();
+ createShallowComponent();
return vm.$nextTick().then(() => {
- expect(newVm.searchEmptyMessage).toBe('No groups or projects matched your search');
- newVm.$destroy();
+ expect(vm.searchEmptyMessage).toBe('No groups or projects matched your search');
});
});
it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `true`', () => {
- const newVm = createComponent(true);
- newVm.$mount();
+ createShallowComponent(true);
return vm.$nextTick().then(() => {
- expect(newVm.searchEmptyMessage).toBe('No groups matched your search');
- newVm.$destroy();
+ expect(vm.searchEmptyMessage).toBe('No groups matched your search');
});
});
});
@@ -453,9 +429,8 @@ describe('AppComponent', () => {
it('should unbind event listeners on eventHub', () => {
jest.spyOn(eventHub, '$off').mockImplementation(() => {});
- const newVm = createComponent();
- newVm.$mount();
- newVm.$destroy();
+ createShallowComponent();
+ wrapper.destroy();
return vm.$nextTick().then(() => {
expect(eventHub.$off).toHaveBeenCalledWith('fetchPage', expect.any(Function));
@@ -468,19 +443,10 @@ describe('AppComponent', () => {
});
describe('template', () => {
- beforeEach(() => {
- vm.$mount();
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
it('should render loading icon', () => {
vm.isLoading = true;
return vm.$nextTick().then(() => {
- expect(vm.$el.querySelector('.loading-animation')).toBeDefined();
- expect(vm.$el.querySelector('span').getAttribute('aria-label')).toBe('Loading groups');
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
});
});
@@ -493,15 +459,13 @@ describe('AppComponent', () => {
});
it('renders modal confirmation dialog', () => {
- vm.groupLeaveConfirmationMessage = 'Are you sure you want to leave the "foo" group?';
- vm.showModal = true;
- return vm.$nextTick().then(() => {
- const modalDialogEl = vm.$el.querySelector('.modal');
+ createShallowComponent();
- expect(modalDialogEl).not.toBe(null);
- expect(modalDialogEl.querySelector('.modal-title').innerText.trim()).toBe('Are you sure?');
- expect(modalDialogEl.querySelector('.btn.btn-warning').innerText.trim()).toBe('Leave');
- });
+ const findGlModal = wrapper.find(GlModal);
+
+ expect(findGlModal.exists()).toBe(true);
+ expect(findGlModal.attributes('title')).toBe('Are you sure?');
+ expect(findGlModal.props('actionPrimary').text).toBe('Leave group');
});
});
});
diff --git a/spec/frontend/groups/components/item_actions_spec.js b/spec/frontend/groups/components/item_actions_spec.js
index d4aa29eaadd..9adbc9abe13 100644
--- a/spec/frontend/groups/components/item_actions_spec.js
+++ b/spec/frontend/groups/components/item_actions_spec.js
@@ -1,5 +1,4 @@
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';
@@ -20,18 +19,25 @@ describe('ItemActions', () => {
};
afterEach(() => {
- if (wrapper) {
- wrapper.destroy();
- wrapper = null;
- }
+ wrapper.destroy();
+ wrapper = null;
});
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', () => {
+ let group;
+
+ beforeEach(() => {
+ group = {
+ ...mockParentGroupItem,
+ canEdit: true,
+ canLeave: true,
+ };
+ createComponent({ group });
+ });
+
it('renders component template correctly', () => {
createComponent();
@@ -39,49 +45,46 @@ describe('ItemActions', () => {
});
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');
+ const button = findEditGroupBtn();
+ expect(button.exists()).toBe(true);
+ expect(button.props('icon')).toBe('pencil');
+ expect(button.attributes('aria-label')).toBe('Edit group');
});
- describe('`canLeave` is true', () => {
- const group = {
- ...mockParentGroupItem,
- canLeave: true,
- };
+ it('renders "Leave this group" button with correct attribute values', () => {
+ const button = findLeaveGroupBtn();
+ expect(button.exists()).toBe(true);
+ expect(button.props('icon')).toBe('leave');
+ expect(button.attributes('aria-label')).toBe('Leave this group');
+ });
- beforeEach(() => {
- createComponent({ group });
- });
+ it('emits `showLeaveGroupModal` event in the event hub', () => {
+ jest.spyOn(eventHub, '$emit');
+ findLeaveGroupBtn().vm.$emit('click', { stopPropagation: () => {} });
- 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');
- });
+ expect(eventHub.$emit).toHaveBeenCalledWith('showLeaveGroupModal', group, parentGroup);
+ });
+ });
- it('emits event on "Leave this group" button click', () => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+ it('does not render leave button if group can not be left', () => {
+ createComponent({
+ group: {
+ ...mockParentGroupItem,
+ canLeave: false,
+ },
+ });
- findLeaveGroupBtn().trigger('click');
+ expect(findLeaveGroupBtn().exists()).toBe(false);
+ });
- expect(eventHub.$emit).toHaveBeenCalledWith('showLeaveGroupModal', group, parentGroup);
- });
+ it('does not render edit button if group can not be edited', () => {
+ createComponent({
+ group: {
+ ...mockParentGroupItem,
+ canEdit: false,
+ },
});
+
+ expect(findEditGroupBtn().exists()).toBe(false);
});
});
diff --git a/spec/frontend/groups/members/index_spec.js b/spec/frontend/groups/members/index_spec.js
index 2fb7904bcfe..aaa36665c45 100644
--- a/spec/frontend/groups/members/index_spec.js
+++ b/spec/frontend/groups/members/index_spec.js
@@ -9,7 +9,12 @@ describe('initGroupMembersApp', () => {
let wrapper;
const setup = () => {
- vm = initGroupMembersApp(el, ['account'], () => ({}));
+ vm = initGroupMembersApp(
+ el,
+ ['account'],
+ { table: { 'data-qa-selector': 'members_list' } },
+ () => ({}),
+ );
wrapper = createWrapper(vm);
};
@@ -68,6 +73,12 @@ describe('initGroupMembersApp', () => {
expect(vm.$store.state.tableFields).toEqual(['account']);
});
+ it('sets `tableAttrs` in Vuex store', () => {
+ setup();
+
+ expect(vm.$store.state.tableAttrs).toEqual({ table: { 'data-qa-selector': 'members_list' } });
+ });
+
it('sets `requestFormatter` in Vuex store', () => {
setup();
diff --git a/spec/frontend/groups/mock_data.js b/spec/frontend/groups/mock_data.js
index 380dda9f7b1..603cb27deec 100644
--- a/spec/frontend/groups/mock_data.js
+++ b/spec/frontend/groups/mock_data.js
@@ -7,13 +7,14 @@ export const ITEM_TYPE = {
export const GROUP_VISIBILITY_TYPE = {
public: 'Public - The group and any public projects can be viewed without any authentication.',
- internal: 'Internal - The group and any internal projects can be viewed by any logged in user.',
+ internal:
+ 'Internal - The group and any internal projects can be viewed by any logged in user except external users.',
private: 'Private - The group and its projects can only be viewed by members.',
};
export const PROJECT_VISIBILITY_TYPE = {
public: 'Public - The project can be accessed without any authentication.',
- internal: 'Internal - The project can be accessed by any logged in user.',
+ internal: 'Internal - The project can be accessed by any logged in user except external users.',
private:
'Private - Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group.',
};