diff options
Diffstat (limited to 'spec/frontend/invite_members')
-rw-r--r-- | spec/frontend/invite_members/components/invite_members_modal_spec.js | 87 | ||||
-rw-r--r-- | spec/frontend/invite_members/components/members_token_select_spec.js | 112 |
2 files changed, 181 insertions, 18 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 0be0fbbde2d..4ac2a28105c 100644 --- a/spec/frontend/invite_members/components/invite_members_modal_spec.js +++ b/spec/frontend/invite_members/components/invite_members_modal_spec.js @@ -3,24 +3,31 @@ import { GlDropdown, GlDropdownItem, GlDatepicker, GlSprintf, GlLink } from '@gi import Api from '~/api'; import InviteMembersModal from '~/invite_members/components/invite_members_modal.vue'; -const groupId = '1'; -const groupName = 'testgroup'; +const id = '1'; +const name = 'testgroup'; +const isProject = false; const accessLevels = { Guest: 10, Reporter: 20, Developer: 30, Maintainer: 40, Owner: 50 }; const defaultAccessLevel = '10'; const helpLink = 'https://example.com'; -const createComponent = () => { +const createComponent = (data = {}) => { return shallowMount(InviteMembersModal, { propsData: { - groupId, - groupName, + id, + name, + isProject, accessLevels, defaultAccessLevel, helpLink, }, + data() { + return data; + }, stubs: { - GlSprintf, 'gl-modal': '<div><slot name="modal-footer"></slot><slot></slot></div>', + 'gl-dropdown': true, + 'gl-dropdown-item': true, + GlSprintf, }, }); }; @@ -34,7 +41,7 @@ describe('InviteMembersModal', () => { }); const findDropdown = () => wrapper.find(GlDropdown); - const findDropdownItems = () => wrapper.findAll(GlDropdownItem); + const findDropdownItems = () => findDropdown().findAll(GlDropdownItem); const findDatepicker = () => wrapper.find(GlDatepicker); const findLink = () => wrapper.find(GlLink); const findCancelButton = () => wrapper.find({ ref: 'cancelButton' }); @@ -88,25 +95,69 @@ describe('InviteMembersModal', () => { format: 'json', }; - beforeEach(() => { - wrapper = createComponent(); + describe('when the invite was sent successfully', () => { + beforeEach(() => { + wrapper = createComponent(); + + wrapper.vm.$toast = { show: jest.fn() }; + jest.spyOn(Api, 'inviteGroupMember').mockResolvedValue({ data: postData }); - jest.spyOn(Api, 'inviteGroupMember').mockResolvedValue({ data: postData }); - wrapper.vm.$toast = { show: jest.fn() }; + wrapper.vm.submitForm(postData); + }); - wrapper.vm.submitForm(postData); + it('displays the successful toastMessage', () => { + const toastMessageSuccessful = 'Members were successfully added'; + + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith( + toastMessageSuccessful, + wrapper.vm.toastOptions, + ); + }); + + it('calls Api inviteGroupMember with the correct params', () => { + expect(Api.inviteGroupMember).toHaveBeenCalledWith(id, postData); + }); }); - it('calls Api inviteGroupMember with the correct params', () => { - expect(Api.inviteGroupMember).toHaveBeenCalledWith(groupId, postData); + describe('when sending the invite for a single member returned an api error', () => { + const apiErrorMessage = 'Members already exists'; + + beforeEach(() => { + wrapper = createComponent({ newUsersToInvite: '123' }); + + wrapper.vm.$toast = { show: jest.fn() }; + jest + .spyOn(Api, 'inviteGroupMember') + .mockRejectedValue({ response: { data: { message: apiErrorMessage } } }); + + findInviteButton().vm.$emit('click'); + }); + + it('displays the api error message for the toastMessage', () => { + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith( + apiErrorMessage, + wrapper.vm.toastOptions, + ); + }); }); - describe('when the invite was sent successfully', () => { - const toastMessageSuccessful = 'Users were succesfully added'; + describe('when sending the invite for multiple members returned any error', () => { + const genericErrorMessage = 'Some of the members could not be added'; - it('displays the successful toastMessage', () => { + beforeEach(() => { + wrapper = createComponent({ newUsersToInvite: '123' }); + + wrapper.vm.$toast = { show: jest.fn() }; + jest + .spyOn(Api, 'inviteGroupMember') + .mockRejectedValue({ response: { data: { success: false } } }); + + findInviteButton().vm.$emit('click'); + }); + + it('displays the expected toastMessage', () => { expect(wrapper.vm.$toast.show).toHaveBeenCalledWith( - toastMessageSuccessful, + genericErrorMessage, wrapper.vm.toastOptions, ); }); diff --git a/spec/frontend/invite_members/components/members_token_select_spec.js b/spec/frontend/invite_members/components/members_token_select_spec.js new file mode 100644 index 00000000000..fb0bd6bb195 --- /dev/null +++ b/spec/frontend/invite_members/components/members_token_select_spec.js @@ -0,0 +1,112 @@ +import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import { GlTokenSelector } from '@gitlab/ui'; +import waitForPromises from 'helpers/wait_for_promises'; +import Api from '~/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 allUsers = [user1, user2]; + +const createComponent = () => { + return shallowMount(MembersTokenSelect, { + propsData: { + ariaLabelledby: label, + placeholder, + }, + }); +}; + +describe('MembersTokenSelect', () => { + let wrapper; + + beforeEach(() => { + jest.spyOn(Api, 'users').mockResolvedValue({ data: allUsers }); + wrapper = createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + const findTokenSelector = () => wrapper.find(GlTokenSelector); + + describe('rendering the token-selector component', () => { + it('renders with the correct props', () => { + const expectedProps = { + ariaLabelledby: label, + placeholder, + }; + + expect(findTokenSelector().props()).toEqual(expect.objectContaining(expectedProps)); + }); + }); + + describe('users', () => { + describe('when input is focused for the first time (modal auto-focus)', () => { + it('does not call the API', async () => { + findTokenSelector().vm.$emit('focus'); + + await waitForPromises(); + + expect(Api.users).not.toHaveBeenCalled(); + }); + }); + + describe('when input is manually focused', () => { + it('calls the API and sets dropdown items as request result', async () => { + const tokenSelector = findTokenSelector(); + + tokenSelector.vm.$emit('focus'); + tokenSelector.vm.$emit('blur'); + tokenSelector.vm.$emit('focus'); + + await waitForPromises(); + + expect(tokenSelector.props('dropdownItems')).toMatchObject(allUsers); + expect(tokenSelector.props('hideDropdownWithNoItems')).toBe(false); + }); + }); + + describe('when text input is typed in', () => { + 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(tokenSelector.props('hideDropdownWithNoItems')).toBe(false); + }); + }); + + 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' }, + ]); + + expect(wrapper.emitted().input[0][0]).toBe('1,2'); + }); + }); + }); + + describe('when text input is blurred', () => { + it('clears text input', async () => { + const tokenSelector = findTokenSelector(); + + tokenSelector.vm.$emit('blur'); + + await nextTick(); + + expect(tokenSelector.props('hideDropdownWithNoItems')).toBe(false); + }); + }); +}); |