diff options
Diffstat (limited to 'spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js')
-rw-r--r-- | spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js b/spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js new file mode 100644 index 00000000000..1e47953a510 --- /dev/null +++ b/spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js @@ -0,0 +1,150 @@ +import { mount, createWrapper, createLocalVue } from '@vue/test-utils'; +import Vuex from 'vuex'; +import { nextTick } from 'vue'; +import { within } from '@testing-library/dom'; +import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils'; +import waitForPromises from 'helpers/wait_for_promises'; +import RoleDropdown from '~/vue_shared/components/members/table/role_dropdown.vue'; +import { member } from '../mock_data'; + +const localVue = createLocalVue(); +localVue.use(Vuex); + +describe('RoleDropdown', () => { + let wrapper; + let actions; + const $toast = { + show: jest.fn(), + }; + + const createStore = () => { + actions = { + updateMemberRole: jest.fn(() => Promise.resolve()), + }; + + return new Vuex.Store({ actions }); + }; + + const createComponent = (propsData = {}) => { + wrapper = mount(RoleDropdown, { + propsData: { + member, + ...propsData, + }, + localVue, + store: createStore(), + mocks: { + $toast, + }, + }); + }; + + const getDropdownMenu = () => within(wrapper.element).getByRole('menu'); + const getByTextInDropdownMenu = (text, options = {}) => + createWrapper(within(getDropdownMenu()).getByText(text, options)); + const getDropdownItemByText = text => + createWrapper( + within(getDropdownMenu()) + .getByText(text, { selector: '[role="menuitem"] p' }) + .closest('[role="menuitem"]'), + ); + const getCheckedDropdownItem = () => + wrapper + .findAll(GlDropdownItem) + .wrappers.find(dropdownItemWrapper => dropdownItemWrapper.props('isChecked')); + + const findDropdownToggle = () => wrapper.find('button[aria-haspopup="true"]'); + const findDropdown = () => wrapper.find(GlDropdown); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('when dropdown is open', () => { + beforeEach(done => { + createComponent(); + + findDropdownToggle().trigger('click'); + wrapper.vm.$root.$on('bv::dropdown::shown', () => { + done(); + }); + }); + + it('renders all valid roles', () => { + Object.keys(member.validRoles).forEach(role => { + expect(getDropdownItemByText(role).exists()).toBe(true); + }); + }); + + it('renders dropdown header', () => { + expect(getByTextInDropdownMenu('Change permissions').exists()).toBe(true); + }); + + it('sets dropdown toggle and checks selected role', () => { + expect(findDropdownToggle().text()).toBe('Owner'); + expect(getCheckedDropdownItem().text()).toBe('Owner'); + }); + + describe('when dropdown item is selected', () => { + it('does nothing if the item selected was already selected', () => { + getDropdownItemByText('Owner').trigger('click'); + + expect(actions.updateMemberRole).not.toHaveBeenCalled(); + }); + + it('calls `updateMemberRole` Vuex action', () => { + getDropdownItemByText('Developer').trigger('click'); + + expect(actions.updateMemberRole).toHaveBeenCalledWith(expect.any(Object), { + memberId: member.id, + accessLevel: { integerValue: 30, stringValue: 'Developer' }, + }); + }); + + it('displays toast when successful', async () => { + getDropdownItemByText('Developer').trigger('click'); + + await waitForPromises(); + + expect($toast.show).toHaveBeenCalledWith('Role updated successfully.'); + }); + + it('disables dropdown while waiting for `updateMemberRole` to resolve', async () => { + getDropdownItemByText('Developer').trigger('click'); + + await nextTick(); + + expect(findDropdown().attributes('disabled')).toBe('disabled'); + + await waitForPromises(); + + expect(findDropdown().attributes('disabled')).toBeUndefined(); + }); + }); + }); + + it("sets initial dropdown toggle value to member's role", () => { + createComponent(); + + expect(findDropdownToggle().text()).toBe('Owner'); + }); + + it('sets the dropdown alignment to right on mobile', async () => { + jest.spyOn(bp, 'isDesktop').mockReturnValue(false); + createComponent(); + + await nextTick(); + + expect(findDropdown().attributes('right')).toBe('true'); + }); + + it('sets the dropdown alignment to left on desktop', async () => { + jest.spyOn(bp, 'isDesktop').mockReturnValue(true); + createComponent(); + + await nextTick(); + + expect(findDropdown().attributes('right')).toBeUndefined(); + }); +}); |