Commit a7b25a29 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera

Merge branch 'peterhegman/vue-group-members-update-qa-selectors' into 'master'

Add missing QA selectors for Vue group members view

See merge request gitlab-org/gitlab!47101
parents 15c03f1a 3f50a5d4
...@@ -5,7 +5,7 @@ import { parseDataAttributes } from 'ee_else_ce/groups/members/utils'; ...@@ -5,7 +5,7 @@ import { parseDataAttributes } from 'ee_else_ce/groups/members/utils';
import App from './components/app.vue'; import App from './components/app.vue';
import membersModule from '~/vuex_shared/modules/members'; import membersModule from '~/vuex_shared/modules/members';
export const initGroupMembersApp = (el, tableFields, requestFormatter) => { export const initGroupMembersApp = (el, tableFields, tableAttrs, requestFormatter) => {
if (!el) { if (!el) {
return () => {}; return () => {};
} }
...@@ -18,6 +18,7 @@ export const initGroupMembersApp = (el, tableFields, requestFormatter) => { ...@@ -18,6 +18,7 @@ export const initGroupMembersApp = (el, tableFields, requestFormatter) => {
...parseDataAttributes(el), ...parseDataAttributes(el),
currentUserId: gon.current_user_id || null, currentUserId: gon.current_user_id || null,
tableFields, tableFields,
tableAttrs,
requestFormatter, requestFormatter,
}), }),
}); });
......
...@@ -25,21 +25,25 @@ const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions'] ...@@ -25,21 +25,25 @@ const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions']
initGroupMembersApp( initGroupMembersApp(
document.querySelector('.js-group-members-list'), document.querySelector('.js-group-members-list'),
SHARED_FIELDS.concat(['source', 'granted']), SHARED_FIELDS.concat(['source', 'granted']),
{ tr: { 'data-qa-selector': 'member_row' } },
memberRequestFormatter, memberRequestFormatter,
); );
initGroupMembersApp( initGroupMembersApp(
document.querySelector('.js-group-linked-list'), document.querySelector('.js-group-linked-list'),
SHARED_FIELDS.concat('granted'), SHARED_FIELDS.concat('granted'),
{ table: { 'data-qa-selector': 'groups_list' }, tr: { 'data-qa-selector': 'group_row' } },
groupLinkRequestFormatter, groupLinkRequestFormatter,
); );
initGroupMembersApp( initGroupMembersApp(
document.querySelector('.js-group-invited-members-list'), document.querySelector('.js-group-invited-members-list'),
SHARED_FIELDS.concat('invited'), SHARED_FIELDS.concat('invited'),
{},
memberRequestFormatter, memberRequestFormatter,
); );
initGroupMembersApp( initGroupMembersApp(
document.querySelector('.js-group-access-requests-list'), document.querySelector('.js-group-access-requests-list'),
SHARED_FIELDS.concat('requested'), SHARED_FIELDS.concat('requested'),
{},
memberRequestFormatter, memberRequestFormatter,
); );
......
...@@ -39,7 +39,7 @@ export default { ...@@ -39,7 +39,7 @@ export default {
), ),
}, },
computed: { computed: {
...mapState(['members', 'tableFields', 'currentUserId', 'sourceId']), ...mapState(['members', 'tableFields', 'tableAttrs', 'currentUserId', 'sourceId']),
filteredFields() { filteredFields() {
return FIELDS.filter(field => this.tableFields.includes(field.key) && this.showField(field)); return FIELDS.filter(field => this.tableFields.includes(field.key) && this.showField(field));
}, },
...@@ -79,6 +79,7 @@ export default { ...@@ -79,6 +79,7 @@ export default {
<template> <template>
<div> <div>
<gl-table <gl-table
v-bind="tableAttrs.table"
class="members-table" class="members-table"
data-testid="members-table" data-testid="members-table"
head-variant="white" head-variant="white"
...@@ -89,6 +90,7 @@ export default { ...@@ -89,6 +90,7 @@ export default {
thead-class="border-bottom" thead-class="border-bottom"
:empty-text="__('No members found')" :empty-text="__('No members found')"
show-empty show-empty
:tbody-tr-attr="tableAttrs.tr"
> >
<template #cell(account)="{ item: member }"> <template #cell(account)="{ item: member }">
<members-table-cell #default="{ memberType, isCurrentUser }" :member="member"> <members-table-cell #default="{ memberType, isCurrentUser }" :member="member">
......
...@@ -35,6 +35,14 @@ export default { ...@@ -35,6 +35,14 @@ export default {
}, },
mounted() { mounted() {
this.isDesktop = bp.isDesktop(); this.isDesktop = bp.isDesktop();
// Bootstrap Vue and GlDropdown to not support adding attributes to the dropdown toggle
// This can be changed once https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1060 is implemented
const dropdownToggle = this.$refs.glDropdown.$el.querySelector('.dropdown-toggle');
if (dropdownToggle) {
dropdownToggle.setAttribute('data-qa-selector', 'access_level_dropdown');
}
}, },
methods: { methods: {
...mapActions(['updateMemberRole']), ...mapActions(['updateMemberRole']),
...@@ -63,6 +71,7 @@ export default { ...@@ -63,6 +71,7 @@ export default {
<template> <template>
<gl-dropdown <gl-dropdown
ref="glDropdown"
:right="!isDesktop" :right="!isDesktop"
:text="member.accessLevel.stringValue" :text="member.accessLevel.stringValue"
:header-text="__('Change permissions')" :header-text="__('Change permissions')"
...@@ -73,6 +82,7 @@ export default { ...@@ -73,6 +82,7 @@ export default {
:key="value" :key="value"
is-check-item is-check-item
:is-checked="value === member.accessLevel.integerValue" :is-checked="value === member.accessLevel.integerValue"
data-qa-selector="access_level_link"
@click="handleSelect(value, name)" @click="handleSelect(value, name)"
> >
{{ name }} {{ name }}
......
...@@ -3,6 +3,7 @@ export default ({ ...@@ -3,6 +3,7 @@ export default ({
sourceId, sourceId,
currentUserId, currentUserId,
tableFields, tableFields,
tableAttrs,
memberPath, memberPath,
requestFormatter, requestFormatter,
}) => ({ }) => ({
...@@ -10,6 +11,7 @@ export default ({ ...@@ -10,6 +11,7 @@ export default ({
sourceId, sourceId,
currentUserId, currentUserId,
tableFields, tableFields,
tableAttrs,
memberPath, memberPath,
requestFormatter, requestFormatter,
showError: false, showError: false,
......
...@@ -6,7 +6,7 @@ describe('initGroupMembersApp', () => { ...@@ -6,7 +6,7 @@ describe('initGroupMembersApp', () => {
let vm; let vm;
const createVm = () => { const createVm = () => {
vm = initGroupMembersApp(el, ['account'], () => ({})); vm = initGroupMembersApp(el, ['account'], {}, () => ({}));
}; };
beforeEach(() => { beforeEach(() => {
......
...@@ -15,6 +15,10 @@ describe('MemberList', () => { ...@@ -15,6 +15,10 @@ describe('MemberList', () => {
state: { state: {
members: [], members: [],
tableFields: [], tableFields: [],
tableAttrs: {
table: { 'data-qa-selector': 'members_list' },
tr: { 'data-qa-selector': 'member_row' },
},
sourceId: 1, sourceId: 1,
currentUserId: 1, currentUserId: 1,
...state, ...state,
......
...@@ -16,17 +16,24 @@ module QA ...@@ -16,17 +16,24 @@ module QA
element :invite_member_button element :invite_member_button
end end
view 'app/views/shared/members/_member.html.haml' do view 'app/assets/javascripts/pages/groups/group_members/index.js' do
element :member_row element :member_row
element :groups_list
element :group_row
end
view 'app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue' do
element :access_level_dropdown element :access_level_dropdown
element :access_level_link
end
view 'app/assets/javascripts/vue_shared/components/members/action_buttons/remove_member_button.vue' do
element :delete_member_button element :delete_member_button
element :developer_access_level_link, 'qa_selector: "#{role.downcase}_access_level_link"' # rubocop:disable QA/ElementWithPattern, Lint/InterpolationCheck
end end
view 'app/views/groups/group_members/index.html.haml' do view 'app/views/groups/group_members/index.html.haml' do
element :invite_group_tab element :invite_group_tab
element :groups_list_tab element :groups_list_tab
element :groups_list
end end
view 'app/views/shared/members/_invite_group.html.haml' do view 'app/views/shared/members/_invite_group.html.haml' do
...@@ -34,10 +41,6 @@ module QA ...@@ -34,10 +41,6 @@ module QA
element :invite_group_button element :invite_group_button
end end
view 'app/views/shared/members/_group.html.haml' do
element :group_row
end
def select_group(group_name) def select_group(group_name)
click_element :group_select_field click_element :group_select_field
search_and_select(group_name) search_and_select(group_name)
...@@ -57,7 +60,7 @@ module QA ...@@ -57,7 +60,7 @@ module QA
def update_access_level(username, access_level) def update_access_level(username, access_level)
within_element(:member_row, text: username) do within_element(:member_row, text: username) do
click_element :access_level_dropdown click_element :access_level_dropdown
click_element "#{access_level.downcase}_access_level_link" click_element :access_level_link, text: access_level
end end
end end
......
...@@ -85,8 +85,10 @@ module QA ...@@ -85,8 +85,10 @@ module QA
it_behaves_like 'audit event', ['Changed name'] it_behaves_like 'audit event', ['Changed name']
end end
context 'Add user, change access level, remove user', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/734' do context 'Add user, change access level, remove user', :requires_admin, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/734' do
before do before do
Runtime::Feature.enable('vue_group_members_list', group: group)
sign_in sign_in
group.visit! group.visit!
Page::Group::Menu.perform(&:click_group_members_item) Page::Group::Menu.perform(&:click_group_members_item)
...@@ -97,6 +99,10 @@ module QA ...@@ -97,6 +99,10 @@ module QA
end end
end end
after do
Runtime::Feature.disable('vue_group_members_list', group: group)
end
it_behaves_like 'audit event', ['Added user access as Guest', 'Changed access level', 'Removed user access'] it_behaves_like 'audit event', ['Added user access as Guest', 'Changed access level', 'Removed user access']
end end
......
...@@ -32,6 +32,11 @@ module QA ...@@ -32,6 +32,11 @@ module QA
before do before do
source_group_with_members.add_member(maintainer_user, Resource::Members::AccessLevel::MAINTAINER) source_group_with_members.add_member(maintainer_user, Resource::Members::AccessLevel::MAINTAINER)
Runtime::Feature.enable('vue_group_members_list', group: target_group_with_project)
end
after do
Runtime::Feature.disable('vue_group_members_list', group: target_group_with_project)
end end
it 'can be shared with another group with correct access level', :requires_admin, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/945' do it 'can be shared with another group with correct access level', :requires_admin, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/945' do
......
...@@ -9,7 +9,12 @@ describe('initGroupMembersApp', () => { ...@@ -9,7 +9,12 @@ describe('initGroupMembersApp', () => {
let wrapper; let wrapper;
const setup = () => { const setup = () => {
vm = initGroupMembersApp(el, ['account'], () => ({})); vm = initGroupMembersApp(
el,
['account'],
{ table: { 'data-qa-selector': 'members_list' } },
() => ({}),
);
wrapper = createWrapper(vm); wrapper = createWrapper(vm);
}; };
...@@ -68,6 +73,12 @@ describe('initGroupMembersApp', () => { ...@@ -68,6 +73,12 @@ describe('initGroupMembersApp', () => {
expect(vm.$store.state.tableFields).toEqual(['account']); expect(vm.$store.state.tableFields).toEqual(['account']);
}); });
it('sets `tableAttrs` in Vuex store', () => {
setup();
expect(vm.$store.state.tableAttrs).toEqual({ table: { 'data-qa-selector': 'members_list' } });
});
it('sets `requestFormatter` in Vuex store', () => { it('sets `requestFormatter` in Vuex store', () => {
setup(); setup();
......
...@@ -5,7 +5,7 @@ import { ...@@ -5,7 +5,7 @@ import {
getByTestId as getByTestIdHelper, getByTestId as getByTestIdHelper,
within, within,
} from '@testing-library/dom'; } from '@testing-library/dom';
import { GlBadge } from '@gitlab/ui'; import { GlBadge, GlTable } from '@gitlab/ui';
import MembersTable from '~/vue_shared/components/members/table/members_table.vue'; import MembersTable from '~/vue_shared/components/members/table/members_table.vue';
import MemberAvatar from '~/vue_shared/components/members/table/member_avatar.vue'; import MemberAvatar from '~/vue_shared/components/members/table/member_avatar.vue';
import MemberSource from '~/vue_shared/components/members/table/member_source.vue'; import MemberSource from '~/vue_shared/components/members/table/member_source.vue';
...@@ -28,6 +28,10 @@ describe('MemberList', () => { ...@@ -28,6 +28,10 @@ describe('MemberList', () => {
state: { state: {
members: [], members: [],
tableFields: [], tableFields: [],
tableAttrs: {
table: { 'data-qa-selector': 'members_list' },
tr: { 'data-qa-selector': 'member_row' },
},
sourceId: 1, sourceId: 1,
currentUserId: 1, currentUserId: 1,
...state, ...state,
...@@ -58,6 +62,8 @@ describe('MemberList', () => { ...@@ -58,6 +62,8 @@ describe('MemberList', () => {
const getByTestId = (id, options) => const getByTestId = (id, options) =>
createWrapper(getByTestIdHelper(wrapper.element, id, options)); createWrapper(getByTestIdHelper(wrapper.element, id, options));
const findTable = () => wrapper.find(GlTable);
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null; wrapper = null;
...@@ -187,4 +193,20 @@ describe('MemberList', () => { ...@@ -187,4 +193,20 @@ describe('MemberList', () => {
expect(initUserPopoversMock).toHaveBeenCalled(); expect(initUserPopoversMock).toHaveBeenCalled();
}); });
it('adds QA selector to table', () => {
createComponent();
expect(findTable().attributes('data-qa-selector')).toBe('members_list');
});
it('adds QA selector to table row', () => {
createComponent();
expect(
findTable()
.find('tbody tr')
.attributes('data-qa-selector'),
).toBe('member_row');
});
}); });
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