diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-30 14:02:35 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-30 14:02:35 +0300 |
commit | 434a0ce52d75e13d48eac9ce83774954c7c5d48d (patch) | |
tree | de3b7a7cf1ce8b07555f28df592297c76894c90f /spec/frontend/members/components/action_buttons | |
parent | 0a0d9493ca481c56b739a3df27c31262283150fe (diff) |
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc2
Diffstat (limited to 'spec/frontend/members/components/action_buttons')
8 files changed, 611 insertions, 0 deletions
diff --git a/spec/frontend/members/components/action_buttons/access_request_action_buttons_spec.js b/spec/frontend/members/components/action_buttons/access_request_action_buttons_spec.js new file mode 100644 index 00000000000..9a8434a1222 --- /dev/null +++ b/spec/frontend/members/components/action_buttons/access_request_action_buttons_spec.js @@ -0,0 +1,108 @@ +import { shallowMount } from '@vue/test-utils'; +import AccessRequestActionButtons from '~/members/components/action_buttons/access_request_action_buttons.vue'; +import RemoveMemberButton from '~/members/components/action_buttons/remove_member_button.vue'; +import ApproveAccessRequestButton from '~/members/components/action_buttons/approve_access_request_button.vue'; +import { accessRequest as member } from '../../mock_data'; + +describe('AccessRequestActionButtons', () => { + let wrapper; + + const createComponent = (propsData = {}) => { + wrapper = shallowMount(AccessRequestActionButtons, { + propsData: { + member, + isCurrentUser: true, + ...propsData, + }, + }); + }; + + const findRemoveMemberButton = () => wrapper.find(RemoveMemberButton); + const findApproveButton = () => wrapper.find(ApproveAccessRequestButton); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('when user has `canRemove` permissions', () => { + beforeEach(() => { + createComponent({ + permissions: { + canRemove: true, + }, + }); + }); + + it('renders remove member button', () => { + expect(findRemoveMemberButton().exists()).toBe(true); + }); + + it('sets props correctly', () => { + expect(findRemoveMemberButton().props()).toMatchObject({ + memberId: member.id, + title: 'Deny access', + isAccessRequest: true, + icon: 'close', + }); + }); + + describe('when member is the current user', () => { + it('sets `message` prop correctly', () => { + expect(findRemoveMemberButton().props('message')).toBe( + `Are you sure you want to withdraw your access request for "${member.source.name}"`, + ); + }); + }); + + describe('when member is not the current user', () => { + it('sets `message` prop correctly', () => { + createComponent({ + isCurrentUser: false, + permissions: { + canRemove: true, + }, + }); + + expect(findRemoveMemberButton().props('message')).toBe( + `Are you sure you want to deny ${member.user.name}'s request to join "${member.source.name}"`, + ); + }); + }); + }); + + describe('when user does not have `canRemove` permissions', () => { + it('does not render remove member button', () => { + createComponent({ + permissions: { + canRemove: false, + }, + }); + + expect(findRemoveMemberButton().exists()).toBe(false); + }); + }); + + describe('when user has `canUpdate` permissions', () => { + it('renders the approve button', () => { + createComponent({ + permissions: { + canUpdate: true, + }, + }); + + expect(findApproveButton().exists()).toBe(true); + }); + }); + + describe('when user does not have `canUpdate` permissions', () => { + it('does not render the approve button', () => { + createComponent({ + permissions: { + canUpdate: false, + }, + }); + + expect(findApproveButton().exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/members/components/action_buttons/approve_access_request_button_spec.js b/spec/frontend/members/components/action_buttons/approve_access_request_button_spec.js new file mode 100644 index 00000000000..7ce2c633bb3 --- /dev/null +++ b/spec/frontend/members/components/action_buttons/approve_access_request_button_spec.js @@ -0,0 +1,74 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import Vuex from 'vuex'; +import { GlButton, GlForm } from '@gitlab/ui'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import ApproveAccessRequestButton from '~/members/components/action_buttons/approve_access_request_button.vue'; + +jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' })); + +const localVue = createLocalVue(); +localVue.use(Vuex); + +describe('ApproveAccessRequestButton', () => { + let wrapper; + + const createStore = (state = {}) => { + return new Vuex.Store({ + state: { + memberPath: '/groups/foo-bar/-/group_members/:id', + ...state, + }, + }); + }; + + const createComponent = (propsData = {}, state) => { + wrapper = shallowMount(ApproveAccessRequestButton, { + localVue, + store: createStore(state), + propsData: { + memberId: 1, + ...propsData, + }, + directives: { + GlTooltip: createMockDirective(), + }, + }); + }; + + const findForm = () => wrapper.find(GlForm); + const findButton = () => findForm().find(GlButton); + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays a tooltip', () => { + const button = findButton(); + + expect(getBinding(button.element, 'gl-tooltip')).not.toBeUndefined(); + expect(button.attributes('title')).toBe('Grant access'); + }); + + it('sets `aria-label` attribute', () => { + expect(findButton().attributes('aria-label')).toBe('Grant access'); + }); + + it('submits the form when button is clicked', () => { + expect(findButton().attributes('type')).toBe('submit'); + }); + + it('displays form with correct action and inputs', () => { + const form = findForm(); + + expect(form.attributes('action')).toBe( + '/groups/foo-bar/-/group_members/1/approve_access_request', + ); + expect(form.find('input[name="authenticity_token"]').attributes('value')).toBe( + 'mock-csrf-token', + ); + }); +}); diff --git a/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js b/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js new file mode 100644 index 00000000000..887b21dc1d0 --- /dev/null +++ b/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js @@ -0,0 +1,85 @@ +import { shallowMount } from '@vue/test-utils'; +import InviteActionButtons from '~/members/components/action_buttons/invite_action_buttons.vue'; +import RemoveMemberButton from '~/members/components/action_buttons/remove_member_button.vue'; +import ResendInviteButton from '~/members/components/action_buttons/resend_invite_button.vue'; +import { invite as member } from '../../mock_data'; + +describe('InviteActionButtons', () => { + let wrapper; + + const createComponent = (propsData = {}) => { + wrapper = shallowMount(InviteActionButtons, { + propsData: { + member, + ...propsData, + }, + }); + }; + + const findRemoveMemberButton = () => wrapper.find(RemoveMemberButton); + const findResendInviteButton = () => wrapper.find(ResendInviteButton); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('when user has `canRemove` permissions', () => { + beforeEach(() => { + createComponent({ + permissions: { + canRemove: true, + }, + }); + }); + + it('renders remove member button', () => { + expect(findRemoveMemberButton().exists()).toBe(true); + }); + + it('sets props correctly', () => { + expect(findRemoveMemberButton().props()).toEqual({ + memberId: member.id, + message: `Are you sure you want to revoke the invitation for ${member.invite.email} to join "${member.source.name}"`, + title: 'Revoke invite', + isAccessRequest: false, + icon: 'remove', + }); + }); + }); + + describe('when user does not have `canRemove` permissions', () => { + it('does not render remove member button', () => { + createComponent({ + permissions: { + canRemove: false, + }, + }); + + expect(findRemoveMemberButton().exists()).toBe(false); + }); + }); + + describe('when user has `canResend` permissions', () => { + it('renders resend invite button', () => { + createComponent({ + permissions: { + canResend: true, + }, + }); + + expect(findResendInviteButton().exists()).toBe(true); + }); + }); + + describe('when user does not have `canResend` permissions', () => { + it('does not render resend invite button', () => { + createComponent({ + permissions: { + canResend: false, + }, + }); + + expect(findResendInviteButton().exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/members/components/action_buttons/leave_button_spec.js b/spec/frontend/members/components/action_buttons/leave_button_spec.js new file mode 100644 index 00000000000..2afe112c74b --- /dev/null +++ b/spec/frontend/members/components/action_buttons/leave_button_spec.js @@ -0,0 +1,59 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlButton } from '@gitlab/ui'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import LeaveButton from '~/members/components/action_buttons/leave_button.vue'; +import LeaveModal from '~/members/components/modals/leave_modal.vue'; +import { LEAVE_MODAL_ID } from '~/members/constants'; +import { member } from '../../mock_data'; + +describe('LeaveButton', () => { + let wrapper; + + const createComponent = (propsData = {}) => { + wrapper = shallowMount(LeaveButton, { + propsData: { + member, + ...propsData, + }, + directives: { + GlTooltip: createMockDirective(), + GlModal: createMockDirective(), + }, + }); + }; + + const findButton = () => wrapper.find(GlButton); + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays a tooltip', () => { + const button = findButton(); + + expect(getBinding(button.element, 'gl-tooltip')).not.toBeUndefined(); + expect(button.attributes('title')).toBe('Leave'); + }); + + it('sets `aria-label` attribute', () => { + expect(findButton().attributes('aria-label')).toBe('Leave'); + }); + + it('renders leave modal', () => { + const leaveModal = wrapper.find(LeaveModal); + + expect(leaveModal.exists()).toBe(true); + expect(leaveModal.props('member')).toEqual(member); + }); + + it('triggers leave modal', () => { + const binding = getBinding(findButton().element, 'gl-modal'); + + expect(binding).not.toBeUndefined(); + expect(binding.value).toBe(LEAVE_MODAL_ID); + }); +}); diff --git a/spec/frontend/members/components/action_buttons/remove_group_link_button_spec.js b/spec/frontend/members/components/action_buttons/remove_group_link_button_spec.js new file mode 100644 index 00000000000..45283788676 --- /dev/null +++ b/spec/frontend/members/components/action_buttons/remove_group_link_button_spec.js @@ -0,0 +1,64 @@ +import { mount, createLocalVue } from '@vue/test-utils'; +import Vuex from 'vuex'; +import { GlButton } from '@gitlab/ui'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import RemoveGroupLinkButton from '~/members/components/action_buttons/remove_group_link_button.vue'; +import { group } from '../../mock_data'; + +const localVue = createLocalVue(); +localVue.use(Vuex); + +describe('RemoveGroupLinkButton', () => { + let wrapper; + + const actions = { + showRemoveGroupLinkModal: jest.fn(), + }; + + const createStore = () => { + return new Vuex.Store({ + actions, + }); + }; + + const createComponent = () => { + wrapper = mount(RemoveGroupLinkButton, { + localVue, + store: createStore(), + propsData: { + groupLink: group, + }, + directives: { + GlTooltip: createMockDirective(), + }, + }); + }; + + const findButton = () => wrapper.find(GlButton); + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + it('displays a tooltip', () => { + const button = findButton(); + + expect(getBinding(button.element, 'gl-tooltip')).not.toBeUndefined(); + expect(button.attributes('title')).toBe('Remove group'); + }); + + it('sets `aria-label` attribute', () => { + expect(findButton().attributes('aria-label')).toBe('Remove group'); + }); + + it('calls Vuex action to open remove group link modal when clicked', () => { + findButton().trigger('click'); + + expect(actions.showRemoveGroupLinkModal).toHaveBeenCalledWith(expect.any(Object), group); + }); +}); diff --git a/spec/frontend/members/components/action_buttons/remove_member_button_spec.js b/spec/frontend/members/components/action_buttons/remove_member_button_spec.js new file mode 100644 index 00000000000..437b3e705a4 --- /dev/null +++ b/spec/frontend/members/components/action_buttons/remove_member_button_spec.js @@ -0,0 +1,66 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import Vuex from 'vuex'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import RemoveMemberButton from '~/members/components/action_buttons/remove_member_button.vue'; + +const localVue = createLocalVue(); +localVue.use(Vuex); + +describe('RemoveMemberButton', () => { + let wrapper; + + const createStore = (state = {}) => { + return new Vuex.Store({ + state: { + memberPath: '/groups/foo-bar/-/group_members/:id', + ...state, + }, + }); + }; + + const createComponent = (propsData = {}, state) => { + wrapper = shallowMount(RemoveMemberButton, { + localVue, + store: createStore(state), + propsData: { + memberId: 1, + message: 'Are you sure you want to remove John Smith?', + title: 'Remove member', + isAccessRequest: true, + ...propsData, + }, + directives: { + GlTooltip: createMockDirective(), + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + it('sets attributes on button', () => { + createComponent(); + + expect(wrapper.attributes()).toMatchObject({ + 'data-member-path': '/groups/foo-bar/-/group_members/1', + 'data-message': 'Are you sure you want to remove John Smith?', + 'data-is-access-request': 'true', + 'aria-label': 'Remove member', + title: 'Remove member', + icon: 'remove', + }); + }); + + it('displays `title` prop as a tooltip', () => { + createComponent(); + + expect(getBinding(wrapper.element, 'gl-tooltip')).not.toBeUndefined(); + }); + + it('has CSS class used by `remove_member_modal.vue`', () => { + createComponent(); + + expect(wrapper.classes()).toContain('js-remove-member-button'); + }); +}); diff --git a/spec/frontend/members/components/action_buttons/resend_invite_button_spec.js b/spec/frontend/members/components/action_buttons/resend_invite_button_spec.js new file mode 100644 index 00000000000..a48942dd277 --- /dev/null +++ b/spec/frontend/members/components/action_buttons/resend_invite_button_spec.js @@ -0,0 +1,66 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import Vuex from 'vuex'; +import { GlButton } from '@gitlab/ui'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import ResendInviteButton from '~/members/components/action_buttons/resend_invite_button.vue'; + +jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' })); + +const localVue = createLocalVue(); +localVue.use(Vuex); + +describe('ResendInviteButton', () => { + let wrapper; + + const createStore = (state = {}) => { + return new Vuex.Store({ + state: { + memberPath: '/groups/foo-bar/-/group_members/:id', + ...state, + }, + }); + }; + + const createComponent = (propsData = {}, state) => { + wrapper = shallowMount(ResendInviteButton, { + localVue, + store: createStore(state), + propsData: { + memberId: 1, + ...propsData, + }, + directives: { + GlTooltip: createMockDirective(), + }, + }); + }; + + const findForm = () => wrapper.find('form'); + const findButton = () => findForm().find(GlButton); + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays a tooltip', () => { + expect(getBinding(findButton().element, 'gl-tooltip')).not.toBeUndefined(); + expect(findButton().attributes('title')).toBe('Resend invite'); + }); + + it('submits the form when button is clicked', () => { + expect(findButton().attributes('type')).toBe('submit'); + }); + + it('displays form with correct action and inputs', () => { + expect(findForm().attributes('action')).toBe('/groups/foo-bar/-/group_members/1/resend_invite'); + expect( + findForm() + .find('input[name="authenticity_token"]') + .attributes('value'), + ).toBe('mock-csrf-token'); + }); +}); diff --git a/spec/frontend/members/components/action_buttons/user_action_buttons_spec.js b/spec/frontend/members/components/action_buttons/user_action_buttons_spec.js new file mode 100644 index 00000000000..b03e80a537d --- /dev/null +++ b/spec/frontend/members/components/action_buttons/user_action_buttons_spec.js @@ -0,0 +1,89 @@ +import { shallowMount } from '@vue/test-utils'; +import UserActionButtons from '~/members/components/action_buttons/user_action_buttons.vue'; +import RemoveMemberButton from '~/members/components/action_buttons/remove_member_button.vue'; +import LeaveButton from '~/members/components/action_buttons/leave_button.vue'; +import { member, orphanedMember } from '../../mock_data'; + +describe('UserActionButtons', () => { + let wrapper; + + const createComponent = (propsData = {}) => { + wrapper = shallowMount(UserActionButtons, { + propsData: { + member, + isCurrentUser: false, + ...propsData, + }, + }); + }; + + const findRemoveMemberButton = () => wrapper.find(RemoveMemberButton); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('when user has `canRemove` permissions', () => { + beforeEach(() => { + createComponent({ + permissions: { + canRemove: true, + }, + }); + }); + + it('renders remove member button', () => { + expect(findRemoveMemberButton().exists()).toBe(true); + }); + + it('sets props correctly', () => { + expect(findRemoveMemberButton().props()).toEqual({ + memberId: member.id, + message: `Are you sure you want to remove ${member.user.name} from "${member.source.name}"`, + title: 'Remove member', + isAccessRequest: false, + icon: 'remove', + }); + }); + + describe('when member is orphaned', () => { + it('sets `message` prop correctly', () => { + createComponent({ + member: orphanedMember, + permissions: { + canRemove: true, + }, + }); + + expect(findRemoveMemberButton().props('message')).toBe( + `Are you sure you want to remove this orphaned member from "${orphanedMember.source.name}"`, + ); + }); + }); + + describe('when member is the current user', () => { + it('renders leave button', () => { + createComponent({ + isCurrentUser: true, + permissions: { + canRemove: true, + }, + }); + + expect(wrapper.find(LeaveButton).exists()).toBe(true); + }); + }); + }); + + describe('when user does not have `canRemove` permissions', () => { + it('does not render remove member button', () => { + createComponent({ + permissions: { + canRemove: false, + }, + }); + + expect(findRemoveMemberButton().exists()).toBe(false); + }); + }); +}); |