mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
MM-54123 Add group to channel (#22954)
* adding group members to channel initial commit * adding group to channel functionality along with add new team members * fixing circular dependency * fixing e2e and other optimizations * adding e2e tests for adding group members to channels * cypress lint * fixing comments * adding count to button * improvements * adjusting some stuff from PR comments * remove ability to add user to team, update message for non-team members * remove adding to team from add groups functionality * update misspelled variable * lint and unit test fixes * add tests, cleanup * lint fix * revert package-lock.json * fixes for cypress tests * rename TeamInviteBanner to TeamWarningBanner, since invites are no longer allowed * update for warning * lint fixes * cleanup * fix failing e2e tests * update messages to not use markdown --------- Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
@@ -10,29 +10,53 @@
|
||||
// Stage: @prod
|
||||
// Group: @channels @channel @channel_settings @smoke
|
||||
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
describe('Channel Settings', () => {
|
||||
let testTeam: Cypress.Team;
|
||||
let firstUser: Cypress.UserProfile;
|
||||
let addedUsersChannel: Cypress.Channel;
|
||||
let username: string;
|
||||
let groupId: string;
|
||||
const usernames: string[] = [];
|
||||
|
||||
const users: Cypress.UserProfile[] = [];
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testTeam = team;
|
||||
firstUser = user;
|
||||
const teamId = testTeam.id;
|
||||
|
||||
// # Add 4 users
|
||||
for (let i = 0; i < 4; i++) {
|
||||
cy.apiCreateUser().then(({user: newUser}) => { // eslint-disable-line
|
||||
cy.apiAddUserToTeam(testTeam.id, newUser.id);
|
||||
// # Add 10 users
|
||||
for (let i = 0; i < 10; i++) {
|
||||
cy.apiCreateUser().then(({user: newUser}) => {
|
||||
users.push(newUser);
|
||||
cy.apiAddUserToTeam(teamId, newUser.id);
|
||||
});
|
||||
}
|
||||
cy.apiCreateChannel(testTeam.id, 'channel-test', 'Channel').then(({channel}) => {
|
||||
cy.apiCreateChannel(teamId, 'channel-test', 'Channel').then(({channel}) => {
|
||||
addedUsersChannel = channel;
|
||||
});
|
||||
|
||||
// # Change permission so that regular users can't add team members
|
||||
cy.apiGetRolesByNames(['team_user']).then((result: any) => {
|
||||
if (result.roles) {
|
||||
const role = result.roles[0];
|
||||
const permissions = role.permissions.filter((permission) => {
|
||||
return !(['add_user_to_team'].includes(permission));
|
||||
});
|
||||
|
||||
if (permissions.length !== role.permissions) {
|
||||
cy.apiPatchRole(role.id, {permissions});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cy.apiLogin(firstUser);
|
||||
}).then(() => {
|
||||
groupId = getRandomId();
|
||||
cy.apiCreateCustomUserGroup(`group${groupId}`, `group${groupId}`, [users[0].id, users[1].id]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,7 +66,7 @@ describe('Channel Settings', () => {
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Add users to channel
|
||||
addNumberOfUsersToChannel(1);
|
||||
addNumberOfUsersToChannel(1, false);
|
||||
|
||||
cy.getLastPostId().then((id) => {
|
||||
// * The system message should contain 'added to the channel by you'
|
||||
@@ -59,7 +83,7 @@ describe('Channel Settings', () => {
|
||||
cy.apiCreateChannel(testTeam.id, 'channel-test', 'Channel').then(({channel}) => {
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
addNumberOfUsersToChannel(3);
|
||||
addNumberOfUsersToChannel(3, false);
|
||||
|
||||
cy.getLastPostId().then((id) => {
|
||||
cy.get(`#postMessageText_${id}`).should('contain', '2 others were added to the channel by you');
|
||||
@@ -82,10 +106,10 @@ describe('Channel Settings', () => {
|
||||
cy.get('#addUsersToChannelModal').should('be.visible');
|
||||
|
||||
// # Type into the input box to search for a user
|
||||
cy.get('#selectItems input').typeWithForce('u');
|
||||
cy.get('#selectItems input').typeWithForce('user');
|
||||
|
||||
// # First add one user in order to see them disappearing from the list
|
||||
cy.get('#multiSelectList > div').first().then((el) => {
|
||||
cy.get('#multiSelectList > div').not(':contains("Already in channel")').first().then((el) => {
|
||||
const childNodes = Array.from(el[0].childNodes);
|
||||
childNodes.map((child: HTMLElement) => usernames.push(child.innerText));
|
||||
|
||||
@@ -113,7 +137,7 @@ describe('Channel Settings', () => {
|
||||
});
|
||||
|
||||
// Add two more users
|
||||
addNumberOfUsersToChannel(2);
|
||||
addNumberOfUsersToChannel(2, false);
|
||||
|
||||
// Verify that the system post reflects the number of added users
|
||||
cy.getLastPostId().then((id) => {
|
||||
@@ -148,6 +172,179 @@ describe('Channel Settings', () => {
|
||||
});
|
||||
cy.get('body').type('{esc}');
|
||||
});
|
||||
|
||||
it('Add group members to channel', () => {
|
||||
cy.apiLogin(firstUser);
|
||||
|
||||
// # Create a new channel
|
||||
cy.apiCreateChannel(testTeam.id, 'new-channel', 'New Channel').then(({channel}) => {
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel menu and click 'Add Members'
|
||||
cy.uiOpenChannelMenu('Add Members');
|
||||
|
||||
// * Assert that modal appears
|
||||
cy.get('#addUsersToChannelModal').should('be.visible');
|
||||
|
||||
// # Type 'group'+ id created in beforeAll into the input box
|
||||
cy.get('#selectItems input').typeWithForce(`group${groupId}`);
|
||||
|
||||
// # Click the first row for a number of times
|
||||
// cy.get('#multiSelectList').should('be.visible').first().click();
|
||||
cy.get('#multiSelectList').should('exist').children().first().click();
|
||||
|
||||
// # Click the button "Add" to add user to a channel
|
||||
cy.uiGetButton('Add').click();
|
||||
|
||||
// # Wait for the modal to disappear
|
||||
cy.get('#addUsersToChannelModal').should('not.exist');
|
||||
|
||||
cy.getLastPostId().then((id) => {
|
||||
// * The system message should contain 'added to the channel by you'
|
||||
cy.get(`#postMessageText_${id}`).should('contain', 'added to the channel by you');
|
||||
|
||||
// # Verify username link
|
||||
verifyMentionedUserAndProfilePopover(id);
|
||||
});
|
||||
|
||||
// * Check that the number of channel members is 3
|
||||
cy.get('#channelMemberCountText').
|
||||
should('be.visible').
|
||||
and('have.text', '3');
|
||||
});
|
||||
});
|
||||
|
||||
it('Add group members that are not team members', () => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Create a new user
|
||||
cy.apiCreateUser().then(({user: newUser}) => {
|
||||
const id = getRandomId();
|
||||
|
||||
// # Create a custom user group
|
||||
cy.apiCreateCustomUserGroup(`newgroup${id}`, `newgroup${id}`, [newUser.id]).then(() => {
|
||||
// # Create a new channel
|
||||
cy.apiCreateChannel(testTeam.id, 'new-group-channel', 'New Group Channel').then(({channel}) => {
|
||||
// # Visit a channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel menu and click 'Add Members'
|
||||
cy.uiOpenChannelMenu('Add Members');
|
||||
|
||||
// * Assert that modal appears
|
||||
cy.get('#addUsersToChannelModal').should('be.visible');
|
||||
|
||||
// # Type 'group' into the input box
|
||||
cy.get('#selectItems input').typeWithForce(`newgroup${id}`);
|
||||
|
||||
// # Click the first row for a number of times
|
||||
// cy.get('#multiSelectList').should('be.visible').first().click();
|
||||
cy.get('#multiSelectList').should('exist').children().first().click();
|
||||
|
||||
// * Check you get a warning when adding a non team member
|
||||
cy.findByTestId('teamWarningBanner').should('contain', '1 user was not selected because they are not a part of this team');
|
||||
|
||||
// * Check the correct username is appearing in the team invite banner
|
||||
cy.findByTestId('teamWarningBanner').should('contain', `@${newUser.username}`);
|
||||
|
||||
// # Click the button "Add" to add user to a channel
|
||||
cy.uiGetButton('Cancel').click();
|
||||
|
||||
// # Wait for the modal to disappear
|
||||
cy.get('#addUsersToChannelModal').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Add group members and guests that are not team members', () => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Create a new user
|
||||
cy.apiCreateUser().then(({user: newUser}) => {
|
||||
// # Create a guest user
|
||||
cy.apiCreateGuestUser({}).then(({guest}) => {
|
||||
const id = getRandomId();
|
||||
|
||||
// # Create a custom user group
|
||||
cy.apiCreateCustomUserGroup(`guestgroup${id}`, `guestgroup${id}`, [guest.id, newUser.id]).then(() => {
|
||||
// # Create a new channel
|
||||
cy.apiCreateChannel(testTeam.id, 'group-guest-channel', 'Channel').then(({channel}) => {
|
||||
// # Visit a channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel menu and click 'Add Members'
|
||||
cy.uiOpenChannelMenu('Add Members');
|
||||
|
||||
// * Assert that modal appears
|
||||
cy.get('#addUsersToChannelModal').should('be.visible');
|
||||
|
||||
// # Type 'group' into the input box
|
||||
cy.get('#selectItems input').typeWithForce(`guestgroup${id}`);
|
||||
|
||||
// # Click the first row for a number of times
|
||||
// cy.get('#multiSelectList').should('be.visible').first().click();
|
||||
cy.get('#multiSelectList').should('exist').children().first().click();
|
||||
|
||||
// * Check you get a warning when adding a non team member
|
||||
cy.findByTestId('teamWarningBanner').should('contain', '2 users were not selected because they are not a part of this team');
|
||||
|
||||
// * Check the correct username is appearing in the invite to team portion
|
||||
cy.findByTestId('teamWarningBanner').should('contain', `@${newUser.username}`);
|
||||
|
||||
// * Check the guest username is in the warning message and won't be added to the team
|
||||
cy.findByTestId('teamWarningBanner').should('contain', `@${guest.username} is a guest user`);
|
||||
|
||||
// # Click the button "Add" to add user to a channel
|
||||
cy.uiGetButton('Cancel').click();
|
||||
|
||||
// # Wait for the modal to disappear
|
||||
cy.get('#addUsersToChannelModal').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('User doesn\'t have permission to add user to team', () => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Create a new user
|
||||
cy.apiCreateUser().then(({user: newUser}) => {
|
||||
const id = getRandomId();
|
||||
|
||||
// # Create a custom user group
|
||||
cy.apiCreateCustomUserGroup(`newgroup${id}`, `newgroup${id}`, [newUser.id]).then(() => {
|
||||
// # Create a new channel
|
||||
cy.apiCreateChannel(testTeam.id, 'new-group-channel', 'Channel').then(({channel}) => {
|
||||
cy.apiLogin(firstUser);
|
||||
|
||||
// # Visit a channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel menu and click 'Add Members'
|
||||
cy.uiOpenChannelMenu('Add Members');
|
||||
|
||||
// * Assert that modal appears
|
||||
cy.get('#addUsersToChannelModal').should('be.visible');
|
||||
|
||||
// # Type 'group' into the input box
|
||||
cy.get('#selectItems input').typeWithForce(`newgroup${id}`);
|
||||
|
||||
// # Click the first row for a number of times
|
||||
// cy.get('#multiSelectList').should('be.visible').first().click();
|
||||
cy.get('#multiSelectList').should('exist').children().first().click();
|
||||
|
||||
// * Check you get a warning when adding a non team member
|
||||
cy.findByTestId('teamWarningBanner').should('contain', '1 user was not selected because they are not a part of this team');
|
||||
|
||||
// * Check the correct username is appearing in the team invite banner
|
||||
cy.findByTestId('teamWarningBanner').should('contain', `@${newUser.username}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function verifyMentionedUserAndProfilePopover(postId: string) {
|
||||
@@ -169,7 +366,7 @@ function verifyMentionedUserAndProfilePopover(postId: string) {
|
||||
});
|
||||
}
|
||||
|
||||
function addNumberOfUsersToChannel(num = 1) {
|
||||
function addNumberOfUsersToChannel(num = 1, allowExisting = false) {
|
||||
// # Open channel menu and click 'Add Members'
|
||||
cy.uiOpenChannelMenu('Add Members');
|
||||
cy.get('#addUsersToChannelModal').should('be.visible');
|
||||
@@ -177,8 +374,14 @@ function addNumberOfUsersToChannel(num = 1) {
|
||||
// * Assert that modal appears
|
||||
// # Click the first row for a number of times
|
||||
Cypress._.times(num, () => {
|
||||
cy.get('#selectItems input').typeWithForce('u');
|
||||
cy.get('#multiSelectList').should('be.visible').first().click();
|
||||
cy.get('#selectItems input').typeWithForce('user');
|
||||
|
||||
// cy.get('#multiSelectList').should('be.visible').first().click();
|
||||
if (allowExisting) {
|
||||
cy.get('#multiSelectList').should('exist').children().first().click();
|
||||
} else {
|
||||
cy.get('#multiSelectList').should('exist').children().not(':contains("Already in channel")').first().click();
|
||||
}
|
||||
});
|
||||
|
||||
// # Click the button "Add" to add user to a channel
|
||||
|
||||
@@ -155,11 +155,11 @@ describe('Verify Accessibility Support in Modals & Dialogs', () => {
|
||||
cy.findByRole('heading', {name: modalName});
|
||||
|
||||
// * Verify the accessibility support in search input
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
cy.findByRole('textbox', {name: 'Search for people or groups'}).
|
||||
should('have.attr', 'aria-autocomplete', 'list');
|
||||
|
||||
// # Search for a text and then check up and down arrow
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
cy.findByRole('textbox', {name: 'Search for people or groups'}).
|
||||
typeWithForce('u').
|
||||
wait(TIMEOUTS.HALF_SEC).
|
||||
typeWithForce('{downarrow}{downarrow}{downarrow}{uparrow}');
|
||||
@@ -184,7 +184,7 @@ describe('Verify Accessibility Support in Modals & Dialogs', () => {
|
||||
});
|
||||
|
||||
// # Search for an invalid text and check if reader can read no results
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
cy.findByRole('textbox', {name: 'Search for people or groups'}).
|
||||
typeWithForce('somethingwhichdoesnotexist').
|
||||
wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ describe('Channel members test', () => {
|
||||
cy.get('#addChannelMembers').click();
|
||||
|
||||
// # Enter user1 and user2 emails
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).typeWithForce(`${user1.email}{enter}${user2.email}{enter}`);
|
||||
cy.findByRole('textbox', {name: 'Search for people or groups'}).typeWithForce(`${user1.email}{enter}${user2.email}{enter}`);
|
||||
|
||||
// # Confirm add the users
|
||||
cy.get('#addUsersToChannelModal #saveItems').click();
|
||||
|
||||
45
e2e-tests/cypress/tests/support/api/group.ts
Normal file
45
e2e-tests/cypress/tests/support/api/group.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// *****************************************************************************
|
||||
// Groups
|
||||
// https://api.mattermost.com/#tag/groups
|
||||
// *****************************************************************************
|
||||
|
||||
import {ChainableT} from '../../types';
|
||||
|
||||
function apiCreateCustomUserGroup(displayName: string, name: string, userIds: string[]): ChainableT<Cypress.Group> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/groups',
|
||||
method: 'POST',
|
||||
body: {
|
||||
display_name: displayName,
|
||||
name,
|
||||
source: 'custom',
|
||||
allow_reference: true,
|
||||
user_ids: userIds,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateCustomUserGroup', apiCreateCustomUserGroup);
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Create custom user group
|
||||
* @param {string} displayName - the display name of the group
|
||||
* @param {string} name - the @ mentionable name of the group
|
||||
* @param {string[]} userIds - users to add to the group
|
||||
*/
|
||||
apiCreateCustomUserGroup: typeof apiCreateCustomUserGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import './cloud';
|
||||
import './cluster';
|
||||
import './common';
|
||||
import './data_retention';
|
||||
import './group';
|
||||
import './keycloak';
|
||||
import './ldap';
|
||||
import './playbooks';
|
||||
|
||||
1
e2e-tests/cypress/tests/support/index.d.ts
vendored
1
e2e-tests/cypress/tests/support/index.d.ts
vendored
@@ -33,6 +33,7 @@ declare namespace Cypress {
|
||||
type UserCustomStatus = import('@mattermost/types/users').UserCustomStatus;
|
||||
type UserAccessToken = import('@mattermost/types/users').UserAccessToken;
|
||||
type DeepPartial = import('@mattermost/types/utilities').DeepPartial;
|
||||
type Group = import('@mattermost/types/groups').Group;
|
||||
interface Chainable {
|
||||
tab: (options?: {shift?: boolean}) => Chainable<JQuery>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user