debian-mirror-gitlab/spec/frontend/members/components/table/role_dropdown_spec.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

254 lines
7.5 KiB
JavaScript
Raw Normal View History

2021-01-03 14:25:43 +05:30
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
2023-06-20 00:43:36 +05:30
import * as Sentry from '@sentry/browser';
2021-03-11 19:13:27 +05:30
import { within } from '@testing-library/dom';
2022-04-04 11:22:00 +05:30
import { mount, createWrapper } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
2021-03-11 19:13:27 +05:30
import Vuex from 'vuex';
2023-03-17 16:20:25 +05:30
import waitForPromises from 'helpers/wait_for_promises';
2021-02-22 17:27:13 +05:30
import RoleDropdown from '~/members/components/table/role_dropdown.vue';
2021-04-29 21:17:54 +05:30
import { MEMBER_TYPES } from '~/members/constants';
2023-03-17 16:20:25 +05:30
import { guestOverageConfirmAction } from 'ee_else_ce/members/guest_overage_confirm_action';
2021-02-22 17:27:13 +05:30
import { member } from '../../mock_data';
2021-01-03 14:25:43 +05:30
2022-04-04 11:22:00 +05:30
Vue.use(Vuex);
2023-03-17 16:20:25 +05:30
jest.mock('ee_else_ce/members/guest_overage_confirm_action');
2023-06-20 00:43:36 +05:30
jest.mock('@sentry/browser');
2021-01-03 14:25:43 +05:30
describe('RoleDropdown', () => {
let wrapper;
let actions;
const $toast = {
show: jest.fn(),
};
2023-06-20 00:43:36 +05:30
const createStore = ({ updateMemberRoleReturn = Promise.resolve() } = {}) => {
2021-01-03 14:25:43 +05:30
actions = {
2023-06-20 00:43:36 +05:30
updateMemberRole: jest.fn(() => updateMemberRoleReturn),
2021-01-03 14:25:43 +05:30
};
2021-04-29 21:17:54 +05:30
return new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: { namespaced: true, actions },
},
});
2021-01-03 14:25:43 +05:30
};
2023-06-20 00:43:36 +05:30
const createComponent = (propsData = {}, store = createStore()) => {
2021-01-03 14:25:43 +05:30
wrapper = mount(RoleDropdown, {
2021-04-29 21:17:54 +05:30
provide: {
namespace: MEMBER_TYPES.user,
2023-03-17 16:20:25 +05:30
group: {
name: 'groupname',
path: '/grouppath/',
},
2021-04-29 21:17:54 +05:30
},
2021-01-03 14:25:43 +05:30
propsData: {
member,
2021-01-29 00:20:46 +05:30
permissions: {},
2021-01-03 14:25:43 +05:30
...propsData,
},
2023-06-20 00:43:36 +05:30
store,
2021-01-03 14:25:43 +05:30
mocks: {
$toast,
},
});
};
const getDropdownMenu = () => within(wrapper.element).getByRole('menu');
const getByTextInDropdownMenu = (text, options = {}) =>
createWrapper(within(getDropdownMenu()).getByText(text, options));
2021-03-08 18:12:59 +05:30
const getDropdownItemByText = (text) =>
2021-01-03 14:25:43 +05:30
createWrapper(
within(getDropdownMenu())
.getByText(text, { selector: '[role="menuitem"] p' })
.closest('[role="menuitem"]'),
);
const getCheckedDropdownItem = () =>
wrapper
2022-08-27 11:52:29 +05:30
.findAllComponents(GlDropdownItem)
2021-03-08 18:12:59 +05:30
.wrappers.find((dropdownItemWrapper) => dropdownItemWrapper.props('isChecked'));
2021-01-03 14:25:43 +05:30
2023-05-27 22:25:52 +05:30
const findDropdownToggle = () => wrapper.find('button[aria-haspopup="menu"]');
2022-08-27 11:52:29 +05:30
const findDropdown = () => wrapper.findComponent(GlDropdown);
2021-01-03 14:25:43 +05:30
2023-03-17 16:20:25 +05:30
beforeEach(() => {
gon.features = { showOverageOnRolePromotion: true };
});
2021-01-03 14:25:43 +05:30
describe('when dropdown is open', () => {
2023-06-20 00:43:36 +05:30
beforeEach(async () => {
2023-03-17 16:20:25 +05:30
guestOverageConfirmAction.mockReturnValue(true);
2021-01-03 14:25:43 +05:30
createComponent();
2023-06-20 00:43:36 +05:30
await findDropdownToggle().trigger('click');
2021-01-03 14:25:43 +05:30
});
it('renders all valid roles', () => {
2021-03-08 18:12:59 +05:30
Object.keys(member.validRoles).forEach((role) => {
2021-01-03 14:25:43 +05:30
expect(getDropdownItemByText(role).exists()).toBe(true);
});
});
it('renders dropdown header', () => {
2021-09-04 01:27:46 +05:30
expect(getByTextInDropdownMenu('Change role').exists()).toBe(true);
2021-01-03 14:25:43 +05:30
});
it('sets dropdown toggle and checks selected role', () => {
expect(findDropdownToggle().text()).toBe('Owner');
expect(getCheckedDropdownItem().text()).toBe('Owner');
});
describe('when dropdown item is selected', () => {
2022-07-16 23:28:13 +05:30
it('does nothing if the item selected was already selected', async () => {
await getDropdownItemByText('Owner').trigger('click');
2021-01-03 14:25:43 +05:30
expect(actions.updateMemberRole).not.toHaveBeenCalled();
});
2022-07-16 23:28:13 +05:30
it('calls `updateMemberRole` Vuex action', async () => {
await getDropdownItemByText('Developer').trigger('click');
2021-01-03 14:25:43 +05:30
expect(actions.updateMemberRole).toHaveBeenCalledWith(expect.any(Object), {
memberId: member.id,
accessLevel: { integerValue: 30, stringValue: 'Developer' },
});
});
2023-06-20 00:43:36 +05:30
describe('when updateMemberRole is successful', () => {
it('displays toast', async () => {
await getDropdownItemByText('Developer').trigger('click');
2021-01-03 14:25:43 +05:30
2023-06-20 00:43:36 +05:30
await nextTick();
2021-01-03 14:25:43 +05:30
2023-06-20 00:43:36 +05:30
expect($toast.show).toHaveBeenCalledWith('Role updated successfully.');
});
2021-01-03 14:25:43 +05:30
2023-06-20 00:43:36 +05:30
it('puts dropdown in loading state while waiting for `updateMemberRole` to resolve', async () => {
await getDropdownItemByText('Developer').trigger('click');
expect(findDropdown().props('loading')).toBe(true);
});
it('enables dropdown after `updateMemberRole` resolves', async () => {
await getDropdownItemByText('Developer').trigger('click');
await waitForPromises();
2021-01-03 14:25:43 +05:30
2023-06-20 00:43:36 +05:30
expect(findDropdown().props('disabled')).toBe(false);
});
it('does not log error to Sentry', async () => {
await getDropdownItemByText('Developer').trigger('click');
await waitForPromises();
expect(Sentry.captureException).not.toHaveBeenCalled();
});
2023-03-17 16:20:25 +05:30
});
2023-06-20 00:43:36 +05:30
describe('when updateMemberRole is not successful', () => {
const reason = 'Rejected ☹️';
2021-01-03 14:25:43 +05:30
2023-06-20 00:43:36 +05:30
beforeEach(() => {
createComponent({}, createStore({ updateMemberRoleReturn: Promise.reject(reason) }));
});
2021-01-03 14:25:43 +05:30
2023-06-20 00:43:36 +05:30
it('does not display toast', async () => {
await getDropdownItemByText('Developer').trigger('click');
await nextTick();
expect($toast.show).not.toHaveBeenCalled();
});
it('puts dropdown in loading state while waiting for `updateMemberRole` to resolve', async () => {
await getDropdownItemByText('Developer').trigger('click');
expect(findDropdown().props('loading')).toBe(true);
});
it('enables dropdown after `updateMemberRole` resolves', async () => {
await getDropdownItemByText('Developer').trigger('click');
await waitForPromises();
expect(findDropdown().props('disabled')).toBe(false);
});
it('logs error to Sentry', async () => {
await getDropdownItemByText('Developer').trigger('click');
await waitForPromises();
expect(Sentry.captureException).toHaveBeenCalledWith(reason);
});
2021-01-03 14:25:43 +05:30
});
});
});
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();
2021-02-22 17:27:13 +05:30
expect(findDropdown().props('right')).toBe(true);
2021-01-03 14:25:43 +05:30
});
it('sets the dropdown alignment to left on desktop', async () => {
jest.spyOn(bp, 'isDesktop').mockReturnValue(true);
createComponent();
await nextTick();
2021-02-22 17:27:13 +05:30
expect(findDropdown().props('right')).toBe(false);
2021-01-03 14:25:43 +05:30
});
2023-03-17 16:20:25 +05:30
describe('guestOverageConfirmAction', () => {
const mockConfirmAction = ({ confirmed }) => {
guestOverageConfirmAction.mockResolvedValueOnce(confirmed);
};
beforeEach(() => {
createComponent();
findDropdownToggle().trigger('click');
});
afterEach(() => {
guestOverageConfirmAction.mockReset();
});
describe('when guestOverageConfirmAction returns true', () => {
beforeEach(() => {
mockConfirmAction({ confirmed: true });
getDropdownItemByText('Reporter').trigger('click');
});
it('calls updateMemberRole', () => {
expect(actions.updateMemberRole).toHaveBeenCalled();
});
});
describe('when guestOverageConfirmAction returns false', () => {
beforeEach(() => {
mockConfirmAction({ confirmed: false });
getDropdownItemByText('Reporter').trigger('click');
});
it('does not call updateMemberRole', () => {
expect(actions.updateMemberRole).not.toHaveBeenCalled();
});
});
});
2021-01-03 14:25:43 +05:30
});