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

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

349 lines
11 KiB
JavaScript
Raw Normal View History

2021-06-08 01:23:25 +05:30
import { GlBadge, GlPagination, GlTable } from '@gitlab/ui';
2022-04-04 11:22:00 +05:30
import Vue from 'vue';
2021-03-11 19:13:27 +05:30
import Vuex from 'vuex';
2021-10-27 15:23:28 +05:30
import setWindowLocation from 'helpers/set_window_location_helper';
2021-11-18 22:05:49 +05:30
import { mountExtended, extendedWrapper } from 'helpers/vue_test_utils_helper';
2021-02-22 17:27:13 +05:30
import CreatedAt from '~/members/components/table/created_at.vue';
import ExpirationDatepicker from '~/members/components/table/expiration_datepicker.vue';
import MemberActionButtons from '~/members/components/table/member_action_buttons.vue';
2021-03-11 19:13:27 +05:30
import MemberAvatar from '~/members/components/table/member_avatar.vue';
import MemberSource from '~/members/components/table/member_source.vue';
import MembersTable from '~/members/components/table/members_table.vue';
import RoleDropdown from '~/members/components/table/role_dropdown.vue';
2022-06-21 17:19:12 +05:30
import UserDate from '~/vue_shared/components/user_date.vue';
2021-11-18 22:05:49 +05:30
import {
MEMBER_TYPES,
MEMBER_STATE_CREATED,
MEMBER_STATE_AWAITING,
MEMBER_STATE_ACTIVE,
2022-07-23 23:45:48 +05:30
USER_STATE_BLOCKED,
BADGE_LABELS_AWAITING_SIGNUP,
BADGE_LABELS_PENDING,
2021-11-18 22:05:49 +05:30
TAB_QUERY_PARAM_VALUES,
} from '~/members/constants';
2021-06-08 01:23:25 +05:30
import {
member as memberMock,
directMember,
invite,
accessRequest,
pagination,
} from '../../mock_data';
2021-01-03 14:25:43 +05:30
2022-04-04 11:22:00 +05:30
Vue.use(Vuex);
2021-01-03 14:25:43 +05:30
2021-02-22 17:27:13 +05:30
describe('MembersTable', () => {
2021-01-03 14:25:43 +05:30
let wrapper;
const createStore = (state = {}) => {
return new Vuex.Store({
2021-04-29 21:17:54 +05:30
modules: {
2021-09-30 23:02:18 +05:30
[MEMBER_TYPES.invite]: {
2021-04-29 21:17:54 +05:30
namespaced: true,
state: {
members: [],
tableFields: [],
tableAttrs: {
table: { 'data-qa-selector': 'members_list' },
tr: { 'data-qa-selector': 'member_row' },
},
2021-06-08 01:23:25 +05:30
pagination,
2021-04-29 21:17:54 +05:30
...state,
},
2021-01-29 00:20:46 +05:30
},
2021-01-03 14:25:43 +05:30
},
});
};
2021-04-29 21:17:54 +05:30
const createComponent = (state, provide = {}) => {
2021-11-18 22:05:49 +05:30
wrapper = mountExtended(MembersTable, {
2021-09-30 23:02:18 +05:30
propsData: {
tabQueryParamValue: TAB_QUERY_PARAM_VALUES.invite,
},
2021-01-03 14:25:43 +05:30
store: createStore(state),
2021-04-29 21:17:54 +05:30
provide: {
sourceId: 1,
currentUserId: 1,
2021-09-30 23:02:18 +05:30
namespace: MEMBER_TYPES.invite,
2021-04-29 21:17:54 +05:30
...provide,
},
2021-01-03 14:25:43 +05:30
stubs: [
'member-avatar',
'member-source',
'created-at',
'member-action-buttons',
'role-dropdown',
'remove-group-link-modal',
2021-10-27 15:23:28 +05:30
'remove-member-modal',
2021-01-29 00:20:46 +05:30
'expiration-datepicker',
2021-01-03 14:25:43 +05:30
],
});
};
2021-09-30 23:02:18 +05:30
const url = 'https://localhost/foo-bar/-/project_members?tab=invited';
2021-06-08 01:23:25 +05:30
2022-08-27 11:52:29 +05:30
const findTable = () => wrapper.findComponent(GlTable);
2021-03-08 18:12:59 +05:30
const findTableCellByMemberId = (tableCellLabel, memberId) =>
2021-11-18 22:05:49 +05:30
wrapper
.findByTestId(`members-table-row-${memberId}`)
.find(`[data-label="${tableCellLabel}"][role="cell"]`);
2021-01-29 00:20:46 +05:30
2022-08-27 11:52:29 +05:30
const findPagination = () => extendedWrapper(wrapper.findComponent(GlPagination));
2021-06-08 01:23:25 +05:30
const expectCorrectLinkToPage2 = () => {
expect(findPagination().findByText('2', { selector: 'a' }).attributes('href')).toBe(
2021-09-30 23:02:18 +05:30
`${url}&invited_members_page=2`,
2021-06-08 01:23:25 +05:30
);
};
2021-01-03 14:25:43 +05:30
afterEach(() => {
wrapper.destroy();
});
describe('fields', () => {
2021-01-29 00:20:46 +05:30
const memberCanUpdate = {
...directMember,
canUpdate: true,
};
2021-01-03 14:25:43 +05:30
it.each`
2022-06-21 17:19:12 +05:30
field | label | member | expectedComponent
${'account'} | ${'Account'} | ${memberMock} | ${MemberAvatar}
${'source'} | ${'Source'} | ${memberMock} | ${MemberSource}
${'granted'} | ${'Access granted'} | ${memberMock} | ${CreatedAt}
${'invited'} | ${'Invited'} | ${invite} | ${CreatedAt}
${'requested'} | ${'Requested'} | ${accessRequest} | ${CreatedAt}
${'maxRole'} | ${'Max role'} | ${memberCanUpdate} | ${RoleDropdown}
${'expiration'} | ${'Expiration'} | ${memberMock} | ${ExpirationDatepicker}
${'userCreatedAt'} | ${'Created on'} | ${memberMock} | ${UserDate}
${'lastActivityOn'} | ${'Last activity'} | ${memberMock} | ${UserDate}
2021-01-03 14:25:43 +05:30
`('renders the $label field', ({ field, label, member, expectedComponent }) => {
createComponent({
members: [member],
tableFields: [field],
});
2021-11-18 22:05:49 +05:30
expect(wrapper.findByText(label, { selector: '[role="columnheader"]' }).exists()).toBe(true);
2021-01-03 14:25:43 +05:30
if (expectedComponent) {
expect(
2022-08-27 11:52:29 +05:30
wrapper
.find(`[data-label="${label}"][role="cell"]`)
.findComponent(expectedComponent)
.exists(),
2021-01-03 14:25:43 +05:30
).toBe(true);
}
});
2021-11-18 22:05:49 +05:30
describe('Invited column', () => {
describe.each`
2022-07-23 23:45:48 +05:30
state | userState | expectedBadgeLabel
${MEMBER_STATE_CREATED} | ${null} | ${BADGE_LABELS_AWAITING_SIGNUP}
${MEMBER_STATE_CREATED} | ${USER_STATE_BLOCKED} | ${BADGE_LABELS_PENDING}
${MEMBER_STATE_AWAITING} | ${''} | ${BADGE_LABELS_AWAITING_SIGNUP}
${MEMBER_STATE_AWAITING} | ${USER_STATE_BLOCKED} | ${BADGE_LABELS_PENDING}
${MEMBER_STATE_AWAITING} | ${'something_else'} | ${BADGE_LABELS_PENDING}
${MEMBER_STATE_ACTIVE} | ${null} | ${''}
${MEMBER_STATE_ACTIVE} | ${'something_else'} | ${''}
2021-11-18 22:05:49 +05:30
`('Invited Badge', ({ state, userState, expectedBadgeLabel }) => {
it(`${
expectedBadgeLabel ? 'shows' : 'hides'
} invited badge if user status: '${userState}' and member state: '${state}'`, () => {
createComponent({
members: [
{
...invite,
state,
invite: {
...invite.invite,
userState,
},
},
],
tableFields: ['invited'],
});
const invitedTab = wrapper.findByTestId('invited-badge');
if (expectedBadgeLabel) {
expect(invitedTab.text()).toBe(expectedBadgeLabel);
} else {
expect(invitedTab.exists()).toBe(false);
}
});
});
});
2021-01-29 00:20:46 +05:30
describe('"Actions" field', () => {
it('renders "Actions" field for screen readers', () => {
createComponent({ members: [memberCanUpdate], tableFields: ['actions'] });
2021-01-03 14:25:43 +05:30
2021-11-18 22:05:49 +05:30
const actionField = wrapper.findByTestId('col-actions');
2021-01-03 14:25:43 +05:30
2021-01-29 00:20:46 +05:30
expect(actionField.exists()).toBe(true);
expect(actionField.classes('gl-sr-only')).toBe(true);
expect(
2022-08-27 11:52:29 +05:30
wrapper
.find(`[data-label="Actions"][role="cell"]`)
.findComponent(MemberActionButtons)
.exists(),
2021-01-29 00:20:46 +05:30
).toBe(true);
});
describe('when user is not logged in', () => {
it('does not render the "Actions" field', () => {
2021-04-29 21:17:54 +05:30
createComponent({ tableFields: ['actions'] }, { currentUserId: null });
2021-01-29 00:20:46 +05:30
2021-11-18 22:05:49 +05:30
expect(wrapper.findByTestId('col-actions').exists()).toBe(false);
2021-01-29 00:20:46 +05:30
});
});
const memberCanRemove = {
...directMember,
canRemove: true,
};
2021-03-08 18:12:59 +05:30
const memberNoPermissions = {
...memberMock,
id: 2,
};
2021-01-29 00:20:46 +05:30
describe.each`
permission | members
2021-03-08 18:12:59 +05:30
${'canUpdate'} | ${[memberNoPermissions, memberCanUpdate]}
${'canRemove'} | ${[memberNoPermissions, memberCanRemove]}
${'canResend'} | ${[memberNoPermissions, invite]}
2021-01-29 00:20:46 +05:30
`('when one of the members has $permission permissions', ({ members }) => {
it('renders the "Actions" field', () => {
createComponent({ members, tableFields: ['actions'] });
2021-11-18 22:05:49 +05:30
expect(wrapper.findByTestId('col-actions').exists()).toBe(true);
2021-03-08 18:12:59 +05:30
expect(findTableCellByMemberId('Actions', members[0].id).classes()).toStrictEqual([
'col-actions',
'gl-display-none!',
2021-03-11 19:13:27 +05:30
'gl-lg-display-table-cell!',
2021-03-08 18:12:59 +05:30
]);
expect(findTableCellByMemberId('Actions', members[1].id).classes()).toStrictEqual([
'col-actions',
]);
2021-01-29 00:20:46 +05:30
});
});
describe.each`
permission | members
${'canUpdate'} | ${[memberMock]}
${'canRemove'} | ${[memberMock]}
${'canResend'} | ${[{ ...invite, invite: { ...invite.invite, canResend: false } }]}
`('when none of the members have $permission permissions', ({ members }) => {
it('does not render the "Actions" field', () => {
createComponent({ members, tableFields: ['actions'] });
2021-11-18 22:05:49 +05:30
expect(wrapper.findByTestId('col-actions').exists()).toBe(false);
2021-01-29 00:20:46 +05:30
});
});
2021-01-03 14:25:43 +05:30
});
});
describe('when `members` is an empty array', () => {
it('displays a "No members found" message', () => {
createComponent();
2021-11-18 22:05:49 +05:30
expect(wrapper.findByText('No members found').exists()).toBe(true);
2021-01-03 14:25:43 +05:30
});
});
describe('when member can not be updated', () => {
it('renders badge in "Max role" field', () => {
createComponent({ members: [memberMock], tableFields: ['maxRole'] });
2022-08-27 11:52:29 +05:30
expect(
wrapper.find(`[data-label="Max role"][role="cell"]`).findComponent(GlBadge).text(),
).toBe(memberMock.accessLevel.stringValue);
2021-01-03 14:25:43 +05:30
});
});
2021-01-29 00:20:46 +05:30
it('adds QA selector to table', () => {
createComponent();
expect(findTable().attributes('data-qa-selector')).toBe('members_list');
});
it('adds QA selector to table row', () => {
createComponent();
2021-03-08 18:12:59 +05:30
expect(findTable().find('tbody tr').attributes('data-qa-selector')).toBe('member_row');
2021-01-29 00:20:46 +05:30
});
2021-06-08 01:23:25 +05:30
describe('when required pagination data is provided', () => {
it('renders `gl-pagination` component with correct props', () => {
2021-10-27 15:23:28 +05:30
setWindowLocation(url);
2021-06-08 01:23:25 +05:30
createComponent();
const glPagination = findPagination();
expect(glPagination.exists()).toBe(true);
expect(glPagination.props()).toMatchObject({
value: pagination.currentPage,
perPage: pagination.perPage,
totalItems: pagination.totalItems,
prevText: 'Prev',
nextText: 'Next',
labelNextPage: 'Go to next page',
labelPrevPage: 'Go to previous page',
align: 'center',
});
});
it('uses `pagination.paramName` to generate the pagination links', () => {
2021-10-27 15:23:28 +05:30
setWindowLocation(url);
2021-06-08 01:23:25 +05:30
createComponent({
pagination: {
currentPage: 1,
perPage: 5,
totalItems: 10,
2021-09-30 23:02:18 +05:30
paramName: 'invited_members_page',
2021-06-08 01:23:25 +05:30
},
});
expectCorrectLinkToPage2();
});
it('removes any url params defined as `null` in the `params` attribute', () => {
2021-10-27 15:23:28 +05:30
setWindowLocation(`${url}&search_groups=foo`);
2021-06-08 01:23:25 +05:30
createComponent({
pagination: {
currentPage: 1,
perPage: 5,
totalItems: 10,
2021-09-30 23:02:18 +05:30
paramName: 'invited_members_page',
2021-06-08 01:23:25 +05:30
params: { search_groups: null },
},
});
expectCorrectLinkToPage2();
});
});
describe.each`
attribute | value
${'paramName'} | ${null}
${'currentPage'} | ${null}
${'perPage'} | ${null}
${'totalItems'} | ${0}
`('when pagination.$attribute is $value', ({ attribute, value }) => {
it('does not render `gl-pagination`', () => {
createComponent({
pagination: {
...pagination,
[attribute]: value,
},
});
expect(findPagination().exists()).toBe(false);
});
});
2021-01-03 14:25:43 +05:30
});