summaryrefslogtreecommitdiff
path: root/spec/frontend/groups
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/groups')
-rw-r--r--spec/frontend/groups/components/app_spec.js66
-rw-r--r--spec/frontend/groups/components/group_folder_spec.js6
-rw-r--r--spec/frontend/groups/components/groups_spec.js26
-rw-r--r--spec/frontend/groups/components/invite_members_banner_spec.js4
-rw-r--r--spec/frontend/groups/components/item_actions_spec.js38
-rw-r--r--spec/frontend/groups/components/transfer_group_form_spec.js131
-rw-r--r--spec/frontend/groups/landing_spec.js5
-rw-r--r--spec/frontend/groups/transfer_edit_spec.js31
8 files changed, 209 insertions, 98 deletions
diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js
index bc8c6460cf4..848e50c86ba 100644
--- a/spec/frontend/groups/components/app_spec.js
+++ b/spec/frontend/groups/components/app_spec.js
@@ -1,7 +1,7 @@
import { GlModal, GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import appComponent from '~/groups/components/app.vue';
@@ -58,7 +58,7 @@ describe('AppComponent', () => {
wrapper = null;
});
- beforeEach(() => {
+ beforeEach(async () => {
mock = new AxiosMockAdapter(axios);
mock.onGet('/dashboard/groups.json').reply(200, mockGroups);
Vue.component('GroupFolder', groupFolderComponent);
@@ -66,7 +66,7 @@ describe('AppComponent', () => {
createShallowComponent();
getGroupsSpy = jest.spyOn(vm.service, 'getGroups');
- return vm.$nextTick();
+ await nextTick();
});
describe('computed', () => {
@@ -280,6 +280,7 @@ describe('AppComponent', () => {
expect(vm.targetParentGroup).toBe(null);
vm.showLeaveGroupModal(group, mockParentGroupItem);
+ expect(vm.isModalVisible).toBe(true);
expect(vm.targetGroup).not.toBe(null);
expect(vm.targetParentGroup).not.toBe(null);
});
@@ -290,6 +291,7 @@ describe('AppComponent', () => {
expect(vm.groupLeaveConfirmationMessage).toBe('');
vm.showLeaveGroupModal(group, mockParentGroupItem);
+ expect(vm.isModalVisible).toBe(true);
expect(vm.groupLeaveConfirmationMessage).toBe(
`Are you sure you want to leave the "${group.fullName}" group?`,
);
@@ -397,66 +399,60 @@ describe('AppComponent', () => {
});
describe('created', () => {
- it('should bind event listeners on eventHub', () => {
+ it('should bind event listeners on eventHub', async () => {
jest.spyOn(eventHub, '$on').mockImplementation(() => {});
createShallowComponent();
- return vm.$nextTick().then(() => {
- expect(eventHub.$on).toHaveBeenCalledWith('fetchPage', expect.any(Function));
- expect(eventHub.$on).toHaveBeenCalledWith('toggleChildren', expect.any(Function));
- expect(eventHub.$on).toHaveBeenCalledWith('showLeaveGroupModal', expect.any(Function));
- expect(eventHub.$on).toHaveBeenCalledWith('updatePagination', expect.any(Function));
- expect(eventHub.$on).toHaveBeenCalledWith('updateGroups', expect.any(Function));
- });
+ await nextTick();
+ expect(eventHub.$on).toHaveBeenCalledWith('fetchPage', expect.any(Function));
+ expect(eventHub.$on).toHaveBeenCalledWith('toggleChildren', expect.any(Function));
+ expect(eventHub.$on).toHaveBeenCalledWith('showLeaveGroupModal', expect.any(Function));
+ expect(eventHub.$on).toHaveBeenCalledWith('updatePagination', expect.any(Function));
+ expect(eventHub.$on).toHaveBeenCalledWith('updateGroups', expect.any(Function));
});
- it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `false`', () => {
+ it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `false`', async () => {
createShallowComponent();
- return vm.$nextTick().then(() => {
- expect(vm.searchEmptyMessage).toBe('No groups or projects matched your search');
- });
+ await nextTick();
+ expect(vm.searchEmptyMessage).toBe('No groups or projects matched your search');
});
- it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `true`', () => {
+ it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `true`', async () => {
createShallowComponent(true);
- return vm.$nextTick().then(() => {
- expect(vm.searchEmptyMessage).toBe('No groups matched your search');
- });
+ await nextTick();
+ expect(vm.searchEmptyMessage).toBe('No groups matched your search');
});
});
describe('beforeDestroy', () => {
- it('should unbind event listeners on eventHub', () => {
+ it('should unbind event listeners on eventHub', async () => {
jest.spyOn(eventHub, '$off').mockImplementation(() => {});
createShallowComponent();
wrapper.destroy();
- return vm.$nextTick().then(() => {
- expect(eventHub.$off).toHaveBeenCalledWith('fetchPage', expect.any(Function));
- expect(eventHub.$off).toHaveBeenCalledWith('toggleChildren', expect.any(Function));
- expect(eventHub.$off).toHaveBeenCalledWith('showLeaveGroupModal', expect.any(Function));
- expect(eventHub.$off).toHaveBeenCalledWith('updatePagination', expect.any(Function));
- expect(eventHub.$off).toHaveBeenCalledWith('updateGroups', expect.any(Function));
- });
+ await nextTick();
+ expect(eventHub.$off).toHaveBeenCalledWith('fetchPage', expect.any(Function));
+ expect(eventHub.$off).toHaveBeenCalledWith('toggleChildren', expect.any(Function));
+ expect(eventHub.$off).toHaveBeenCalledWith('showLeaveGroupModal', expect.any(Function));
+ expect(eventHub.$off).toHaveBeenCalledWith('updatePagination', expect.any(Function));
+ expect(eventHub.$off).toHaveBeenCalledWith('updateGroups', expect.any(Function));
});
});
describe('template', () => {
- it('should render loading icon', () => {
+ it('should render loading icon', async () => {
vm.isLoading = true;
- return vm.$nextTick().then(() => {
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
- });
+ await nextTick();
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
});
- it('should render groups tree', () => {
+ it('should render groups tree', async () => {
vm.store.state.groups = [mockParentGroupItem];
vm.isLoading = false;
- return vm.$nextTick().then(() => {
- expect(vm.$el.querySelector('.groups-list-tree-container')).toBeDefined();
- });
+ await nextTick();
+ expect(vm.$el.querySelector('.groups-list-tree-container')).toBeDefined();
});
it('renders modal confirmation dialog', () => {
diff --git a/spec/frontend/groups/components/group_folder_spec.js b/spec/frontend/groups/components/group_folder_spec.js
index 1d8e10479b6..98b7c2dd6c6 100644
--- a/spec/frontend/groups/components/group_folder_spec.js
+++ b/spec/frontend/groups/components/group_folder_spec.js
@@ -1,4 +1,4 @@
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
import groupFolderComponent from '~/groups/components/group_folder.vue';
import groupItemComponent from '~/groups/components/group_item.vue';
@@ -18,13 +18,13 @@ const createComponent = (groups = mockGroups, parentGroup = mockParentGroupItem)
describe('GroupFolderComponent', () => {
let vm;
- beforeEach(() => {
+ beforeEach(async () => {
Vue.component('GroupItem', groupItemComponent);
vm = createComponent();
vm.$mount();
- return Vue.nextTick();
+ await nextTick();
});
afterEach(() => {
diff --git a/spec/frontend/groups/components/groups_spec.js b/spec/frontend/groups/components/groups_spec.js
index 0ec1ef5a49e..590b4fb3d57 100644
--- a/spec/frontend/groups/components/groups_spec.js
+++ b/spec/frontend/groups/components/groups_spec.js
@@ -1,4 +1,4 @@
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import groupFolderComponent from '~/groups/components/group_folder.vue';
@@ -21,13 +21,13 @@ const createComponent = (searchEmpty = false) => {
describe('GroupsComponent', () => {
let vm;
- beforeEach(() => {
+ beforeEach(async () => {
Vue.component('GroupFolder', groupFolderComponent);
Vue.component('GroupItem', groupItemComponent);
vm = createComponent();
- return vm.$nextTick();
+ await nextTick();
});
afterEach(() => {
@@ -52,20 +52,18 @@ describe('GroupsComponent', () => {
});
describe('template', () => {
- it('should render component template correctly', () => {
- return vm.$nextTick().then(() => {
- expect(vm.$el.querySelector('.groups-list-tree-container')).toBeDefined();
- expect(vm.$el.querySelector('.group-list-tree')).toBeDefined();
- expect(vm.$el.querySelector('.gl-pagination')).toBeDefined();
- expect(vm.$el.querySelectorAll('.has-no-search-results').length).toBe(0);
- });
+ it('should render component template correctly', async () => {
+ await nextTick();
+ expect(vm.$el.querySelector('.groups-list-tree-container')).toBeDefined();
+ expect(vm.$el.querySelector('.group-list-tree')).toBeDefined();
+ expect(vm.$el.querySelector('.gl-pagination')).toBeDefined();
+ expect(vm.$el.querySelectorAll('.has-no-search-results').length).toBe(0);
});
- it('should render empty search message when `searchEmpty` is `true`', () => {
+ it('should render empty search message when `searchEmpty` is `true`', async () => {
vm.searchEmpty = true;
- return vm.$nextTick().then(() => {
- expect(vm.$el.querySelector('.has-no-search-results')).toBeDefined();
- });
+ await nextTick();
+ expect(vm.$el.querySelector('.has-no-search-results')).toBeDefined();
});
});
});
diff --git a/spec/frontend/groups/components/invite_members_banner_spec.js b/spec/frontend/groups/components/invite_members_banner_spec.js
index c81edad499c..1924f400861 100644
--- a/spec/frontend/groups/components/invite_members_banner_spec.js
+++ b/spec/frontend/groups/components/invite_members_banner_spec.js
@@ -1,6 +1,7 @@
import { GlBanner } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
+import { nextTick } from 'vue';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import InviteMembersBanner from '~/groups/components/invite_members_banner.vue';
import eventHub from '~/invite_members/event_hub';
@@ -75,7 +76,6 @@ describe('InviteMembersBanner', () => {
it('calls openModal through the eventHub', () => {
expect(eventHub.$emit).toHaveBeenCalledWith('openModal', {
- inviteeType: 'members',
source: 'invite_members_banner',
});
});
@@ -140,7 +140,7 @@ describe('InviteMembersBanner', () => {
expect(wrapper.find(GlBanner).exists()).toBe(true);
wrapper.find(GlBanner).vm.$emit('close');
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(wrapper.find(GlBanner).exists()).toBe(false);
});
});
diff --git a/spec/frontend/groups/components/item_actions_spec.js b/spec/frontend/groups/components/item_actions_spec.js
index ffbdf9b1aa6..3ceb038dd3c 100644
--- a/spec/frontend/groups/components/item_actions_spec.js
+++ b/spec/frontend/groups/components/item_actions_spec.js
@@ -1,4 +1,4 @@
-import { shallowMount } from '@vue/test-utils';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ItemActions from '~/groups/components/item_actions.vue';
import eventHub from '~/groups/event_hub';
import { mockParentGroupItem, mockChildren } from '../mock_data';
@@ -13,7 +13,7 @@ describe('ItemActions', () => {
};
const createComponent = (props = {}) => {
- wrapper = shallowMount(ItemActions, {
+ wrapper = shallowMountExtended(ItemActions, {
propsData: { ...defaultProps, ...props },
});
};
@@ -23,8 +23,10 @@ describe('ItemActions', () => {
wrapper = null;
});
- const findEditGroupBtn = () => wrapper.find('[data-testid="edit-group-btn"]');
- const findLeaveGroupBtn = () => wrapper.find('[data-testid="leave-group-btn"]');
+ const findEditGroupBtn = () => wrapper.findByTestId(`edit-group-${mockParentGroupItem.id}-btn`);
+ const findLeaveGroupBtn = () => wrapper.findByTestId(`leave-group-${mockParentGroupItem.id}-btn`);
+ const findRemoveGroupBtn = () =>
+ wrapper.findByTestId(`remove-group-${mockParentGroupItem.id}-btn`);
describe('template', () => {
let group;
@@ -34,6 +36,7 @@ describe('ItemActions', () => {
...mockParentGroupItem,
canEdit: true,
canLeave: true,
+ canRemove: true,
};
createComponent({ group });
});
@@ -41,21 +44,21 @@ describe('ItemActions', () => {
it('renders component template correctly', () => {
createComponent();
- expect(wrapper.classes()).toContain('controls');
+ expect(wrapper.classes()).toContain('gl-display-flex', 'gl-justify-content-end', 'gl-ml-5');
});
- it('renders "Edit group" button with correct attribute values', () => {
+ it('renders "Edit" group button with correct attribute values', () => {
const button = findEditGroupBtn();
expect(button.exists()).toBe(true);
- expect(button.props('icon')).toBe('pencil');
- expect(button.attributes('aria-label')).toBe('Edit group');
+ expect(button.attributes('href')).toBe(mockParentGroupItem.editPath);
});
- it('renders "Leave this group" button with correct attribute values', () => {
- const button = findLeaveGroupBtn();
+ it('renders "Delete" group button with correct attribute values', () => {
+ const button = findRemoveGroupBtn();
expect(button.exists()).toBe(true);
- expect(button.props('icon')).toBe('leave');
- expect(button.attributes('aria-label')).toBe('Leave this group');
+ expect(button.attributes('href')).toBe(
+ `${mockParentGroupItem.editPath}#js-remove-group-form`,
+ );
});
it('emits `showLeaveGroupModal` event in the event hub', () => {
@@ -103,4 +106,15 @@ describe('ItemActions', () => {
expect(findEditGroupBtn().exists()).toBe(false);
});
+
+ it('does not render delete button if group can not be edited', () => {
+ createComponent({
+ group: {
+ ...mockParentGroupItem,
+ canRemove: false,
+ },
+ });
+
+ expect(findRemoveGroupBtn().exists()).toBe(false);
+ });
});
diff --git a/spec/frontend/groups/components/transfer_group_form_spec.js b/spec/frontend/groups/components/transfer_group_form_spec.js
new file mode 100644
index 00000000000..6dc760f4f7c
--- /dev/null
+++ b/spec/frontend/groups/components/transfer_group_form_spec.js
@@ -0,0 +1,131 @@
+import { GlAlert, GlSprintf } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import Component from '~/groups/components/transfer_group_form.vue';
+import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue';
+import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select.vue';
+
+describe('Transfer group form', () => {
+ let wrapper;
+
+ const confirmButtonText = 'confirm';
+ const confirmationPhrase = 'confirmation-phrase';
+ const paidGroupHelpLink = 'some/fake/link';
+ const groupNamespaces = [
+ {
+ id: 1,
+ humanName: 'Group 1',
+ },
+ {
+ id: 2,
+ humanName: 'Group 2',
+ },
+ ];
+
+ const defaultProps = {
+ groupNamespaces,
+ paidGroupHelpLink,
+ isPaidGroup: false,
+ confirmationPhrase,
+ confirmButtonText,
+ };
+
+ const createComponent = (propsData = {}) =>
+ shallowMountExtended(Component, {
+ propsData: {
+ ...defaultProps,
+ ...propsData,
+ },
+ stubs: { GlSprintf },
+ });
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findConfirmDanger = () => wrapper.findComponent(ConfirmDanger);
+ const findNamespaceSelect = () => wrapper.findComponent(NamespaceSelect);
+ const findHiddenInput = () => wrapper.find('[name="new_parent_group_id"]');
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('default', () => {
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ it('renders the namespace select component', () => {
+ expect(findNamespaceSelect().exists()).toBe(true);
+ });
+
+ it('sets the namespace select properties', () => {
+ expect(findNamespaceSelect().props()).toMatchObject({
+ defaultText: 'Select parent group',
+ fullWidth: false,
+ includeHeaders: false,
+ emptyNamespaceTitle: 'No parent group',
+ includeEmptyNamespace: true,
+ groupNamespaces,
+ });
+ });
+
+ it('renders the hidden input field', () => {
+ expect(findHiddenInput().exists()).toBe(true);
+ expect(findHiddenInput().attributes('value')).toBeUndefined();
+ });
+
+ it('does not render the alert message', () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+
+ it('renders the confirm danger component', () => {
+ expect(findConfirmDanger().exists()).toBe(true);
+ });
+
+ it('sets the confirm danger properties', () => {
+ expect(findConfirmDanger().props()).toMatchObject({
+ buttonClass: 'qa-transfer-button',
+ disabled: true,
+ buttonText: confirmButtonText,
+ phrase: confirmationPhrase,
+ });
+ });
+ });
+
+ describe('with a selected project', () => {
+ const [firstGroup] = groupNamespaces;
+ beforeEach(() => {
+ wrapper = createComponent();
+ findNamespaceSelect().vm.$emit('select', firstGroup);
+ });
+
+ it('sets the confirm danger disabled property to false', () => {
+ expect(findConfirmDanger().props()).toMatchObject({ disabled: false });
+ });
+
+ it('sets the hidden input field', () => {
+ expect(findHiddenInput().exists()).toBe(true);
+ expect(parseInt(findHiddenInput().attributes('value'), 10)).toBe(firstGroup.id);
+ });
+
+ it('emits "confirm" event when the danger modal is confirmed', () => {
+ expect(wrapper.emitted('confirm')).toBeUndefined();
+
+ findConfirmDanger().vm.$emit('confirm');
+
+ expect(wrapper.emitted('confirm')).toHaveLength(1);
+ });
+ });
+
+ describe('isPaidGroup = true', () => {
+ beforeEach(() => {
+ wrapper = createComponent({ isPaidGroup: true });
+ });
+
+ it('disables the transfer button', () => {
+ expect(findConfirmDanger().props()).toMatchObject({ disabled: true });
+ });
+
+ it('hides the namespace selector button', () => {
+ expect(findNamespaceSelect().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/groups/landing_spec.js b/spec/frontend/groups/landing_spec.js
index f90f541eb96..d60adea202b 100644
--- a/spec/frontend/groups/landing_spec.js
+++ b/spec/frontend/groups/landing_spec.js
@@ -159,7 +159,10 @@ describe('Landing', () => {
});
it('should call Cookies.set', () => {
- expect(Cookies.set).toHaveBeenCalledWith(test.cookieName, 'true', { expires: 365 });
+ expect(Cookies.set).toHaveBeenCalledWith(test.cookieName, 'true', {
+ expires: 365,
+ secure: false,
+ });
});
});
diff --git a/spec/frontend/groups/transfer_edit_spec.js b/spec/frontend/groups/transfer_edit_spec.js
deleted file mode 100644
index bc070920d02..00000000000
--- a/spec/frontend/groups/transfer_edit_spec.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import $ from 'jquery';
-
-import { loadHTMLFixture } from 'helpers/fixtures';
-import setupTransferEdit from '~/groups/transfer_edit';
-
-describe('setupTransferEdit', () => {
- const formSelector = '.js-group-transfer-form';
- const targetSelector = '#new_parent_group_id';
-
- beforeEach(() => {
- loadHTMLFixture('groups/edit.html');
- setupTransferEdit(formSelector, targetSelector);
- });
-
- it('disables submit button on load', () => {
- expect($(formSelector).find(':submit').prop('disabled')).toBe(true);
- });
-
- it('enables submit button when selection changes to non-empty value', () => {
- const lastValue = $(formSelector).find(targetSelector).find('.dropdown-content li').last();
- $(formSelector).find(targetSelector).val(lastValue).trigger('change');
-
- expect($(formSelector).find(':submit').prop('disabled')).toBeFalsy();
- });
-
- it('disables submit button when selection changes to empty value', () => {
- $(formSelector).find(targetSelector).val('').trigger('change');
-
- expect($(formSelector).find(':submit').prop('disabled')).toBe(true);
- });
-});