diff options
author | Robert Speicher <rspeicher@gmail.com> | 2021-01-20 13:34:23 -0600 |
---|---|---|
committer | Robert Speicher <rspeicher@gmail.com> | 2021-01-20 13:34:23 -0600 |
commit | 6438df3a1e0fb944485cebf07976160184697d72 (patch) | |
tree | 00b09bfd170e77ae9391b1a2f5a93ef6839f2597 /spec/frontend/invite_members | |
parent | 42bcd54d971da7ef2854b896a7b34f4ef8601067 (diff) | |
download | gitlab-ce-6438df3a1e0fb944485cebf07976160184697d72.tar.gz |
Add latest changes from gitlab-org/gitlab@13-8-stable-eev13.8.0-rc42
Diffstat (limited to 'spec/frontend/invite_members')
-rw-r--r-- | spec/frontend/invite_members/components/invite_members_modal_spec.js | 227 | ||||
-rw-r--r-- | spec/frontend/invite_members/components/members_token_select_spec.js | 39 |
2 files changed, 201 insertions, 65 deletions
diff --git a/spec/frontend/invite_members/components/invite_members_modal_spec.js b/spec/frontend/invite_members/components/invite_members_modal_spec.js index 4ac2a28105c..fc039bdf6da 100644 --- a/spec/frontend/invite_members/components/invite_members_modal_spec.js +++ b/spec/frontend/invite_members/components/invite_members_modal_spec.js @@ -1,5 +1,7 @@ import { shallowMount } from '@vue/test-utils'; -import { GlDropdown, GlDropdownItem, GlDatepicker, GlSprintf, GlLink } from '@gitlab/ui'; +import { GlDropdown, GlDropdownItem, GlDatepicker, GlSprintf, GlLink, GlModal } from '@gitlab/ui'; +import { stubComponent } from 'helpers/stub_component'; +import waitForPromises from 'helpers/wait_for_promises'; import Api from '~/api'; import InviteMembersModal from '~/invite_members/components/invite_members_modal.vue'; @@ -10,6 +12,15 @@ const accessLevels = { Guest: 10, Reporter: 20, Developer: 30, Maintainer: 40, O const defaultAccessLevel = '10'; const helpLink = 'https://example.com'; +const user1 = { id: 1, name: 'Name One', username: 'one_1', avatar_url: '' }; +const user2 = { id: 2, name: 'Name Two', username: 'one_2', avatar_url: '' }; +const user3 = { + id: 'user-defined-token', + name: 'email@example.com', + username: 'one_2', + avatar_url: '', +}; + const createComponent = (data = {}) => { return shallowMount(InviteMembersModal, { propsData: { @@ -24,9 +35,12 @@ const createComponent = (data = {}) => { return data; }, stubs: { - 'gl-modal': '<div><slot name="modal-footer"></slot><slot></slot></div>', - 'gl-dropdown': true, - 'gl-dropdown-item': true, + GlModal: stubComponent(GlModal, { + template: + '<div><slot name="modal-title"></slot><slot></slot><slot name="modal-footer"></slot></div>', + }), + GlDropdown: true, + GlDropdownItem: true, GlSprintf, }, }); @@ -46,6 +60,7 @@ describe('InviteMembersModal', () => { const findLink = () => wrapper.find(GlLink); const findCancelButton = () => wrapper.find({ ref: 'cancelButton' }); const findInviteButton = () => wrapper.find({ ref: 'inviteButton' }); + const clickInviteButton = () => findInviteButton().vm.$emit('click'); describe('rendering the modal', () => { beforeEach(() => { @@ -53,7 +68,7 @@ describe('InviteMembersModal', () => { }); it('renders the modal with the correct title', () => { - expect(wrapper.attributes('title')).toBe('Invite team members'); + expect(wrapper.find(GlModal).props('title')).toBe('Invite team members'); }); it('renders the Cancel button text correctly', () => { @@ -88,78 +103,184 @@ describe('InviteMembersModal', () => { }); describe('submitting the invite form', () => { - const postData = { - user_id: '1', - access_level: '10', - expires_at: new Date(), - format: 'json', - }; + const apiErrorMessage = 'Member already exists'; + + describe('when inviting an existing user to group by user ID', () => { + const postData = { + user_id: '1', + access_level: '10', + expires_at: undefined, + format: 'json', + }; + + describe('when invites are sent successfully', () => { + beforeEach(() => { + wrapper = createComponent({ newUsersToInvite: [user1] }); - describe('when the invite was sent successfully', () => { - beforeEach(() => { - wrapper = createComponent(); + wrapper.vm.$toast = { show: jest.fn() }; + jest.spyOn(Api, 'addGroupMembersByUserId').mockResolvedValue({ data: postData }); + jest.spyOn(wrapper.vm, 'showToastMessageSuccess'); - wrapper.vm.$toast = { show: jest.fn() }; - jest.spyOn(Api, 'inviteGroupMember').mockResolvedValue({ data: postData }); + clickInviteButton(); + }); - wrapper.vm.submitForm(postData); + it('calls Api addGroupMembersByUserId with the correct params', () => { + expect(Api.addGroupMembersByUserId).toHaveBeenCalledWith(id, postData); + }); + + it('displays the successful toastMessage', () => { + expect(wrapper.vm.showToastMessageSuccess).toHaveBeenCalled(); + }); }); - it('displays the successful toastMessage', () => { - const toastMessageSuccessful = 'Members were successfully added'; + describe('when the invite received an api error message', () => { + beforeEach(() => { + wrapper = createComponent({ newUsersToInvite: [user1] }); + + wrapper.vm.$toast = { show: jest.fn() }; + jest + .spyOn(Api, 'addGroupMembersByUserId') + .mockRejectedValue({ response: { data: { message: apiErrorMessage } } }); + jest.spyOn(wrapper.vm, 'showToastMessageError'); + + clickInviteButton(); + }); - expect(wrapper.vm.$toast.show).toHaveBeenCalledWith( - toastMessageSuccessful, - wrapper.vm.toastOptions, - ); + it('displays the apiErrorMessage in the toastMessage', async () => { + await waitForPromises(); + + expect(wrapper.vm.showToastMessageError).toHaveBeenCalledWith({ + response: { data: { message: apiErrorMessage } }, + }); + }); }); - it('calls Api inviteGroupMember with the correct params', () => { - expect(Api.inviteGroupMember).toHaveBeenCalledWith(id, postData); + describe('when any invite failed for any other reason', () => { + beforeEach(() => { + wrapper = createComponent({ newUsersToInvite: [user1, user2] }); + + wrapper.vm.$toast = { show: jest.fn() }; + jest + .spyOn(Api, 'addGroupMembersByUserId') + .mockRejectedValue({ response: { data: { success: false } } }); + jest.spyOn(wrapper.vm, 'showToastMessageError'); + + clickInviteButton(); + }); + + it('displays the generic error toastMessage', async () => { + await waitForPromises(); + + expect(wrapper.vm.showToastMessageError).toHaveBeenCalled(); + }); }); }); - describe('when sending the invite for a single member returned an api error', () => { - const apiErrorMessage = 'Members already exists'; + describe('when inviting a new user by email address', () => { + const postData = { + access_level: '10', + expires_at: undefined, + email: 'email@example.com', + format: 'json', + }; + + describe('when invites are sent successfully', () => { + beforeEach(() => { + wrapper = createComponent({ newUsersToInvite: [user3] }); + + wrapper.vm.$toast = { show: jest.fn() }; + jest.spyOn(Api, 'inviteGroupMembersByEmail').mockResolvedValue({ data: postData }); + jest.spyOn(wrapper.vm, 'showToastMessageSuccess'); - beforeEach(() => { - wrapper = createComponent({ newUsersToInvite: '123' }); + clickInviteButton(); + }); - wrapper.vm.$toast = { show: jest.fn() }; - jest - .spyOn(Api, 'inviteGroupMember') - .mockRejectedValue({ response: { data: { message: apiErrorMessage } } }); + it('calls Api inviteGroupMembersByEmail with the correct params', () => { + expect(Api.inviteGroupMembersByEmail).toHaveBeenCalledWith(id, postData); + }); - findInviteButton().vm.$emit('click'); + it('displays the successful toastMessage', () => { + expect(wrapper.vm.showToastMessageSuccess).toHaveBeenCalled(); + }); }); - it('displays the api error message for the toastMessage', () => { - expect(wrapper.vm.$toast.show).toHaveBeenCalledWith( - apiErrorMessage, - wrapper.vm.toastOptions, - ); + describe('when any invite failed for any reason', () => { + beforeEach(() => { + wrapper = createComponent({ newUsersToInvite: [user1, user2] }); + + wrapper.vm.$toast = { show: jest.fn() }; + jest + .spyOn(Api, 'addGroupMembersByUserId') + .mockRejectedValue({ response: { data: { success: false } } }); + jest.spyOn(wrapper.vm, 'showToastMessageError'); + + clickInviteButton(); + }); + + it('displays the generic error toastMessage', async () => { + await waitForPromises(); + + expect(wrapper.vm.showToastMessageError).toHaveBeenCalled(); + }); }); }); - describe('when sending the invite for multiple members returned any error', () => { - const genericErrorMessage = 'Some of the members could not be added'; + describe('when inviting members and non-members in same click', () => { + const postData = { + access_level: '10', + expires_at: undefined, + format: 'json', + }; + + const emailPostData = { ...postData, email: 'email@example.com' }; + const idPostData = { ...postData, user_id: '1' }; + + describe('when invites are sent successfully', () => { + beforeEach(() => { + wrapper = createComponent({ newUsersToInvite: [user1, user3] }); + + wrapper.vm.$toast = { show: jest.fn() }; + jest.spyOn(Api, 'inviteGroupMembersByEmail').mockResolvedValue({ data: postData }); + jest.spyOn(Api, 'addGroupMembersByUserId').mockResolvedValue({ data: postData }); + jest.spyOn(wrapper.vm, 'showToastMessageSuccess'); - beforeEach(() => { - wrapper = createComponent({ newUsersToInvite: '123' }); + clickInviteButton(); + }); - wrapper.vm.$toast = { show: jest.fn() }; - jest - .spyOn(Api, 'inviteGroupMember') - .mockRejectedValue({ response: { data: { success: false } } }); + it('calls Api inviteGroupMembersByEmail with the correct params', () => { + expect(Api.inviteGroupMembersByEmail).toHaveBeenCalledWith(id, emailPostData); + }); - findInviteButton().vm.$emit('click'); + it('calls Api addGroupMembersByUserId with the correct params', () => { + expect(Api.addGroupMembersByUserId).toHaveBeenCalledWith(id, idPostData); + }); + + it('displays the successful toastMessage', () => { + expect(wrapper.vm.showToastMessageSuccess).toHaveBeenCalled(); + }); }); - it('displays the expected toastMessage', () => { - expect(wrapper.vm.$toast.show).toHaveBeenCalledWith( - genericErrorMessage, - wrapper.vm.toastOptions, - ); + describe('when any invite failed for any reason', () => { + beforeEach(() => { + wrapper = createComponent({ newUsersToInvite: [user1, user3] }); + + wrapper.vm.$toast = { show: jest.fn() }; + + jest + .spyOn(Api, 'inviteGroupMembersByEmail') + .mockRejectedValue({ response: { data: { success: false } } }); + + jest.spyOn(Api, 'addGroupMembersByUserId').mockResolvedValue({ data: postData }); + jest.spyOn(wrapper.vm, 'showToastMessageError'); + + clickInviteButton(); + }); + + it('displays the generic error toastMessage', async () => { + await waitForPromises(); + + expect(wrapper.vm.showToastMessageError).toHaveBeenCalled(); + }); }); }); }); diff --git a/spec/frontend/invite_members/components/members_token_select_spec.js b/spec/frontend/invite_members/components/members_token_select_spec.js index 106a2df783d..ff123a13ce7 100644 --- a/spec/frontend/invite_members/components/members_token_select_spec.js +++ b/spec/frontend/invite_members/components/members_token_select_spec.js @@ -3,13 +3,13 @@ import { nextTick } from 'vue'; import { GlTokenSelector } from '@gitlab/ui'; import waitForPromises from 'helpers/wait_for_promises'; import { stubComponent } from 'helpers/stub_component'; -import Api from '~/api'; +import * as UserApi from '~/api/user_api'; import MembersTokenSelect from '~/invite_members/components/members_token_select.vue'; const label = 'testgroup'; const placeholder = 'Search for a member'; -const user1 = { id: 1, name: 'Name One', username: 'one_1', avatar_url: '' }; -const user2 = { id: 2, name: 'Name Two', username: 'two_2', avatar_url: '' }; +const user1 = { id: 1, name: 'John Smith', username: 'one_1', avatar_url: '' }; +const user2 = { id: 2, name: 'Jane Doe', username: 'two_2', avatar_url: '' }; const allUsers = [user1, user2]; const createComponent = () => { @@ -28,7 +28,7 @@ describe('MembersTokenSelect', () => { let wrapper; beforeEach(() => { - jest.spyOn(Api, 'users').mockResolvedValue({ data: allUsers }); + jest.spyOn(UserApi, 'getUsers').mockResolvedValue({ data: allUsers }); wrapper = createComponent(); }); @@ -57,7 +57,7 @@ describe('MembersTokenSelect', () => { await waitForPromises(); - expect(Api.users).not.toHaveBeenCalled(); + expect(UserApi.getUsers).not.toHaveBeenCalled(); }); }); @@ -77,27 +77,42 @@ describe('MembersTokenSelect', () => { }); describe('when text input is typed in', () => { + let tokenSelector; + + beforeEach(() => { + tokenSelector = findTokenSelector(); + }); + it('calls the API with search parameter', async () => { const searchParam = 'One'; - const tokenSelector = findTokenSelector(); tokenSelector.vm.$emit('text-input', searchParam); await waitForPromises(); - expect(Api.users).toHaveBeenCalledWith(searchParam, wrapper.vm.$options.queryOptions); + expect(UserApi.getUsers).toHaveBeenCalledWith( + searchParam, + wrapper.vm.$options.queryOptions, + ); expect(tokenSelector.props('hideDropdownWithNoItems')).toBe(false); }); + + describe('when input text is an email', () => { + it('allows user defined tokens', async () => { + tokenSelector.vm.$emit('text-input', 'foo@bar.com'); + + await nextTick(); + + expect(tokenSelector.props('allowUserDefinedTokens')).toBe(true); + }); + }); }); describe('when user is selected', () => { it('emits `input` event with selected users', () => { - findTokenSelector().vm.$emit('input', [ - { id: 1, name: 'John Smith' }, - { id: 2, name: 'Jane Doe' }, - ]); + findTokenSelector().vm.$emit('input', [user1, user2]); - expect(wrapper.emitted().input[0][0]).toBe('1,2'); + expect(wrapper.emitted().input[0][0]).toEqual([user1, user2]); }); }); }); |