Commit a56a7989 authored by Illya Klymov's avatar Illya Klymov

Merge branch...

Merge branch '235603-convert-group-members-list-view-from-haml-to-vue-role-approve-button' into 'master'

Group members Vue conversion - approve access request button

See merge request gitlab-org/gitlab!44676
parents 30fde3b8 e27438b4
<script>
import ActionButtonGroup from './action_button_group.vue';
import RemoveMemberButton from './remove_member_button.vue';
import ApproveAccessRequestButton from './approve_access_request_button.vue';
import { s__, sprintf } from '~/locale';
export default {
name: 'AccessRequestActionButtons',
components: { ActionButtonGroup, RemoveMemberButton },
components: { ActionButtonGroup, RemoveMemberButton, ApproveAccessRequestButton },
props: {
member: {
type: Object,
......@@ -42,7 +43,9 @@ export default {
<template>
<action-button-group>
<!-- Approve button will go here -->
<div v-if="permissions.canUpdate" class="gl-px-1">
<approve-access-request-button :member-id="member.id" />
</div>
<div v-if="permissions.canRemove" class="gl-px-1">
<remove-member-button
:member-id="member.id"
......
<script>
import { mapState } from 'vuex';
import { GlButton, GlForm, GlTooltipDirective } from '@gitlab/ui';
import csrf from '~/lib/utils/csrf';
import { __ } from '~/locale';
export default {
name: 'ApproveAccessRequestButton',
csrf,
title: __('Grant access'),
components: { GlButton, GlForm },
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
memberId: {
type: Number,
required: true,
},
},
computed: {
...mapState(['memberPath']),
approvePath() {
return this.memberPath.replace(/:id$/, `${this.memberId}/approve_access_request`);
},
},
};
</script>
<template>
<gl-form :action="approvePath" method="post">
<input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
<gl-button
v-gl-tooltip.hover
:title="$options.title"
:aria-label="$options.title"
icon="check"
variant="success"
type="submit"
/>
</gl-form>
</template>
import { shallowMount } from '@vue/test-utils';
import AccessRequestActionButtons from '~/vue_shared/components/members/action_buttons/access_request_action_buttons.vue';
import RemoveMemberButton from '~/vue_shared/components/members/action_buttons/remove_member_button.vue';
import ApproveAccessRequestButton from '~/vue_shared/components/members/action_buttons/approve_access_request_button.vue';
import { accessRequest as member } from '../mock_data';
describe('AccessRequestActionButtons', () => {
......@@ -17,6 +18,7 @@ describe('AccessRequestActionButtons', () => {
};
const findRemoveMemberButton = () => wrapper.find(RemoveMemberButton);
const findApproveButton = () => wrapper.find(ApproveAccessRequestButton);
afterEach(() => {
wrapper.destroy();
......@@ -79,4 +81,28 @@ describe('AccessRequestActionButtons', () => {
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);
});
});
});
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 '~/vue_shared/components/members/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',
);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment