snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Nightly Race / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-16 00:29:55 +05:00
commit 240db4e2a7
15309 changed files with 2173406 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @not_cloud @system_console @license_removal
import {promoteToChannelOrTeamAdmin} from '../channel_moderation/helpers.ts';
import * as TIMEOUTS from '@/fixtures/timeouts';
import {getAdminAccount} from '@/support/env';
describe('System console', () => {
const sysadmin = getAdminAccount();
let teamAdmin;
let regularUser;
let teamName;
let privateChannelName;
before(() => {
cy.shouldNotRunOnCloudEdition();
// * Check if server has license
cy.apiRequireLicense();
// # Set channel permissions as listed in the test
setChannelPermission();
// # Create regular user and team admin
cy.apiInitSetup({userPrefix: 'regular-user'}).then(({team, user}) => {
teamName = team.name;
regularUser = user;
cy.apiCreateUser({prefix: 'team-admin'}).then(({user: newUser}) => {
cy.apiAddUserToTeam(team.id, newUser.id).then(() => {
teamAdmin = newUser;
promoteToChannelOrTeamAdmin(teamAdmin.id, team.id, 'teams');
cy.apiCreateChannel(team.id, 'private', 'Private', 'P').then(({channel}) => {
privateChannelName = channel.name;
Cypress._.forEach([teamAdmin.id, regularUser.id], (userId) => cy.apiAddUserToChannel(channel.id, userId));
});
});
});
});
});
it('MM-41397 - License page shows upgrade to Enterprise Advanced for Enterprise licenses', () => {
cy.visit('/admin_console/about/license');
cy.get('.admin-console__header').
should('be.visible').
and('have.text', 'Edition and License');
// Validate Enterprise to Enterprise Advanced upgrade content
cy.get('.EnterpriseEditionRightPannel').
should('be.visible').
within(() => {
// Check the title
cy.get('.upgrade-title').should('have.text', 'Upgrade to Enterprise Advanced');
// Check the advantages list
cy.findByText('Dynamic attribute-based access controls');
cy.findByText('Data spillage handling');
cy.findByText('Burn-on-read messages');
cy.findByText('Mobile biometrics & advanced security');
cy.findByText('Automatic channel translations');
cy.findByText('Channel banners');
cy.findByText('And more...');
cy.findByRole('button', {name: 'Contact Sales'});
});
// Validate Compare plans link is not present for Enterprise licenses
cy.findByRole('link', {name: 'Compare Plans'}).should('not.exist');
});
it('MM-T1201 - Remove and re-add license - Permissions freeze in place when license is removed (and then re-added)', () => {
// * Verify user access per permissions changed while on E20
verifyUserChannelPermission(teamName, privateChannelName, sysadmin, teamAdmin, regularUser);
// # Remove license and verify user access when downgraded to E0/team edition
cy.apiAdminLogin();
cy.apiDeleteLicense();
verifyUserChannelPermission(teamName, privateChannelName, sysadmin, teamAdmin, regularUser);
// # Re-add license and verify user access when upgraded to E20
cy.apiAdminLogin();
cy.apiRequireLicense();
verifyUserChannelPermission(teamName, privateChannelName, sysadmin, teamAdmin, regularUser);
});
});
// # Set channel permissions as listed in the test
function setChannelPermission() {
cy.visit('admin_console/user_management/permissions/system_scheme');
cy.findByTestId('resetPermissionsToDefault').click();
cy.get('#confirmModalButton').click();
cy.findByTestId('all_users-public_channel-create_public_channel-checkbox').click();
cy.findByTestId('all_users-private_channel-manage_private_channel_properties-checkbox').click();
cy.findByTestId('team_admin-private_channel-manage_private_channel_properties-checkbox').click();
cy.findByTestId('saveSetting').click();
}
function verifyCreatePublicChannel(teamName, testUsers) {
for (const testUser of testUsers) {
const {user, canCreate, isSysadmin} = testUser;
// # Login as a user, and visit the team and channel
cy.apiLogin(user);
cy.visit(`/${teamName}/channels/town-square`);
// # Click on create new channel at LHS
cy.uiBrowseOrCreateChannel('Create new channel');
cy.findByRole('dialog', {name: 'Create a new channel'}).within(() => {
// * Verify if creating a public channel is disabled or not
cy.get('#public-private-selector-button-O').should(isSysadmin || canCreate ? 'not.have.class' : 'have.class', 'disabled');
// * Verify if creating a private channel is not disabled
cy.get('#public-private-selector-button-P').should('not.have.class', 'disabled');
});
}
}
function verifyRenamePrivateChannel(teamName, privateChannelName, testUsers) {
for (const testUser of testUsers) {
const {user, canRename} = testUser;
cy.apiLogin(user);
cy.visit(`/${teamName}/channels/${privateChannelName}`);
// * Click the dropdown menu and verify if the rename option is visible or not
cy.get('#channelHeaderTitle', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').click();
cy.get('#channelRename').should(canRename ? 'be.visible' : 'not.exist');
}
}
function verifyUserChannelPermission(teamName, privateChannelName, sysadmin, teamAdmin, regularUser) {
// * Verify that system admin sees option to create public channels and team admins / members do not
verifyCreatePublicChannel(teamName, [
{user: sysadmin, canCreate: true, isSysadmin: true},
{user: teamAdmin, canCreate: false},
{user: regularUser, canCreate: false},
]);
// * Verify that team admin and system admin see option to rename private channel, and member does not
verifyRenamePrivateChannel(teamName, privateChannelName, [
{user: sysadmin, canRename: true},
{user: teamAdmin, canRename: true},
{user: regularUser, canRename: false},
]);
}

View File

@@ -0,0 +1,270 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @not_cloud @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
// These specs exercise the license upload preview/diff flow added in MM-67113.
// The upload and preview endpoints require real, signed license bytes that are
// not available to the e2e environment, so the network is stubbed via
// cy.intercept and a tiny dummy file is fed into the hidden file input. The
// stubs are crafted to reproduce the two issues reported during QA:
// 1. After uploading a new license, the success screen showed the previous
// tier and the System Console license page did not refresh.
// 2. Re-uploading the currently applied license was not handled gracefully.
const OLD_LICENSE_ID = 'old-license-id-0000000000000';
// Current (already applied) license, as returned by GET /license/client.
const currentClientLicense = buildClientLicense({
id: OLD_LICENSE_ID,
skuName: 'Professional',
skuShortName: 'professional',
users: '100',
});
// New license returned by the preview/upload endpoints (an upgrade to Enterprise).
const newLicense = buildLicense({
id: 'new-license-id-0000000000000',
skuName: 'Enterprise',
skuShortName: 'enterprise',
users: 500,
});
describe('System console - License preview/diff view', () => {
before(() => {
cy.apiAdminLogin();
cy.shouldNotRunOnCloudEdition();
// * Ensure the server is licensed so the System Console renders the
// enterprise license page (the displayed license is stubbed below).
cy.apiRequireLicense();
});
beforeEach(() => {
cy.apiAdminLogin();
});
it('MM-67113 - Shows the newly uploaded license tier on success and refreshes the page after closing', () => {
// # The displayed license starts as Professional. It is served from a
// mutable holder so we can simulate the server only reporting the new
// license once propagation completes (by the time the modal closes).
const clientLicenseHolder = {body: currentClientLicense};
cy.intercept('GET', '**/api/v4/license/client', (req) => {
req.reply({statusCode: 200, body: clientLicenseHolder.body});
}).as('getClientLicense');
// # Preview and upload both return the new Enterprise license
cy.intercept('POST', '**/api/v4/license/preview', {statusCode: 200, body: newLicense}).as('previewLicense');
cy.intercept('POST', '**/api/v4/license', {statusCode: 200, body: newLicense}).as('uploadLicense');
cy.visit('/admin_console/about/license');
cy.wait('@getClientLicense');
// * The page initially shows the current (Professional) license
cy.get('.EnterpriseEditionLeftPanel__Title', {timeout: TIMEOUTS.TEN_SEC}).
should('contain.text', 'Mattermost Professional');
// # Select a license file to open the upload modal
selectLicenseFile();
// # Wait for the preview request and the diff view to render
cy.wait('@previewLicense');
cy.get('#UploadLicenseModal').should('be.visible').within(() => {
// * The diff view compares the current and new license tiers
cy.findByText('Review License Changes').should('be.visible');
cy.get('.diff-current').should('contain.text', 'Professional');
cy.get('.diff-new').should('contain.text', 'Enterprise');
// # Apply the new license
cy.get('#confirm-button').click();
});
cy.wait('@uploadLicense');
// * The success screen reflects the NEWLY uploaded tier (Enterprise),
// not the previously applied tier (Professional). This is the core of
// the "uploaded Enterprise, got Professional" report.
cy.get('#UploadLicenseModal').should('be.visible').within(() => {
cy.findByText('New license successfully applied').should('be.visible');
cy.get('.subtitle').
should('contain.text', 'Enterprise').
and('not.contain.text', 'Professional');
});
// # By the time the admin closes the modal, the server reports the new
// license. Closing must trigger a refresh that picks this up.
cy.then(() => {
clientLicenseHolder.body = buildClientLicense({
id: newLicense.id,
skuName: 'Enterprise',
skuShortName: 'enterprise',
users: '500',
});
});
cy.get('#UploadLicenseModal').within(() => {
cy.get('#done-button').click();
});
cy.get('#UploadLicenseModal').should('not.exist');
// * The System Console license page refreshes to show the new license
// without requiring a manual page reload.
cy.get('.EnterpriseEditionLeftPanel__Title', {timeout: TIMEOUTS.TEN_SEC}).
should('contain.text', 'Mattermost Enterprise');
});
it('MM-67113 - Warns when re-uploading the currently applied license and leaves it unchanged', () => {
// # The displayed license stays Professional throughout this flow
cy.intercept('GET', '**/api/v4/license/client', {
statusCode: 200,
body: currentClientLicense,
}).as('getClientLicense');
// # Preview and upload return the SAME license that is currently applied
// (same id), so the diff view should detect an unchanged license.
const sameLicense = buildLicense({
id: OLD_LICENSE_ID,
skuName: 'Professional',
skuShortName: 'professional',
users: 100,
});
cy.intercept('POST', '**/api/v4/license/preview', {statusCode: 200, body: sameLicense}).as('previewLicense');
cy.intercept('POST', '**/api/v4/license', {statusCode: 200, body: sameLicense}).as('uploadLicense');
cy.visit('/admin_console/about/license');
cy.wait('@getClientLicense');
cy.get('.EnterpriseEditionLeftPanel__Title', {timeout: TIMEOUTS.TEN_SEC}).
should('contain.text', 'Mattermost Professional');
// # Select the same license file to open the upload modal
selectLicenseFile();
cy.wait('@previewLicense');
// * The diff view warns that the license is already active
cy.get('#UploadLicenseModal').should('be.visible').within(() => {
cy.findByText('This license is already active').should('be.visible');
// # The admin can still apply it; doing so must not break the flow
cy.get('#confirm-button').click();
});
cy.wait('@uploadLicense');
// * The flow completes successfully and the modal can be closed
cy.get('#UploadLicenseModal').should('be.visible').within(() => {
cy.findByText('New license successfully applied').should('be.visible');
cy.get('#done-button').click();
});
cy.get('#UploadLicenseModal').should('not.exist');
// * The applied license is unchanged and the page remains functional
cy.get('.EnterpriseEditionLeftPanel__Title', {timeout: TIMEOUTS.TEN_SEC}).
should('contain.text', 'Mattermost Professional');
});
});
// Feed a small dummy file into the hidden license file input. The actual bytes
// are irrelevant because the preview/upload endpoints are stubbed.
function selectLicenseFile() {
cy.get('[data-testid="EnterpriseEditionLeftPanel"] input[type="file"]').
selectFile({
contents: Cypress.Buffer.from('dummy-license-content'),
fileName: 'test-license.mattermost-license',
}, {force: true});
}
// Build a License object matching the shape returned by POST /license/preview
// and POST /license (server model.License serialized to JSON).
function buildLicense({id, skuName, skuShortName, users}) {
const now = Date.now();
return {
id,
issued_at: now,
starts_at: now,
expires_at: now + (365 * 24 * 60 * 60 * 1000),
customer: {
id: 'customer-id',
name: 'Test Customer',
email: 'test@example.com',
company: 'Test Company',
},
features: {
users,
ldap: true,
ldap_groups: true,
mfa: true,
google_oauth: true,
office365_oauth: true,
compliance: true,
cluster: true,
metrics: true,
mhpns: true,
saml: true,
elastic_search: true,
announcement: true,
theme_management: true,
email_notification_contents: true,
data_retention: true,
message_export: true,
custom_permissions_schemes: true,
custom_terms_of_service: true,
guest_accounts: true,
guest_accounts_permissions: true,
},
sku_name: skuName,
sku_short_name: skuShortName,
is_gov_sku: false,
};
}
// Build a ClientLicense object (old format) matching GET /license/client.
// All values are strings, as produced by the server.
function buildClientLicense({id, skuName, skuShortName, users}) {
const now = Date.now();
return {
IsLicensed: 'true',
IsTrial: 'false',
Id: id,
SkuName: skuName,
SkuShortName: skuShortName,
Users: users,
IssuedAt: String(now),
StartsAt: String(now),
ExpiresAt: String(now + (365 * 24 * 60 * 60 * 1000)),
Name: 'Test Customer',
Email: 'test@example.com',
Company: 'Test Company',
IsGovSku: 'false',
LDAP: 'true',
LDAPGroups: 'true',
MFA: 'true',
SAML: 'true',
Cluster: 'true',
Metrics: 'true',
GoogleOAuth: 'true',
Office365OAuth: 'true',
OpenId: 'true',
Compliance: 'true',
MHPNS: 'true',
Announcement: 'true',
Elasticsearch: 'true',
DataRetention: 'true',
IDLoadedPushNotifications: 'true',
EmailNotificationContents: 'true',
MessageExport: 'true',
CustomPermissionsSchemes: 'true',
GuestAccounts: 'true',
GuestAccountsPermissions: 'true',
CustomTermsOfService: 'true',
LockTeammateNameDisplay: 'true',
Cloud: 'false',
SharedChannels: 'true',
RemoteClusterService: 'true',
OutgoingOAuthConnections: 'true',
};
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @not_cloud @system_console @license_removal
describe('System console', () => {
before(() => {
// * Ensure we are on self-hosted Starter edition
cy.shouldNotRunOnCloudEdition();
cy.apiDeleteLicense();
});
it('MM-T5132 License page shows View plans button', () => {
cy.visit('/admin_console/about/license');
// *Validate View plans button exits
cy.get('.StarterLeftPanel').get('#starter_edition_view_plans').contains('View plans');
// # Click View plans
cy.get('.StarterLeftPanel').get('#starter_edition_view_plans').click();
// *Ensure pricing modal is open
cy.get('#pricingModal').should('exist');
});
});

View File

@@ -0,0 +1,115 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Archived channels', () => {
let testChannel;
let testPrivateChannel;
before(() => {
cy.apiRequireLicense();
cy.apiInitSetup({
channelPrefix: {name: '000-archive', displayName: '000 Archive Test'},
}).then(({channel, team}) => {
testChannel = channel;
// # Archive the public channel
cy.apiDeleteChannel(testChannel.id);
// # Create and archive a private channel with a prefix to ensure proper sorting
cy.apiCreateChannel(team.id, '000-private-archive', '000 Private Archive Test', 'P').then(({channel: privateChannel}) => {
testPrivateChannel = privateChannel;
cy.apiDeleteChannel(privateChannel.id);
});
});
});
it('are present in the channels list view', () => {
// # Go to the channels list view
cy.visit('/admin_console/user_management/channels');
// * Verify the archived channel is visible
cy.findByText(testChannel.display_name, {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
// * Verify the deleted channel displays the correct icon
cy.findByTestId(`${testChannel.name}-archive-icon`).should('be.visible');
});
it('appear in the search results of the channels list view', () => {
// # Go to the channels list view
cy.visit('/admin_console/user_management/channels');
// # Search for the archived channel
cy.findByTestId('searchInput', {timeout: TIMEOUTS.ONE_MIN}).type(`${testChannel.display_name}{enter}`);
// * Verify the archived channel is in the results
cy.findByText(testChannel.display_name).should('be.visible');
});
it('display an unarchive button and a limited set of other UI elements', () => {
// # Go to the channel details view
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
// * Verify the Unarchive Channel button is visible
cy.get('button.btn-secondary', {timeout: TIMEOUTS.TWO_SEC}).should('have.text', 'Unarchive Channel').should('be.visible').should('be.enabled');
// * Verify that only one widget is visible
cy.get('div.AdminPanel').should('be.visible').and('have.length', 1);
});
it('can be unarchived', () => {
// # Go to the channel details view
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
// # Click Unarchive Channel button
cy.get('button.btn-secondary', {timeout: TIMEOUTS.TWO_SEC}).findAllByText('Unarchive Channel').click();
// * Verify the Archive Channel button is visible
cy.get('button.btn-secondary.btn-danger', {timeout: TIMEOUTS.TWO_SEC}).findAllByText('Archive Channel').should('be.visible');
// * Verify that the other widget appears
cy.get('div.AdminPanel').should('be.visible').should('have.length', 5);
// # Save and wait for redirect
cy.get('#saveSetting').click();
cy.get('.DataGrid', {timeout: TIMEOUTS.TWO_SEC}).scrollIntoView().should('be.visible');
// * Verify via the API that the channel is unarchived
cy.apiGetChannel(testChannel.id).then(({channel}) => {
expect(channel.delete_at).to.eq(0);
});
});
it('display archive icon for public archived channels in channel list', () => {
// # Go to the channels list view
cy.visit('/admin_console/user_management/channels');
// * Verify the archived public channel is visible
cy.findByText(testChannel.display_name, {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
// * Verify the archive icon is displayed
cy.findByTestId(`${testChannel.name}-archive-icon`).should('be.visible');
});
it('display archive-lock icon for private archived channels in channel list', () => {
// # Go to the channels list view
cy.visit('/admin_console/user_management/channels');
// * Verify the archived private channel is visible
cy.findByText(testPrivateChannel.display_name, {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
// * Verify the archive icon is displayed for private channel
cy.findByTestId(`${testPrivateChannel.name}-archive-icon`).should('be.visible');
});
});

View File

@@ -0,0 +1,111 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @system_console @mfa
import ldapUsers from '@/fixtures/ldap_users.json';
import * as TIMEOUTS from '@/fixtures/timeouts';
import {getAdminAccount} from '@/support/env';
const authenticator = require('authenticator');
describe('Settings', () => {
let mfaUser;
let samlUser;
const ldapUser = ldapUsers['test-1'];
before(() => {
cy.apiInitSetup().then(({user}) => {
mfaUser = user;
cy.apiUpdateConfig({
ServiceSettings: {
EnableMultifactorAuthentication: true,
},
});
// * Check if server has license for LDAP
cy.apiRequireLicenseForFeature('LDAP');
return cy.apiSyncLDAPUser({ldapUser});
}).then(() => {
return cy.apiCreateUser();
}).then(({user: user2}) => {
// # Create SAML user
samlUser = user2;
const body = {
from: 'email',
auto: false,
};
body.matches = {};
body.matches[user2.email] = user2.username;
return migrateAuthToSAML(body);
}).then(() => {
return cy.apiGenerateMfaSecret(mfaUser.id);
}).then((res) => {
// # Create MFA user
const token = authenticator.generateToken(res.code.secret);
return cy.apiActivateUserMFA(mfaUser.id, true, token);
});
});
it('MM-T953 Verify correct authentication method', () => {
cy.visit('/admin_console/user_management/users');
const adminUsername = getAdminAccount().username;
// # Type sysadmin
cy.findByPlaceholderText('Search users').clear().type(adminUsername).wait(TIMEOUTS.TWO_SEC);
// * Verify sign-in method from user profile
cy.get('.displayName').click();
cy.get('label').contains('Authentication Method').find('span').last().should('have.text', 'Email');
cy.get('a.back').click();
// # Type saml user
cy.findByPlaceholderText('Search users').clear().type(samlUser.username).wait(TIMEOUTS.TWO_SEC);
// * Verify sign-in method from user profile
cy.get('.displayName').click();
cy.get('label').contains('Authentication Method').find('span').last().should('have.text', 'SAML');
cy.get('a.back').click();
// # Type ldap user
cy.findByPlaceholderText('Search users').clear().type(ldapUser.username).wait(TIMEOUTS.TWO_SEC);
// * Verify sign-in method from user profile
cy.get('.displayName').click();
cy.get('label').contains('Authentication Method').find('span').last().should('have.text', 'LDAP');
cy.get('a.back').click();
// # Type mfa user
cy.findByPlaceholderText('Search users').clear().type(mfaUser.username).wait(TIMEOUTS.TWO_SEC);
// * Verify sign-in method from user profile
cy.get('.displayName').click();
cy.get('label').contains('Authentication Method').find('span').last().should('contain.text', 'MFA');
cy.get('a.back').click();
});
});
function migrateAuthToSAML(body) {
return cy.request({
headers: {'X-Requested-With': 'XMLHttpRequest'},
url: '/api/v4/users/migrate_auth/saml',
method: 'POST',
body,
timeout: TIMEOUTS.ONE_MIN,
}).then((response) => {
expect(response.status).to.equal(200);
return cy.wrap(response);
});
}

View File

@@ -0,0 +1,203 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Channel members test', () => {
let testChannel;
let user1;
let user2;
let sysadmin;
before(() => {
// # Login as sysadmin
cy.apiAdminLogin().then((res) => {
sysadmin = res.user;
});
// * Check if server has license
cy.apiRequireLicense();
cy.apiInitSetup().then(({team, channel, user}) => {
user1 = user;
testChannel = channel;
cy.apiCreateUser().then(({user: newUser}) => {
user2 = newUser;
cy.apiAddUserToTeam(team.id, user2.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, user2.id);
});
});
});
});
it('MM-23938 - Channel members block is only visible when channel is not group synced', () => {
// # Visit the channel page
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
// * Assert that the members block is visible on non group synced channel
cy.get('#channelMembers').scrollIntoView().should('be.visible');
// # Click the sync group members switch
cy.findByTestId('syncGroupSwitch').
scrollIntoView().
findByRole('button').
click({force: true});
// * Assert that the members block is no longer visible
cy.get('#channelMembers').should('not.exist');
});
it('MM-23938 - Channel Members block can search for users, remove users, add users and modify their roles', () => {
// # Visit the channel page
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
// * Assert that the members block is visible on non group synced team
cy.get('#channelMembers').scrollIntoView().should('be.visible');
// # Search for user1 that we know is in the team
searchFor(user1.email);
// # Wait till loading complete and then remove the only visible user
cy.get('#channelMembers .DataGrid_loading').should('not.exist');
cy.get('#channelMembers .UserGrid_removeRow a').should('be.visible').click();
// # Attempt to save
cy.get('#saveSetting').click();
// * Assert that confirmation modal contains the right message
cy.get('#confirmModalBody').should('be.visible').and('contain', '1 user will be removed.').and('contain', 'Are you sure you wish to remove this user?');
// # Cancel
cy.get('#cancelModalButton').click();
// # Search for user2 that we know is in the team
searchFor(user2.email);
// # Wait till loading complete and then remove the only visible user
cy.get('#channelMembers .DataGrid_loading').should('not.exist');
cy.get('#channelMembers .UserGrid_removeRow a').should('be.visible').click();
// # Attempt to save
cy.get('#saveSetting').click();
// * Assert that confirmation modal contains the right message
cy.get('#confirmModalBody').should('be.visible').and('contain', '2 users will be removed.').and('contain', 'Are you sure you wish to remove these users?');
// # Confirm Save
cy.get('#confirmModalButton').click();
// # Check that the members block is no longer visible meaning that the save has succeeded and we were redirected out
cy.get('#channelMembers').should('not.exist');
// # Visit the channel page
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
// # Search for user1 that we know is no longer in the team
searchFor(user1.email);
// * Assert that no matching users found
cy.get('#channelMembers .DataGrid_rows').should('contain', 'No users found');
// # Search for user2 that we know is no longer in the team
searchFor(user2.email);
// * Assert that no matching users found
cy.get('#channelMembers .DataGrid_rows').should('contain', 'No users found');
// # Open the add members modal
cy.get('#addChannelMembers').click();
// # Enter user1 and user2 emails
cy.findByRole('combobox', {name: 'Search for people or groups'}).typeWithForce(`${user1.email}{enter}${user2.email}{enter}`);
// # Confirm add the users
cy.get('#addUsersToChannelModal #saveItems').click();
// # Search for user1
searchFor(user1.email);
// * Assert that the user is now added to the members block and contains text denoting that they are New
cy.get('#channelMembers .DataGrid_rows').children(0).should('contain', user1.email).and('contain', 'New');
// # Open the user role dropdown menu
cy.get(`#userGridRoleDropdown_${user1.username}`).click();
// * Verify that the menu is opened
cy.get('.Menu__content').should('be.visible').within(() => {
// # Make the user an admin
cy.findByText('Make Channel Admin').should('be.visible');
cy.findByText('Make Channel Admin').click();
});
// # Search for user2
searchFor(user2.email);
// * Assert that the user is now added to the members block and contains text denoting that they are New
cy.get('#channelMembers .DataGrid_rows').children(0).should('contain', user2.email).and('contain', 'New');
// # Search for sysadmin
searchFor(sysadmin.email);
// * Assert that searching for users after adding users returns only relevant search results
cy.get('#channelMembers .DataGrid_rows').children(0).should('contain', sysadmin.email);
// # Attempt to save
saveConfig();
// # Visit the channel page
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
// # Search user1 that we know is now in the team again
searchFor(user1.email);
cy.get('#channelMembers .DataGrid_loading').should('not.exist');
// * Assert that the user is now saved as an admin
cy.get('#channelMembers .DataGrid_rows').children(0).should('contain', user1.email).and('not.contain', 'New').and('contain', 'Channel Admin');
// # Open the user role dropdown menu
cy.get(`#userGridRoleDropdown_${user1.username}`).click();
// * Verify that the menu is opened
cy.get('.Menu__content').should('be.visible').within(() => {
// # Make the user a regular member again
cy.findByText('Make Channel Member').should('be.visible').click();
});
// * Assert user1 is now back to being a regular member
cy.get('#channelMembers .DataGrid_rows').children(0).should('contain', user1.email).and('not.contain', 'New').and('contain', 'Member');
// # Search user2 that we know is now in the team again
searchFor(user2.email);
cy.get('#channelMembers .DataGrid_loading').should('not.exist');
// * Assert user2 is now saved as a regular member
cy.get('#channelMembers .DataGrid_rows').children(0).should('contain', user2.email).and('not.contain', 'New').and('contain', 'Member');
// # Attempt to save
saveConfig();
});
});
function saveConfig() {
// # Click save
cy.get('#saveSetting').click();
// # Check that the members block is no longer visible meaning that the save has succeeded and we were redirected out
cy.get('#channelMembers').should('not.exist');
}
function searchFor(searchTerm) {
cy.get('#channelMembers .DataGrid_search input[type="text"]').scrollIntoView().clear().type(searchTerm);
cy.wait(TIMEOUTS.HALF_SEC); // Timeout required to wait for timeout that happens when search input changes
}

View File

@@ -0,0 +1,182 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console @channel_moderation
import type {Channel} from '@mattermost/types/channels';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {checkboxesTitleToIdMap} from './constants';
import {
disablePermission,
enablePermission,
postChannelMentionsAndVerifySystemMessageExist,
postChannelMentionsAndVerifySystemMessageNotExist,
saveConfigForChannel,
saveConfigForScheme,
visitChannel,
visitChannelConfigPage,
} from './helpers';
describe('MM-23102 - Channel Moderation - Channel Mentions', () => {
let regularUser: UserProfile;
let guestUser: UserProfile;
let testTeam: Team;
let testChannel: Channel;
before(() => {
// * Check if server has license
cy.apiRequireLicense();
cy.apiInitSetup().then(({team, channel, user}) => {
regularUser = user;
testTeam = team;
testChannel = channel;
cy.apiCreateGuestUser({}).then(({guest}) => {
guestUser = guest;
cy.apiAddUserToTeam(testTeam.id, guestUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, guestUser.id);
});
});
});
});
it('MM-T1551 Channel Mentions option for Guests', () => {
// # Uncheck the Channel Mentions option for Guests and save
visitChannelConfigPage(testChannel);
disablePermission(checkboxesTitleToIdMap.CHANNEL_MENTIONS_GUESTS);
saveConfigForChannel();
visitChannel(guestUser, testChannel, testTeam);
// # Check Guest user has the permission to user special mentions like @all @channel and @here
postChannelMentionsAndVerifySystemMessageExist(testChannel.name);
// # Visit Channel page and Search for the channel.
visitChannelConfigPage(testChannel);
// # check the channel mentions option for guests and save
enablePermission(checkboxesTitleToIdMap.CHANNEL_MENTIONS_GUESTS);
saveConfigForChannel();
visitChannel(guestUser, testChannel, testTeam);
// # Check Guest user has the permission to user special mentions like @all @channel and @here
postChannelMentionsAndVerifySystemMessageNotExist(testChannel);
});
it('MM-T1552 Channel Mentions option for Members', () => {
// # Visit Channel page and Search for the channel.
visitChannelConfigPage(testChannel);
// # Uncheck the channel mentions option for guests and save
disablePermission(checkboxesTitleToIdMap.CHANNEL_MENTIONS_MEMBERS);
saveConfigForChannel();
visitChannel(regularUser, testChannel, testTeam);
// # Check Member user does not has the permission to use special mentions like @all @channel and @here
postChannelMentionsAndVerifySystemMessageExist(testChannel.name);
// # Visit Channel page and Search for the channel.
visitChannelConfigPage(testChannel);
// # check the channel mentions option for guests and save
enablePermission(checkboxesTitleToIdMap.CHANNEL_MENTIONS_MEMBERS);
saveConfigForChannel();
visitChannel(regularUser, testChannel, testTeam);
// # Check Member user has the permission to user special mentions like @all @channel and @here
postChannelMentionsAndVerifySystemMessageNotExist(testChannel);
});
it('MM-T1555 Channel Mentions option removed when Create Post is disabled', () => {
// # Visit Channel page and Search for the channel.
visitChannelConfigPage(testChannel);
// # Uncheck the create posts option for guests
disablePermission(checkboxesTitleToIdMap.CREATE_POSTS_GUESTS);
// * Option to allow Channel Mentions for Guests should also be disabled when Create Post option is disabled.
// * A message Guests can not use channel mentions without the ability to create posts should be displayed.
cy.findByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledGuestsDueToCreatePosts').
should('have.text', 'Guests can not use channel mentions without the ability to create posts.');
cy.findByTestId(checkboxesTitleToIdMap.CHANNEL_MENTIONS_GUESTS).should('be.disabled');
// # check the create posts option for guests and uncheck for members
enablePermission(checkboxesTitleToIdMap.CREATE_POSTS_GUESTS);
disablePermission(checkboxesTitleToIdMap.CREATE_POSTS_MEMBERS);
// * Option to allow Channel Mentions for Members should also be disabled when Create Post option is disabled.
// * A message Members can not use channel mentions without the ability to create posts should be displayed.
cy.findByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledMemberDueToCreatePosts').
should('have.text', 'Members can not use channel mentions without the ability to create posts.');
cy.findByTestId(checkboxesTitleToIdMap.CHANNEL_MENTIONS_MEMBERS).should('be.disabled');
// # Uncheck the create posts option for guests
disablePermission(checkboxesTitleToIdMap.CREATE_POSTS_GUESTS);
// * Ensure that channel mentions for members and guests is disabled
// * Ensure message Guests & Members can not use channel mentions without the ability to create posts
cy.findByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledBothDueToCreatePosts').
should('have.text', 'Guests and members can not use channel mentions without the ability to create posts.');
cy.findByTestId(checkboxesTitleToIdMap.CHANNEL_MENTIONS_GUESTS).should('be.disabled');
cy.findByTestId(checkboxesTitleToIdMap.CHANNEL_MENTIONS_MEMBERS).should('be.disabled');
});
it('MM-T1556 Message when user without channel mention permission uses special channel mentions', () => {
visitChannelConfigPage(testChannel);
disablePermission(checkboxesTitleToIdMap.CHANNEL_MENTIONS_MEMBERS);
saveConfigForChannel();
visitChannel(regularUser, testChannel, testTeam);
cy.findByTestId('post_textbox').clear().type('@');
// * Ensure that @here, @all, and @channel do not show up in the autocomplete list
cy.findAllByTestId('mentionSuggestion_here').should('not.exist');
cy.findAllByTestId('mentionSuggestion_all').should('not.exist');
cy.findAllByTestId('mentionSuggestion_channel').should('not.exist');
// * When you type @all, @enter, and @channel make sure that a system message shows up notifying you nothing happened.
postChannelMentionsAndVerifySystemMessageExist(testChannel.name);
});
it('MM-T1557 Confirm sending notifications while using special channel mentions', () => {
// # Visit Channel page and Search for the channel.
visitChannelConfigPage(testChannel);
disablePermission(checkboxesTitleToIdMap.CHANNEL_MENTIONS_MEMBERS);
saveConfigForChannel();
// # Set @channel and @all confirmation dialog to true
cy.visit('admin_console/environment/notifications');
cy.findByTestId('TeamSettings.EnableConfirmNotificationsToChanneltrue').check();
saveConfigForScheme();
// # Visit test channel
visitChannel(regularUser, testChannel, testTeam);
// * Type at all and enter that no confirmation dialogue shows up
cy.postMessage('@all ');
cy.get('#genericModalLabel').should('not.exist');
// * Type at channel and enter that no confirmation dialogue shows up
cy.postMessage('@channel ');
cy.get('#genericModalLabel').should('not.exist');
// * Type at here and enter that no confirmation dialogue shows up
cy.postMessage('@here ');
cy.get('#genericModalLabel').should('not.exist');
});
});

View File

@@ -0,0 +1,26 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
export const checkboxesTitleToIdMap = {
ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS: 'all_users-public_channel-manage_public_channel_members_and_read_groups-checkbox',
ALL_USERS_MANAGE_PRIVATE_CHANNEL_MEMBERS: 'all_users-private_channel-manage_private_channel_members_and_read_groups-checkbox',
ALL_USERS_MANAGE_OAUTH_APPLICATIONS: 'all_users-integrations-manage_oauth-checkbox',
CREATE_POSTS_GUESTS: 'create_post-guests',
CREATE_POSTS_MEMBERS: 'create_post-members',
POST_REACTIONS_GUESTS: 'create_reactions-guests',
POST_REACTIONS_MEMBERS: 'create_reactions-members',
MANAGE_MEMBERS_GUESTS: 'manage_members-guests',
MANAGE_MEMBERS_MEMBERS: 'manage_members-members',
CHANNEL_MENTIONS_MEMBERS: 'use_channel_mentions-members',
CHANNEL_MENTIONS_GUESTS: 'use_channel_mentions-guests',
};
export const checkBoxes = [
checkboxesTitleToIdMap.CREATE_POSTS_GUESTS,
checkboxesTitleToIdMap.CREATE_POSTS_MEMBERS,
checkboxesTitleToIdMap.POST_REACTIONS_GUESTS,
checkboxesTitleToIdMap.POST_REACTIONS_MEMBERS,
checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS,
checkboxesTitleToIdMap.CHANNEL_MENTIONS_GUESTS,
checkboxesTitleToIdMap.CHANNEL_MENTIONS_MEMBERS,
];

View File

@@ -0,0 +1,112 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console @channel_moderation
import type {Channel} from '@mattermost/types/channels';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {checkboxesTitleToIdMap} from './constants';
import {
disablePermission,
enablePermission,
saveConfigForChannel,
visitChannel,
visitChannelConfigPage,
} from './helpers';
describe('MM-23102 - Channel Moderation - Create Posts', () => {
let regularUser: UserProfile;
let guestUser: UserProfile;
let testTeam: Team;
let testChannel: Channel;
before(() => {
// * Check if server has license
cy.apiRequireLicense();
cy.apiInitSetup().then(({team, channel, user}) => {
regularUser = user;
testTeam = team;
testChannel = channel;
cy.apiCreateGuestUser({}).then(({guest}) => {
guestUser = guest;
cy.apiAddUserToTeam(testTeam.id, guestUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, guestUser.id);
});
});
});
});
it('MM-T1541 Create Post option for Guests', () => {
// # Go to channel configuration page of
visitChannelConfigPage(testChannel);
// # Uncheck the Create Posts option for Guests and Save
disablePermission(checkboxesTitleToIdMap.CREATE_POSTS_GUESTS);
saveConfigForChannel();
// # Login as a Guest user and visit the same channel
visitChannel(guestUser, testChannel, testTeam);
// # Check Guest user should not have the permission to create a post on a channel when the option is removed
// * Guest user should see a message stating that this channel is read-only and the textbox area should be disabled
cy.findByTestId('post_textbox').should('have.attr', 'placeholder', 'This channel is read-only. Only members with permission can post here.');
cy.findByTestId('post_textbox').should('be.disabled');
// # As a system admin, check the option to allow Create Posts for Guests and save
visitChannelConfigPage(testChannel);
enablePermission(checkboxesTitleToIdMap.CREATE_POSTS_GUESTS);
saveConfigForChannel();
// # Login as a Guest user and visit the same channel
visitChannel(guestUser, testChannel, testTeam);
// # Check Guest user should have the permission to create a post on a channel when the option is allowed
// * Guest user should see a message stating that this channel is read-only and the textbox area should be disabled
cy.findByTestId('post_textbox').clear();
cy.findByTestId('post_textbox').should('have.attr', 'placeholder', `Write to ${testChannel.display_name}`);
cy.findByTestId('post_textbox').should('not.be.disabled');
});
it('MM-T1542 Create Post option for Members', () => {
// # Go to system admin page and to channel configuration page of test channel
visitChannelConfigPage(testChannel);
// # Uncheck the Create Posts option for Members and Save
disablePermission(checkboxesTitleToIdMap.CREATE_POSTS_MEMBERS);
saveConfigForChannel();
// # Login as a Guest user and visit test channel
visitChannel(regularUser, testChannel, testTeam);
// # Check Member should not have the permission to create a post on a channel when the option is removed.
// * User should see a message stating that this channel is read-only and the textbox area should be disabled
cy.findByTestId('post_textbox').should('have.attr', 'placeholder', 'This channel is read-only. Only members with permission can post here.');
cy.findByTestId('post_textbox').should('be.disabled');
// # As a system admin, check the option to allow Create Posts for Members and save
visitChannelConfigPage(testChannel);
enablePermission(checkboxesTitleToIdMap.CREATE_POSTS_MEMBERS);
saveConfigForChannel();
// # Login as a Member user and visit the same channel
visitChannel(regularUser, testChannel, testTeam);
// # Check Member should have the permission to create a post on a channel when the option is allowed
// * Member user should see a message stating that this channel is read-only and the textbox area should be disabled
cy.findByTestId('post_textbox').clear();
cy.findByTestId('post_textbox').should('have.attr', 'placeholder', `Write to ${testChannel.display_name}`);
cy.findByTestId('post_textbox').should('not.be.disabled');
});
});

View File

@@ -0,0 +1,314 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {Channel} from '@mattermost/types/channels';
import type {UserProfile} from '@mattermost/types/users';
import type {Team} from '@mattermost/types/teams';
import {checkBoxes} from './constants';
import * as TIMEOUTS from '@/fixtures/timeouts';
import {getAdminAccount} from '@/support/env';
// # Visits the channel configuration for a channel with channelName
export const visitChannelConfigPage = (channel: Channel) => {
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/channels');
cy.get('.DataGrid_searchBar').within(() => {
cy.findByPlaceholderText('Search').type(`${channel.name}{enter}`);
});
cy.findByText('Edit').click();
cy.wait(TIMEOUTS.ONE_SEC);
};
// # Disable a permission
export const disablePermission = (permission: string) => {
cy.waitUntil(() => cy.findByTestId(permission).scrollIntoView().should('be.visible').then((el) => {
const classAttribute = el[0].getAttribute('class') ?? '';
if (classAttribute.includes('checked') || classAttribute.includes('intermediate')) {
el[0].click();
return false;
}
return true;
}));
cy.findByTestId(permission).should('not.have.class', 'checked');
};
// # Saves channel config and navigates back to the channel config page if specified
export const saveConfigForChannel = (channelName: string | null = null, clickConfirmationButton = false) => {
cy.get('#saveSetting').then((btn) => {
if (btn.is(':enabled')) {
btn.click();
if (clickConfirmationButton) {
cy.get('#confirmModalButton').click();
}
// # Wait for location path to end with /admin_console/user_management/channels
cy.waitUntil(() => cy.location().then((location) => {
return location.href.endsWith('/admin_console/user_management/channels');
}));
// # Make sure the save is complete by looking for the search input which is only visible on the team's index page
cy.get('.DataGrid_searchBar').should('be.visible').within(() => {
cy.findByPlaceholderText('Search').should('be.visible');
});
if (channelName) {
// # Search for the channel.
cy.get('.DataGrid_searchBar').within(() => {
cy.findByPlaceholderText('Search').type(`${channelName}{enter}`);
});
cy.findByText('Edit').click();
}
}
});
};
// # Visits a channel as the member specified
export const visitChannel = (user: UserProfile, channel: Channel, team: Team) => {
cy.apiLogin(user);
cy.visit(`/${team.name}/channels/${channel.name}`);
cy.get('#postListContent', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
};
// # Checks to see if we got a system message warning after using @all/@here/@channel
export const postChannelMentionsAndVerifySystemMessageExist = (channelName: string) => {
function getSystemMessage(text: string) {
return `Channel notifications are disabled in ${channelName}. The ${text} did not trigger any notifications.`;
}
// # Type @all and post it to the channel
cy.postMessage('@all ');
// # Get last post message text
cy.getLastPostId().then((postId) => {
// * Assert that the last message posted is the system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('include.text', getSystemMessage('@all'));
});
// # Type @here and post it to the channel
cy.postMessage('@here ');
// # Get last post message text
cy.getLastPostId().then((postId) => {
// * Assert that the last message posted is the system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('include.text', getSystemMessage('@here'));
});
cy.postMessage('@channel ');
// # Type last post message text
cy.getLastPostId().then((postId) => {
// * Assert that the last message posted is the system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('include.text', getSystemMessage('@channel'));
});
};
// # Enable a permission
export const enablePermission = (permission: string) => {
cy.waitUntil(() => cy.findByTestId(permission).scrollIntoView().should('be.visible').then((el) => {
const classAttribute = el[0].getAttribute('class') ?? '';
if (!classAttribute.includes('checked')) {
el[0].click();
return false;
}
return true;
}));
cy.findByTestId(permission).should('have.class', 'checked');
};
// # Checks to see if we did not get a system message warning after using @all/@here/@channel
export const postChannelMentionsAndVerifySystemMessageNotExist = (channel: Channel) => {
function getSystemMessage(text: string) {
return `Channel notifications are disabled in ${channel.name}. The ${text} did not trigger any notifications.`;
}
cy.postMessage('@all ');
// # Get last post message text
cy.getLastPostId().then((postId) => {
// * Assert that the last message posted is NOT a system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('not.have.text', getSystemMessage('@all'));
});
cy.postMessage('@here ');
// # Get last post message text
cy.getLastPostId().then((postId) => {
// * Assert that the last message posted is NOT a system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('not.have.text', getSystemMessage('@here'));
});
cy.postMessage('@channel ');
// # Get last post message text
cy.getLastPostId().then((postId) => {
// * Assert that the last message posted is NOT a system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('not.have.text', getSystemMessage('@channel'));
});
};
// # Wait's until the Saving text becomes Save
const waitUntilConfigSave = () => {
cy.waitUntil(() => cy.get('#saveSetting').then((el) => {
return el[0].innerText === 'Save';
}));
};
// Clicks the save button in the system console page.
// waitUntilConfigSaved: If we need to wait for the save button to go from saving -> save.
// Usually we need to wait unless we are doing this in team override scheme
export const saveConfigForScheme = (waitUntilConfigSaved = true, clickConfirmationButton = false) => {
// # Save if possible (if previous test ended abruptly all permissions may already be enabled)
cy.get('#saveSetting').then((btn) => {
if (btn.is(':enabled')) {
btn.click();
}
});
if (clickConfirmationButton) {
cy.get('#confirmModalButton').click();
}
if (waitUntilConfigSaved) {
waitUntilConfigSave();
}
};
// # Goes to the System Scheme page as System Admin
export const goToSystemScheme = () => {
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/permissions/system_scheme');
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'System Scheme');
};
// # Goes to the permissions page and creates a new team override scheme with schemeName
export const goToPermissionsAndCreateTeamOverrideScheme = (schemeName: string, team: Team) => {
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/permissions');
cy.findByTestId('team-override-schemes-link').click();
cy.get('#scheme-name').type(schemeName);
cy.findByTestId('add-teams').click();
cy.get('#selectItems input').typeWithForce(team.display_name);
cy.get('#multiSelectList').should('be.visible').children().first().click({force: true});
cy.get('#saveItems').should('be.visible').click();
saveConfigForScheme(false);
cy.wait(TIMEOUTS.ONE_SEC);
};
// # Goes to the permissions page and clicks edit or delete for a team override scheme
export const deleteOrEditTeamScheme = (schemeDisplayName: string, editOrDelete: string) => {
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/permissions');
cy.findByTestId(`${schemeDisplayName}-${editOrDelete}`).click();
if (editOrDelete === 'delete') {
cy.get('#confirmModalButton').click();
}
};
// # Open channel members rhs
export const viewManageChannelMembersRHS = () => {
// # Click member count to open member list rhs
cy.get('.member-rhs__trigger').click();
};
// # Enable (check) all the permissions in the channel moderation widget through the API
export const enableDisableAllChannelModeratedPermissionsViaAPI = (channel: Channel, enable = true) => {
cy.externalRequest(
{
user: getAdminAccount(),
method: 'PUT',
path: `channels/${channel.id}/moderations/patch`,
data:
[
{
name: 'create_post',
roles: {
members: enable,
guests: enable,
},
},
{
name: 'create_reactions',
roles: {
members: enable,
guests: enable,
},
},
{
name: 'manage_members',
roles: {
members: enable,
},
},
{
name: 'use_channel_mentions',
roles: {
members: enable,
guests: enable,
},
},
{
name: 'manage_bookmarks',
roles: {
members: enable,
},
},
],
},
);
};
// # This goes to the system scheme and clicks the reset permissions to default and then saves the setting
export const resetSystemSchemePermissionsToDefault = () => {
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/permissions/system_scheme');
cy.findByTestId('resetPermissionsToDefault').click();
cy.get('#confirmModalButton').click();
saveConfigForScheme();
};
export const demoteToChannelOrTeamMember = (userId: string, id: string, channelsOrTeams = 'channels') => {
cy.externalRequest({
user: getAdminAccount(),
method: 'put',
path: `${channelsOrTeams}/${id}/members/${userId}/schemeRoles`,
data: {
scheme_user: true,
scheme_admin: false,
},
});
};
export const promoteToChannelOrTeamAdmin = (userId: string, id: string, channelsOrTeams = 'channels') => {
cy.externalRequest({
user: getAdminAccount(),
method: 'put',
path: `${channelsOrTeams}/${id}/members/${userId}/schemeRoles`,
data: {
scheme_user: true,
scheme_admin: true,
},
});
};
// # Disable (uncheck) all the permissions in the channel moderation widget
export const disableAllChannelModeratedPermissions = () => {
checkBoxes.forEach((buttonId) => {
cy.findByTestId(buttonId).then((btn) => {
if (btn.hasClass('checked')) {
btn.click();
}
});
});
};
// # Enable (check) all the permissions in the channel moderation widget
export const enableAllChannelModeratedPermissions = () => {
checkBoxes.forEach((buttonId) => {
cy.findByTestId(buttonId).then((btn) => {
if (!btn.hasClass('checked')) {
btn.click();
}
});
});
};

View File

@@ -0,0 +1,319 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @system_console @channel_moderation
import {checkboxesTitleToIdMap} from './constants';
import {
deleteOrEditTeamScheme,
demoteToChannelOrTeamMember,
disablePermission,
enablePermission,
enableDisableAllChannelModeratedPermissionsViaAPI,
goToPermissionsAndCreateTeamOverrideScheme,
goToSystemScheme,
postChannelMentionsAndVerifySystemMessageNotExist,
promoteToChannelOrTeamAdmin,
saveConfigForChannel,
saveConfigForScheme,
viewManageChannelMembersRHS,
visitChannel,
visitChannelConfigPage,
} from './helpers';
import {getRandomId} from '@/utils';
describe('MM-23102 - Channel Moderation - Higher Scoped Scheme', () => {
let regularUser: Cypress.UserProfile;
let guestUser: Cypress.UserProfile;
let testTeam: Cypress.Team;
let testChannel: Cypress.Channel;
before(() => {
// * Check if server has license
cy.apiRequireLicense();
});
beforeEach(() => {
cy.apiAdminLogin();
cy.apiResetRoles();
cy.apiInitSetup().then(({team, channel, user}) => {
regularUser = user;
testTeam = team;
testChannel = channel;
cy.apiCreateGuestUser({}).then(({guest}) => {
guestUser = guest;
cy.apiAddUserToTeam(testTeam.id, guestUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, guestUser.id);
});
});
});
});
it('MM-T1559 Effect of changing System Schemes on a Channel for which Channel Moderation Settings was modified', () => {
// # Visit Channel page and Search for the channel.
visitChannelConfigPage(testChannel);
disablePermission(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS);
disablePermission(checkboxesTitleToIdMap.CHANNEL_MENTIONS_MEMBERS);
// # check the channel mentions option for guests and save
enablePermission(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS);
saveConfigForChannel();
goToSystemScheme();
disablePermission(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS);
saveConfigForScheme();
// * Ensure manage members for members is disabled
visitChannelConfigPage(testChannel);
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('be.disabled');
visitChannel(regularUser, testChannel, testTeam);
// # View members modal
viewManageChannelMembersRHS();
// * Add Members button does not exist
cy.get('#showInviteModal').should('not.exist');
});
it('MM-T1560 Effect of changing System Schemes on a Channel for which Channel Moderation Settings was never modified', () => {
// # Reset system scheme to default and create a new channel to ensure that this channels moderation settings have never been modified
cy.apiAdminLogin();
cy.apiCreateChannel(testTeam.id, 'never-modified', `Never Modified ${getRandomId()}`).then(({channel}) => {
goToSystemScheme();
cy.findByTestId(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS).click();
saveConfigForScheme();
// # Visit Channel page and Search for the channel.
// * ensure manage members for members is disabled
visitChannelConfigPage(channel);
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('be.disabled');
visitChannel(regularUser, channel, testTeam);
// # View members modal
viewManageChannelMembersRHS();
// * Add Members button does not exist
cy.get('#showInviteModal').should('not.exist');
});
});
it('MM-T1561 Effect of changing Team Override Schemes on a Channel for which Channel Moderation Settings was never modified', () => {
// # Reset system scheme to default and create a new channel to ensure that this channels moderation settings have never been modified
cy.apiAdminLogin();
cy.apiCreateChannel(testTeam.id, 'never-modified', `Never Modified ${getRandomId()}`).then(({channel}) => {
goToPermissionsAndCreateTeamOverrideScheme(channel.name, testTeam);
deleteOrEditTeamScheme(channel.name, 'edit');
cy.findByTestId(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS).click();
saveConfigForScheme(false);
// # Visit Channel page and Search for the channel.
// * Assert message for manage member for members appears and that it's disabled
visitChannelConfigPage(channel);
cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember').
should('have.text', `Manage members for members are disabled in ${channel.name} Team Scheme.`);
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('be.disabled');
visitChannel(regularUser, channel, testTeam);
// # View members modal
viewManageChannelMembersRHS();
// * Add Members button does not exist
cy.get('#showInviteModal').should('not.exist');
});
});
it('MM-T1562 Effect of changing Team Override Schemes on a Channel for which Channel Moderation Settings was modified', () => {
const teamOverrideSchemeName = testChannel.name + getRandomId();
// # Reset system scheme to default and create a new channel to ensure that this channels moderation settings have never been modified
visitChannelConfigPage(testChannel);
disablePermission(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS);
disablePermission(checkboxesTitleToIdMap.CHANNEL_MENTIONS_MEMBERS);
saveConfigForChannel();
visitChannelConfigPage(testChannel);
enablePermission(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS);
saveConfigForChannel();
goToPermissionsAndCreateTeamOverrideScheme(teamOverrideSchemeName, testTeam);
deleteOrEditTeamScheme(teamOverrideSchemeName, 'edit');
cy.findByTestId(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS).click();
saveConfigForScheme(false);
// # Visit Channel page and Search for the channel.
// * Assert message shows and manage members for members is disabled
visitChannelConfigPage(testChannel);
cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember').
should('have.text', `Manage members for members are disabled in ${teamOverrideSchemeName} Team Scheme.`);
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('be.disabled');
visitChannel(regularUser, testChannel, testTeam);
// # View members modal
viewManageChannelMembersRHS();
// * Add Members button does not exist
cy.get('#showInviteModal').should('not.exist');
});
it('MM-T1578 Manage Members removed for Public Channels', () => {
const teamOverrideSchemeName = testChannel.name + getRandomId();
// # Create a new team override scheme and remove manage public channel members
// * Ensure that manage private channel members is checked
goToPermissionsAndCreateTeamOverrideScheme(teamOverrideSchemeName, testTeam);
deleteOrEditTeamScheme(teamOverrideSchemeName, 'edit');
cy.findByTestId(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS).click();
cy.findByTestId(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PRIVATE_CHANNEL_MEMBERS).should('be.visible').and('have.class', 'checked');
saveConfigForScheme(false);
// # Visit Channel page and Search for the channel.
// * Ensure message is disabled and manage members for members is disabled
visitChannelConfigPage(testChannel);
cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public');
cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember').
should('have.text', `Manage members for members are disabled in ${teamOverrideSchemeName} Team Scheme.`);
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('be.disabled');
// # Turn channel into a private channel
cy.findByTestId('allow-all-toggle').click();
saveConfigForChannel(testChannel.display_name, true);
// * Ensure it is private and no error message is shown and that manage members for members is not disabled
cy.findByTestId('allow-all-toggle').should('has.have.text', 'Private');
cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember').
should('not.have.text', `Manage members for members are disabled in ${teamOverrideSchemeName} Team Scheme.`);
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('not.be.disabled');
// # Turn channel back to public channel
cy.findByTestId('allow-all-toggle').click();
saveConfigForChannel(testChannel.display_name, true);
// * ensure it got reverted back to a Public channel
cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public');
});
it('MM-T1579 Manage Members removed for Private Channels / Permissions inherited when channel converted from Public to Private', () => {
const teamOverrideSchemeName = testChannel.name + getRandomId();
// # Create a new team override scheme and remove manage private channel members from it
// * Ensure that manage public channel members is checked
goToPermissionsAndCreateTeamOverrideScheme(teamOverrideSchemeName, testTeam);
deleteOrEditTeamScheme(teamOverrideSchemeName, 'edit');
cy.findByTestId(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PRIVATE_CHANNEL_MEMBERS).click();
cy.findByTestId(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS).should('be.visible').and('have.class', 'checked');
saveConfigForScheme(false);
// # Visit Channel page and Search for the channel.
visitChannelConfigPage(testChannel);
// * Ensure that error message is not displayed and manage members for members is not disabled
cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public');
cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember').
should('not.have.text', `Manage members for members are disabled in ${teamOverrideSchemeName} Team Scheme.`);
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('not.be.disabled');
// # Turn it into a private channel
cy.findByTestId('allow-all-toggle').click();
saveConfigForChannel(testChannel.display_name, true);
// * Ensure it is a private channel and that a message is disabled and also manage members for members is disabled
cy.findByTestId('allow-all-toggle').should('has.have.text', 'Private');
cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember').
should('have.text', `Manage members for members are disabled in ${teamOverrideSchemeName} Team Scheme.`);
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('be.disabled');
// # Turn channel back to public channel
cy.findByTestId('allow-all-toggle').click();
saveConfigForChannel(testChannel.display_name, true);
// * Ensure it got reset back to a public channel
cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public');
});
it('MM-T1581 Check if user is allowed to Edit or Delete their own posts on a Read-Only channel', () => {
visitChannel(regularUser, testChannel, testTeam);
cy.postMessage(`test message ${Date.now()}`);
cy.findByTestId('post_textbox_placeholder').should('not.have.text', 'This channel is read-only. Only members with permission can post here.');
cy.findByTestId('post_textbox').should('not.be.disabled');
visitChannelConfigPage(testChannel);
disablePermission(checkboxesTitleToIdMap.CREATE_POSTS_MEMBERS);
saveConfigForChannel();
visitChannel(regularUser, testChannel, testTeam);
// * user should see a message stating that this channel is read-only and the textbox area should be disabled
cy.findByTestId('post_textbox_placeholder').should('have.text', 'This channel is read-only. Only members with permission can post here.');
cy.findByTestId('post_textbox').should('be.disabled');
cy.getLastPostId().then((postId) => {
cy.clickPostDotMenu(postId);
// * As per test case, ensure edit and delete button show up
cy.get(`#edit_post_${postId}`).should('exist');
cy.get(`#delete_post_${postId}`).should('exist');
});
});
it('MM-T1582 Channel Moderation Settings should not be applied for Channel Admins', () => {
enableDisableAllChannelModeratedPermissionsViaAPI(testChannel, false);
visitChannel(regularUser, testChannel, testTeam);
promoteToChannelOrTeamAdmin(regularUser.id, testChannel.id);
// * Assert user can post message and user channel mentions
postChannelMentionsAndVerifySystemMessageNotExist(testChannel);
// # Check Channel Admin have the permission to react to any post on a channel when all channel moderation permissions are off.
// * Channel Admin should see the smiley face that allows a user to react to a post
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).trigger('mouseover');
cy.findByTestId('post-reaction-emoji-icon').should('exist');
});
// # View members modal
viewManageChannelMembersRHS();
// * Add Members button does not exist
cy.get('#showInviteModal').should('exist');
demoteToChannelOrTeamMember(regularUser.id, testChannel.id);
});
it('MM-T1583 Channel Moderation Settings should not be applied for Team Admins', () => {
enableDisableAllChannelModeratedPermissionsViaAPI(testChannel, false);
visitChannel(regularUser, testChannel, testTeam);
promoteToChannelOrTeamAdmin(regularUser.id, testTeam.id, 'teams');
// * Assert user can post message and user channel mentions
postChannelMentionsAndVerifySystemMessageNotExist(testChannel);
// # Check Channel Admin have the permission to react to any post on a channel when all channel moderation permissions are off.
// * Channel Admin should see the smiley face that allows a user to react to a post
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).trigger('mouseover');
cy.findByTestId('post-reaction-emoji-icon').should('exist');
});
// # View members modal
viewManageChannelMembersRHS();
// * Add Members button does not exist
cy.get('#showInviteModal').should('exist');
demoteToChannelOrTeamMember(regularUser.id, testTeam.id, 'teams');
});
});

View File

@@ -0,0 +1,198 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console @channel_moderation
import type {Channel} from '@mattermost/types/channels';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {checkboxesTitleToIdMap} from './constants';
import {
deleteOrEditTeamScheme,
disablePermission,
enablePermission,
goToPermissionsAndCreateTeamOverrideScheme,
goToSystemScheme,
saveConfigForChannel,
saveConfigForScheme,
viewManageChannelMembersRHS,
visitChannel,
visitChannelConfigPage,
} from './helpers';
import * as TIMEOUTS from '@/fixtures/timeouts';
import {getRandomId} from '@/utils';
function addButtonExists() {
cy.uiGetRHS().contains('button', 'Add').should('be.visible');
}
function addButtonDoesNotExists() {
cy.uiGetRHS().contains('button', 'Add').should('not.exist');
}
describe('MM-23102 - Channel Moderation - Manage Members', () => {
let regularUser: UserProfile;
let guestUser: UserProfile;
let testTeam: Team;
let testChannel: Channel;
before(() => {
// * Check if server has license
cy.apiRequireLicense();
});
beforeEach(() => {
cy.apiAdminLogin();
cy.apiResetRoles();
cy.apiInitSetup().then(({team, channel, user}) => {
regularUser = user;
testTeam = team;
testChannel = channel;
cy.apiCreateGuestUser({}).then(({guest}) => {
guestUser = guest;
cy.apiAddUserToTeam(testTeam.id, guestUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, guestUser.id);
});
});
});
});
it('MM-T1547 No option to Manage Members for Guests', () => {
visitChannelConfigPage(testChannel);
// * Assert that Manage Members for Guests does not exist (checkbox is not there)
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_GUESTS).should('not.exist');
visitChannel(guestUser, testChannel, testTeam);
// # View members rhs
viewManageChannelMembersRHS();
// * Add Members button does not exist
addButtonDoesNotExists();
});
it('MM-T1548 Manage Members option for Members', () => {
// # Visit test channel page and turn off the Manage members for Members and then save
visitChannelConfigPage(testChannel);
disablePermission(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS);
saveConfigForChannel();
visitChannel(regularUser, testChannel, testTeam);
viewManageChannelMembersRHS();
// * Add Members button does not exist
addButtonDoesNotExists();
cy.uiGetRHS().contains('button', 'Add').should('not.exist');
// # Visit test channel page and turn off the Manage members for Members and then save
visitChannelConfigPage(testChannel);
enablePermission(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS);
saveConfigForChannel();
visitChannel(regularUser, testChannel, testTeam);
viewManageChannelMembersRHS();
// * Add Members button does exist
addButtonExists();
});
it('MM-T1549 Manage Members option removed for Members in System Scheme', () => {
// Edit the System Scheme and disable the Manage Members option for Members & Save.
goToSystemScheme();
disablePermission(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS);
saveConfigForScheme();
// # Visit test channel page
visitChannelConfigPage(testChannel);
// * Assert that Manage Members option should be disabled for a Members.
// * A message Manage members for members are disabled in the System Scheme should be displayed.
cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember').
should('exist').
and('have.text', 'Manage members for members are disabled in System Scheme.');
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('be.disabled');
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_GUESTS).should('not.exist');
visitChannel(regularUser, testChannel, testTeam);
viewManageChannelMembersRHS();
// * Add Members button does not exist
addButtonDoesNotExists();
// Edit the System Scheme and enable the Manage Members option for Members & Save.
goToSystemScheme();
enablePermission(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS);
saveConfigForScheme();
// # Visit test channel page
visitChannelConfigPage(testChannel);
// * Assert that Manage Members option should be enabled for a Members.
// * A message Manage members for members are enabled in the System Scheme should be displayed.
cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember').
should('not.exist');
visitChannel(regularUser, testChannel, testTeam);
viewManageChannelMembersRHS();
// * Add Members button does not exist
addButtonExists();
});
it('MM-T1550 Manage Members option removed for Members in Team Override Scheme', () => {
const teamOverrideSchemeName = `manage_members_${getRandomId()}`;
// # Create a new team override scheme and remove manage members option for members
goToPermissionsAndCreateTeamOverrideScheme(teamOverrideSchemeName, testTeam);
// # Disable mange channel members
deleteOrEditTeamScheme(teamOverrideSchemeName, 'edit');
disablePermission(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS);
saveConfigForScheme(false);
cy.wait(TIMEOUTS.FIVE_SEC);
// * Assert that Manage Members is disabled for members and a message is displayed
visitChannelConfigPage(testChannel);
cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember').
should('exist').
and('have.text', `Manage members for members are disabled in ${teamOverrideSchemeName} Team Scheme.`);
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('be.disabled');
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_GUESTS).should('not.exist');
visitChannel(regularUser, testChannel, testTeam);
viewManageChannelMembersRHS();
// * Add Members button does not exist in manage channel members modal
addButtonDoesNotExists();
// # Enable manage channel members
deleteOrEditTeamScheme(teamOverrideSchemeName, 'edit');
enablePermission(checkboxesTitleToIdMap.ALL_USERS_MANAGE_PUBLIC_CHANNEL_MEMBERS);
saveConfigForScheme(false);
cy.wait(TIMEOUTS.FIVE_SEC);
visitChannelConfigPage(testChannel);
cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember').
should('not.exist');
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('have.class', 'checkbox checked');
cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_GUESTS).should('not.exist');
visitChannel(regularUser, testChannel, testTeam);
viewManageChannelMembersRHS();
// * Add Members button does exist in manage channel members modal
addButtonExists();
});
});

View File

@@ -0,0 +1,230 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @system_console @channel_moderation
import type {Channel} from '@mattermost/types/channels';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {checkboxesTitleToIdMap} from './constants';
import {
deleteOrEditTeamScheme,
disablePermission,
enablePermission,
goToPermissionsAndCreateTeamOverrideScheme,
goToSystemScheme,
saveConfigForChannel,
saveConfigForScheme,
visitChannel,
visitChannelConfigPage,
} from './helpers';
import * as TIMEOUTS from '@/fixtures/timeouts';
import {getAdminAccount} from '@/support/env';
import {getRandomId} from '@/utils';
describe('MM-23102 - Channel Moderation - Post Reactions', () => {
let regularUser: UserProfile;
let guestUser: UserProfile;
let testTeam: Team;
let testChannel: Channel;
const admin = getAdminAccount();
before(() => {
// * Check if server has license
cy.apiRequireLicense();
cy.apiInitSetup().then(({team, channel, user}) => {
regularUser = user;
testTeam = team;
testChannel = channel;
cy.apiCreateGuestUser({}).then(({guest}) => {
guestUser = guest;
cy.apiAddUserToTeam(testTeam.id, guestUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, guestUser.id);
});
// Post a few messages in the channel
visitChannel(admin, testChannel, testTeam);
for (let i = 0; i < 3; i++) {
cy.postMessage(`test message ${Date.now()}`);
}
});
});
});
it('MM-T1543 Post Reactions option for Guests', () => {
visitChannelConfigPage(testChannel);
// # Uncheck the post reactions option for Guests and save
disablePermission(checkboxesTitleToIdMap.POST_REACTIONS_GUESTS);
saveConfigForChannel();
// # Login as a Guest user and visit the same channel
visitChannel(guestUser, testChannel, testTeam);
// # Check Guest user should not have the permission to react to any post on a channel when the option is removed.
// * Guest user should not see the smiley face that allows a user to react to a post
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).trigger('mouseover');
cy.findByTestId('post-reaction-emoji-icon').should('not.exist');
});
// # Visit test channel configuration page and enable post reactions for guest and save
visitChannelConfigPage(testChannel);
enablePermission(checkboxesTitleToIdMap.POST_REACTIONS_GUESTS);
saveConfigForChannel();
visitChannel(guestUser, testChannel, testTeam);
// # Check Guest user should have the permission to react to any post on a channel when the option is allowed.
// * Guest user should see the smiley face that allows a user to react to a post
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).trigger('mouseover');
cy.findByTestId('post-reaction-emoji-icon').should('exist');
});
});
it('MM-T1544 Post Reactions option for Members', () => {
visitChannelConfigPage(testChannel);
// # Uncheck the Create reactions option for Members and save
disablePermission(checkboxesTitleToIdMap.POST_REACTIONS_MEMBERS);
saveConfigForChannel();
// # Login as a Member user and visit the same channel
visitChannel(regularUser, testChannel, testTeam);
// # Check Member user should not have the permission to react to any post on a channel when the option is removed.
// * Member user should not see the smiley face that allows a user to react to a post
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).trigger('mouseover');
cy.findByTestId('post-reaction-emoji-icon').should('not.exist');
});
// # Visit test Channel configuration page and enable post reactions for members and save
visitChannelConfigPage(testChannel);
enablePermission(checkboxesTitleToIdMap.POST_REACTIONS_MEMBERS);
saveConfigForChannel();
// # Login as a Member user and visit the same channel
visitChannel(regularUser, testChannel, testTeam);
// # Check Member user should have the permission to react to any post on a channel when the option is allowed.
// * Member user should see the smiley face that allows a user to react to a post
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).trigger('mouseover');
cy.findByTestId('post-reaction-emoji-icon').should('exist');
});
});
it('MM-T1545 Post Reactions option removed for Guests and Members in System Scheme', () => {
// # Login as sysadmin and visit the Permissions page in the system console.
// # Edit the System Scheme and remove the Post Reaction option for Guests & Save.
goToSystemScheme();
cy.get('.guest').should('be.visible').within(() => {
cy.findByText('Post Reactions').click();
});
saveConfigForScheme();
// # Visit the Channels page and click on a channel.
visitChannelConfigPage(testChannel);
// * Assert that post reaction is disabled for guest and not disabled for members and a message is displayed
cy.findByTestId('admin-channel_settings-channel_moderation-postReactions-disabledGuest').
should('exist').
and('have.text', 'Post reactions for guests are disabled in System Scheme.');
cy.findByTestId(checkboxesTitleToIdMap.POST_REACTIONS_MEMBERS).should('not.be.disabled');
cy.findByTestId(checkboxesTitleToIdMap.POST_REACTIONS_GUESTS).should('be.disabled');
// # Go to system admin page and then go to the system scheme and remove post reaction option for all members and save
goToSystemScheme();
cy.get('#all_users-posts-reactions').click();
saveConfigForScheme();
visitChannelConfigPage(testChannel);
// * Post Reaction option should be disabled for a Members. A message Post reactions for guests & members are disabled in the System Scheme should be displayed.
cy.findByTestId('admin-channel_settings-channel_moderation-postReactions-disabledBoth').
should('exist').
and('have.text', 'Post reactions for members and guests are disabled in System Scheme.');
cy.findByTestId(checkboxesTitleToIdMap.POST_REACTIONS_MEMBERS).should('be.disabled');
cy.findByTestId(checkboxesTitleToIdMap.POST_REACTIONS_GUESTS).should('be.disabled');
// # Login as a Guest user and visit the same channel
visitChannel(guestUser, testChannel, testTeam);
// # Check Guest User should not have the permission to react to any post on any channel when the option is removed from the System Scheme.
// * Guest user should not see the smiley face that allows a user to react to a post
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).trigger('mouseover');
cy.findByTestId('post-reaction-emoji-icon').should('not.exist');
});
// # Login as a Member user and visit the same channel
visitChannel(regularUser, testChannel, testTeam);
// # Check Member should not have the permission to react to any post on any channel when the option is removed from the System Scheme.
// * Member user should not see the smiley face that allows a user to react to a post
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).trigger('mouseover');
cy.findByTestId('post-reaction-emoji-icon').should('not.exist');
});
});
// GUEST PERMISSIONS DON'T EXIST ON TEAM OVERRIDE SCHEMES SO GUEST PORTION NOT IMPLEMENTED!
// ONLY THE MEMBERS PORTION OF THIS TEST IS IMPLEMENTED
it('MM-T1546_4 Post Reactions option removed for Guests & Members in Team Override Scheme', () => {
const teamOverrideSchemeName = `post_reactions_${getRandomId()}`;
// # Create a new team override scheme
goToPermissionsAndCreateTeamOverrideScheme(teamOverrideSchemeName, testTeam);
visitChannelConfigPage(testChannel);
// * Assert that post reaction is disabled for members
cy.findByTestId(checkboxesTitleToIdMap.POST_REACTIONS_MEMBERS).should('have.class', 'checkbox checked');
// # Login as a Member user and visit the same channel
visitChannel(regularUser, testChannel, testTeam);
// # Check Member should have the permission to react to any post on any channel in that team
// * User should see the smiley face that allows a user to react to a post
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).trigger('mouseover');
cy.findByTestId('post-reaction-emoji-icon').should('exist');
});
// # Go to system admin page and then go to the system scheme and remove post reaction option for all members and save
deleteOrEditTeamScheme(teamOverrideSchemeName, 'edit');
cy.get('#all_users-posts-reactions').click();
saveConfigForScheme(false);
// # Wait until the groups have been saved (since it redirects you)
cy.wait(TIMEOUTS.ONE_SEC);
visitChannelConfigPage(testChannel);
// * Assert that post reaction is disabled for members
cy.findByTestId(checkboxesTitleToIdMap.POST_REACTIONS_MEMBERS).should('have.class', 'checkbox disabled');
// # Login as a Member user and visit the same channel
visitChannel(regularUser, testChannel, testTeam);
// # Check Member should not have the permission to react to any post on any channel in that team
// * User should not see the smiley face that allows a user to react to a post
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).trigger('mouseover');
cy.findByTestId('post-reaction-emoji-icon').should('not.exist');
});
});
});

View File

@@ -0,0 +1,101 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console @channel_moderation
import type {Channel} from '@mattermost/types/channels';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {checkBoxes} from './constants';
import {
disableAllChannelModeratedPermissions,
enableAllChannelModeratedPermissions,
saveConfigForChannel,
} from './helpers';
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Channel Moderation', () => {
let guestUser: UserProfile;
let testTeam: Team;
let testChannel: Channel;
before(() => {
// * Check if server has license
cy.apiRequireLicense();
cy.apiInitSetup().then(({team, channel}) => {
testTeam = team;
testChannel = channel;
cy.apiCreateGuestUser({}).then(({guest}) => {
guestUser = guest;
cy.apiAddUserToTeam(testTeam.id, guestUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, guestUser.id);
});
});
});
});
it('MM-22276 - Enable and Disable all channel moderated permissions', () => {
// # Go to system admin page and to channel configuration page of test channel
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/channels');
// # Search for the channel.
cy.get('.DataGrid_searchBar').within(() => {
cy.findByPlaceholderText('Search').type(`${testChannel.name}{enter}`);
});
cy.findByText('Edit').click();
// # Wait until the groups retrieved and show up
cy.wait(TIMEOUTS.ONE_SEC);
// # Check all the boxes currently unchecked (align with the system scheme permissions)
enableAllChannelModeratedPermissions();
// # Save if possible (if previous test ended abruptly all permissions may already be enabled)
saveConfigForChannel(testChannel.display_name);
// # Wait until the groups retrieved and show up
cy.wait(TIMEOUTS.ONE_SEC);
// * Ensure all checkboxes are checked
checkBoxes.forEach((buttonId) => {
cy.findByTestId(buttonId).should('have.class', 'checked');
});
// # Uncheck all the boxes currently checked
disableAllChannelModeratedPermissions();
// # Save the page and wait till saving is done
saveConfigForChannel(testChannel.display_name);
// # Wait until the groups retrieved and show up
cy.wait(TIMEOUTS.ONE_SEC);
// * Ensure all checkboxes have the correct unchecked state
checkBoxes.forEach((buttonId) => {
// * Ensure all checkboxes are unchecked
cy.findByTestId(buttonId).should('not.have.class', 'checked');
// * Ensure Channel Mentions are disabled due to Create Posts
if (buttonId.includes('use_channel_mentions')) {
cy.findByTestId(buttonId).should('be.disabled');
return;
}
// * Ensure all other check boxes are still enabled
cy.findByTestId(buttonId).should('not.be.disabled');
});
});
});

View File

@@ -0,0 +1,87 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console @high_availability @not_cloud
describe('Cluster', () => {
before(() => {
cy.shouldNotRunOnCloudEdition();
// * Check if server has license
cy.apiRequireLicense();
// # Reset Gossip Encryption
cy.apiUpdateConfig({
ClusterSettings: {
Enable: null,
EnableGossipEncryption: null,
},
});
// # Visit high availability system console page
cy.visit('/admin_console/environment/high_availability');
});
it('SC25050 - Can change Gossip Encryption', () => {
cy.findByTestId('EnableGossipEncryption').scrollIntoView().should('be.visible').within(() => {
// * Verify that setting is visible and matches text content
cy.get('.control-label').should('be.visible').and('have.text', 'Enable Gossip encryption:');
// * Verify that the help setting is visible and matches text content
const contents = 'When true, all communication through the gossip protocol will be encrypted.';
cy.get('.help-text').should('be.visible').and('have.text', contents);
// * Verify that Gossip Encryption is set to true by default
cy.get('#EnableGossipEncryptiontrue').should('have.attr', 'checked');
});
// # Enable Gossip Encryption
cy.apiUpdateConfig({
ClusterSettings: {
Enable: true,
EnableGossipEncryption: true,
},
});
cy.reload();
cy.findByTestId('EnableGossipEncryption').scrollIntoView().should('be.visible').within(() => {
// * Verify that Gossip Encryption is set to true
cy.get('#EnableGossipEncryptiontrue').should('have.attr', 'checked');
});
});
it('Can change Gossip Compression', () => {
cy.findByTestId('EnableGossipCompression').scrollIntoView().should('be.visible').within(() => {
// * Verify that setting is visible and matches text content
cy.get('.control-label').should('be.visible').and('have.text', 'Enable Gossip compression:');
// * Verify that the help setting is visible and matches text content
const contents = 'When true, all communication through the gossip protocol will be compresssed. It is recommended to keep this flag disabled.';
cy.get('.help-text').should('be.visible').and('have.text', contents);
// * Verify that Gossip Compression is set to true by default
cy.get('#EnableGossipCompressiontrue').should('have.attr', 'checked');
});
// # Disable Gossip Compression
cy.apiUpdateConfig({
ClusterSettings: {
Enable: true,
EnableGossipCompression: false,
},
});
cy.reload();
cy.findByTestId('EnableGossipCompression').scrollIntoView().should('be.visible').within(() => {
// * Verify that Gossip Compression is set to false
cy.get('#EnableGossipCompressionfalse').should('have.attr', 'checked');
});
});
});

View File

@@ -0,0 +1,148 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console @compliance_export
import {verifyExportedMessagesCount, editLastPost} from './helpers';
describe('Compliance Export', () => {
let teamName;
before(() => {
cy.apiRequireLicenseForFeature('Compliance');
cy.apiUpdateConfig({
MessageExportSettings: {
ExportFormat: 'csv',
DownloadExportResults: true,
},
});
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
cy.apiLogin(sysadmin);
cy.apiInitSetup().then(({team}) => {
teamName = team.name;
});
// # Visit a channel and post a message so it has something to be exported initially
cy.visit('/');
cy.postMessage('hello');
// # Go to compliance page, enable export and do initial export
cy.uiGoToCompliancePage();
cy.uiEnableComplianceExport();
cy.uiExportCompliance();
});
});
it('MM-T1177_1 - Compliance export should include updated posts after editing multiple times, exporting multiple times', () => {
// # Visit town-square channel
cy.visit(`/${teamName}/channels/town-square`);
// # Post messages
cy.postMessage('Testing one');
cy.postMessage('Testing two');
// # Edit last post
editLastPost('This is Edit Post');
// # Go to compliance page and export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// * 3 messages should be exported
verifyExportedMessagesCount('3');
});
it('MM-T1177_2 - Compliance export should include updated posts after editing multiple times, exporting multiple times', () => {
// # Visit town-square channel
cy.visit(`/${teamName}/channels/town-square`);
// # Post a Message
cy.postMessage('Testing');
// # Edit last post
editLastPost('This is Edit One');
// # Post a Message
cy.postMessage('This is Edit Two');
// # Go to compliance page and export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// * 3 messages should be exported
verifyExportedMessagesCount('3');
});
it('MM-T1177_3 - Compliance export should include updated posts after editing multiple times, exporting multiple times', () => {
// # Navigate to a team and post a message
cy.visit(`/${teamName}/channels/town-square`);
cy.postMessage('Testing');
// # Go to compliance page and export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Editing previously exported post
cy.visit(`/${teamName}/channels/town-square`);
editLastPost('This is Edit Three');
// # Go to compliance page and export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// * 2 messages should be exported
verifyExportedMessagesCount('2');
});
it('MM-T1177_4 - Compliance export should include updated posts after editing multiple times, exporting multiple times', () => {
// # Navigate to a team and post a Message
cy.visit(`/${teamName}/channels/town-square`);
cy.postMessage('Testing');
// # Go to compliance page and export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Editing previously exported post
cy.visit(`/${teamName}/channels/town-square`);
editLastPost('This is Edit Three');
// # Post new message
cy.postMessage('This is the post');
// # Go to compliance page and export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// * 3 messages should be exported
verifyExportedMessagesCount('3');
});
it('MM-T1177_5 - Compliance export should include updated posts after editing multiple times, exporting multiple times', () => {
// # Visit town-square channel
cy.visit(`/${teamName}/channels/town-square`);
// # Navigate to a team and post a message
cy.postMessage('Testing');
// # Editing previously exported post
editLastPost('This is Edit Four');
editLastPost('This is Edit Five');
// # Go to compliance page and export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// * 3 messages should be exported
verifyExportedMessagesCount('3');
});
});

View File

@@ -0,0 +1,171 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console @compliance_export
import {verifyExportedMessagesCount, gotoTeamAndPostImage} from './helpers';
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Compliance Export', () => {
let teamName;
before(() => {
cy.apiRequireLicenseForFeature('Compliance');
cy.apiUpdateConfig({
MessageExportSettings: {
ExportFormat: 'csv',
DownloadExportResults: true,
},
});
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
cy.apiLogin(sysadmin);
cy.apiInitSetup().then(({team}) => {
teamName = team.name;
});
// # Visit a channel and post a message so it has something to be exported initially
cy.visit('/');
cy.postMessage('hello');
// # Go to compliance page, enable export and do initial export
cy.uiGoToCompliancePage();
cy.uiEnableComplianceExport();
cy.uiExportCompliance();
});
});
it('MM-T3435 - Download Compliance Export Files - CSV Format', () => {
// # Navigate to a team and post an attachment
cy.visit(`/${teamName}/channels/town-square`);
gotoTeamAndPostImage();
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Get the first row
cy.get('.job-table__table').find('tbody > tr').eq(0).as('firstRow');
// # Get the download link
cy.get('@firstRow').findByText('Download').parents('a').should('exist').then((fileAttachment) => {
const fileURL = fileAttachment.attr('href');
// * Download and verify export file properties
cy.apiDownloadFileAndVerifyContentType(fileURL);
});
});
it('MM-T3438 - Download Compliance Export Files when 0 messages exported', () => {
// # Navigate to a team and post an attachment
cy.visit(`/${teamName}/channels/town-square`);
gotoTeamAndPostImage();
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Get the first row
cy.get('.job-table__table').find('tbody > tr').eq(0).as('firstRow');
// # Get the download link
cy.get('@firstRow').findByText('Download').parents('a').should('exist').then((fileAttachment) => {
const fileURL = fileAttachment.attr('href');
// * Download and verify export file properties
cy.apiDownloadFileAndVerifyContentType(fileURL);
// # Export compliance again
cy.uiExportCompliance();
// * Download link should not exist this time
cy.get('.job-table__table').
find('tbody > tr:eq(0)').
findByText('Download').should('not.exist');
});
});
it('MM-T1168 - Compliance Export - Run Now, entry appears in job table', () => {
// # Navigate to a team and post an attachment
cy.visit(`/${teamName}/channels/town-square`);
gotoTeamAndPostImage();
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Get the first row
cy.get('.job-table__table').find('tbody > tr').eq(0).as('firstRow');
// * Verify table header
cy.get('@firstheader').within(() => {
cy.get('th:eq(0)').should('have.text', 'Status');
cy.get('th:eq(1)').should('have.text', 'Finish Time');
cy.get('th:eq(2)').should('have.text', 'Run Time');
cy.get('th:eq(3)').should('have.text', 'Files');
cy.get('th:eq(4)').should('have.text', 'Details');
});
// * Verify first row (last run job) data
cy.get('@firstRow').within(() => {
cy.get('td:eq(0)').should('have.text', 'Success');
cy.get('td:eq(2)').contains('seconds');
cy.get('td:eq(3)').should('have.text', 'Download');
cy.get('td:eq(4)').should('have.text', '1 message exported.');
});
});
it('MM-T1169 - Compliance Export - CSV and Global Relay', () => {
// # Navigate to a team and post an attachment
cy.visit(`/${teamName}/channels/town-square`);
gotoTeamAndPostImage();
// # Post 9 text messages
Cypress._.times(9, (i) => {
cy.postMessage(`This is the post ${i}`);
});
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// * 10 messages should be exported
verifyExportedMessagesCount('10');
});
it('MM-T1165 - Compliance Export - Fields disabled when disabled', () => {
// # Go to compliance page and disable export
cy.uiGoToCompliancePage();
cy.findByTestId('enableComplianceExportfalse').click();
// * Verify that exported button is disabled
cy.findByRole('button', {name: /run compliance export job now/i}).should('be.not.enabled');
});
it('MM-T1167 - Compliance Export job can be canceled', () => {
// # Go to compliance page and enable export
cy.uiGoToCompliancePage();
cy.uiEnableComplianceExport();
// # Click the export job button
cy.findByRole('button', {name: /run compliance export job now/i}).click();
// # Click X button to cancel import
cy.findByTitle(/cancel/i, {timeout: TIMEOUTS.FIVE_SEC}).should('be.visible').click();
// # Get the first row
cy.get('.job-table__table').find('tbody > tr').eq(0).as('firstRow');
// * Canceled text should be shown in the first row of the table
cy.get('@firstRow').find('td:eq(0)').should('have.text', 'Canceled');
});
});

View File

@@ -0,0 +1,306 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
import {
gotoGlobalPolicy,
editGlobalPolicyMessageRetention,
runDataRetentionAndVerifyPostDeleted,
verifyPostNotDeleted,
} from './helpers';
describe('Data Retention - Global and Custom Policy Only', () => {
let testTeam;
let testChannel;
let users;
let channelA;
let channelB;
let channelC;
let newTeam;
const postText = 'This is testing';
before(() => {
cy.apiRequireLicenseForFeature('DataRetention');
cy.apiUpdateConfig({
ServiceSettings: {
EnableUserAccessTokens: true,
},
});
cy.apiInitSetup().then(({team, channel, user}) => {
testTeam = team;
testChannel = channel;
users = user.id;
});
});
beforeEach(() => {
cy.apiDeleteAllCustomRetentionPolicies();
cy.intercept({
method: 'POST',
url: '/api/v4/data_retention/policies',
}).as('createCustomPolicy');
// # Go to data retention settings
cy.uiGoToDataRetentionPage();
});
it('MM-T4093 - Assign Global Policy = 10 Days & Custom Policy = None to channel', () => {
gotoGlobalPolicy();
// # Edit global policy message retention
editGlobalPolicyMessageRetention('10', '10 days');
// * Verify there is no any team and channel assigned
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.get('.DataGrid_rows .DataGrid_empty').first().should('contain.text', 'No items found');
});
let testChannel2;
cy.apiCreateChannel(testTeam.id, 'test_channel', 'testChannel2').then(({channel}) => {
testChannel2 = channel;
});
// # Create 13 days older post
// # Get Epoch value
const createDate = new Date().setDate(new Date().getDate() - 13);
const createDate2 = new Date().setDate(new Date().getDate() - 7);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDate);
cy.apiPostWithCreateDate(testChannel2.id, postText, token, createDate2);
// * Run the job and verify 13 days older post has been deleted
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText);
// * Verify 7 days older post is not deleted
verifyPostNotDeleted(testTeam, testChannel2, postText);
});
});
it('MM-T4099 - Assign Global Policy = 10 Days & Custom Policy = 5 days to Channels', () => {
// # Edit Global Policy to 10 days
gotoGlobalPolicy();
editGlobalPolicyMessageRetention('10', '10 days');
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('MyPolicy', 'days', '5');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
// # Create channel-A
cy.apiCreateChannel(testTeam.id, 'channel-test', 'GlobalChannel-1').then(({channel}) => {
channelA = channel;
});
// # Create channel-B
cy.apiCreateChannel(testTeam.id, 'channel-test', 'Custom-Channel1').then(({channel}) => {
channelB = channel;
});
// # Create channel-C
cy.apiCreateChannel(testTeam.id, 'channel-test', 'Global-Channel-2').then(({channel}) => {
channelC = channel;
});
// * Verify create policy api response
cy.wait('@createCustomPolicy').then((interception) => {
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'MyPolicy', '5 days', '1 team, 0 channels');
});
});
// # Create more than 3,7, and 12 days older post
// # Get Epoch value
const createDate1 = new Date().setDate(new Date().getDate() - 7);
const createDate2 = new Date().setDate(new Date().getDate() - 3);
const createDate3 = new Date().setDate(new Date().getDate() - 12);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDate1);
cy.apiPostWithCreateDate(channelA.id, postText, token, createDate2);
cy.apiPostWithCreateDate(channelB.id, postText, token, createDate2);
cy.apiPostWithCreateDate(channelC.id, postText, token, createDate3);
// * Run the job and verify 7 days older post is deleted
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText);
// * Verify 7 days older post is not deleted
verifyPostNotDeleted(testTeam, channelA, postText);
// * Verify 3 days older post is not deleted
verifyPostNotDeleted(testTeam, channelB, postText);
// * Verify 12 days older post is deleted
verifyPostNotDeleted(testTeam, channelC, postText, 1);
});
});
it('MM-T4101 - Assign Global Policy = 5 days & Custom Policy = None to Teams', () => {
// # Edit global policy to 5 days
gotoGlobalPolicy();
editGlobalPolicyMessageRetention('5', '5 days');
// * Verify there is no any team and channel assigned
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.get('.DataGrid_rows .DataGrid_empty').first().should('contain.text', 'No items found');
});
// # Create new channel
let testChannel2;
cy.apiCreateChannel(testTeam.id, 'channel-test', 'OtherChannel ').then(({channel}) => {
testChannel2 = channel;
});
// # Create new Team and Channel
cy.apiCreateTeam('team', 'Team1').then(({team}) => {
cy.apiCreateChannel(team.id, 'test_channel', 'Channel-A').then(({channel}) => {
newTeam = team;
channelA = channel;
});
});
// # Create 3 and 7 days older posts
// # Get Epoch value
const createDays1 = new Date().setDate(new Date().getDate() - 7);
const createDays2 = new Date().setDate(new Date().getDate() - 3);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDays1);
cy.apiPostWithCreateDate(testChannel2.id, postText, token, createDays1);
cy.apiPostWithCreateDate(channelA.id, postText, token, createDays2);
// * Run the job and verify 7 days older posts have been deleted
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText);
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel2, postText);
// * Verify 3 days older post was not deleted
verifyPostNotDeleted(newTeam, channelA, postText);
});
});
it('MM-T4103 - Assign Global Policy = 10 days & Custom Policy = 5 days to Team', () => {
// # Edit global policy to 5 days
gotoGlobalPolicy();
editGlobalPolicyMessageRetention('10', '10 days');
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('MyPolicy', 'days', '5');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'MyPolicy', '5 days', '1 team, 0 channels');
});
});
// # Create channel-A
cy.apiCreateChannel(testTeam.id, 'channel-test', 'GlobalChannel-1').then(({channel}) => {
channelA = channel;
});
// # Create a new Team and Channel
cy.apiCreateTeam('team', 'Team1').then(({team}) => {
newTeam = team;
cy.apiCreateChannel(newTeam.id, 'test_channel', 'Channel-A').then(({channel}) => {
channelB = channel;
});
// # Create a new channel in newTeam
cy.apiCreateChannel(newTeam.id, 'channel-test', 'Global-Channel-2').then(({channel}) => {
channelC = channel;
});
});
// # Create more than 3,7, and 12 days older posts
// # Get Epoch value
const createDate1 = new Date().setDate(new Date().getDate() - 7);
const createDate2 = new Date().setDate(new Date().getDate() - 3);
const createDate3 = new Date().setDate(new Date().getDate() - 12);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDate1);
cy.apiPostWithCreateDate(channelA.id, postText, token, createDate2);
cy.apiPostWithCreateDate(channelB.id, postText, token, createDate1);
cy.apiPostWithCreateDate(channelC.id, postText, token, createDate3);
// * Run the job and verify 7 days older post is deleted
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText);
// * Verify 7 days older post is not deleted
verifyPostNotDeleted(testTeam, channelA, postText);
// * Verify 3 days older post is not deleted
verifyPostNotDeleted(newTeam, channelB, postText);
// * Verify 12 days older post is deleted
verifyPostNotDeleted(newTeam, channelC, postText, 1);
});
});
it('MM-T4096 - Assign Global Policy = 1 Year & Custom Policy = None to channel', () => {
// # Edit global policy to 1 year
gotoGlobalPolicy();
editGlobalPolicyMessageRetention('365', '1 year');
// * Verify there is no any team and channel assigned
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.get('.DataGrid_rows .DataGrid_empty').first().should('contain.text', 'No items found');
});
// # Create a new channel
cy.apiCreateChannel(testTeam.id, 'channel-test', 'GlobalChannel ').then(({channel}) => {
channelA = channel;
});
// # Create less than one year and one year older post
// # Get Epoch value
const createDate1 = new Date().setMonth(new Date().getMonth() - 14);
const createDate2 = new Date().setMonth(new Date().getMonth() - 10);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDate1);
cy.apiPostWithCreateDate(channelA.id, postText, token, createDate2);
// * Run the job and verify 1 year older post has been deleted
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText);
// * Verify less than one year post was not deleted
verifyPostNotDeleted(testTeam, channelA, postText);
});
});
});

View File

@@ -0,0 +1,350 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
import {
runDataRetentionAndVerifyPostDeleted,
gotoGlobalPolicy,
editGlobalPolicyMessageRetention,
verifyPostNotDeleted,
} from './helpers';
describe('Data Retention - Custom Policy Only', () => {
let testTeam;
let testChannel;
let users;
const postText = 'This is testing';
before(() => {
cy.apiRequireLicenseForFeature('DataRetention');
cy.apiUpdateConfig({
ServiceSettings: {
EnableUserAccessTokens: true,
},
});
cy.apiInitSetup().then(({team, channel, user}) => {
testTeam = team;
testChannel = channel;
users = user.id;
});
});
beforeEach(() => {
cy.apiDeleteAllCustomRetentionPolicies();
cy.intercept({
method: 'POST',
url: '/api/v4/data_retention/policies',
}).as('createCustomPolicy');
// # Go to data retention settings page
cy.uiGoToDataRetentionPage();
});
it('MM-T4097 - Assign Global Policy = Forever & Custom Policy = 10 days to Channel', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('MyPolicy', 'days', '10');
// # Add channel to the policy
cy.uiAddChannelsToCustomPolicy([testChannel.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'MyPolicy', '10 days', '0 teams, 1 channel');
});
});
// # Create new Channel
let channelB;
cy.apiCreateChannel(testTeam.id, 'test_channel', 'channelB').then(({channel}) => {
channelB = channel;
});
// # Create 12 days older posts
// # Get Epoch value
const createDate = new Date().setDate(new Date().getDate() - 12);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDate);
cy.apiPostWithCreateDate(channelB.id, postText, token, createDate);
// * Run the job and verify 12 days older post is deleted
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText);
// * Verify 12 days older post is not deleted
verifyPostNotDeleted(testTeam, channelB, postText);
});
});
it('MM-T4098 - Assign Global Policy = Forever & Custom Policy = 1 year to Channels', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('MyPolicy', 'days', '365');
// # Add channel to the policy
cy.uiAddChannelsToCustomPolicy([testChannel.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'MyPolicy', '1 year', '0 teams, 1 channel');
});
});
// # Create new Channel
let channelB;
cy.apiCreateChannel(testTeam.id, 'test_channel', ' channelB').then(({channel}) => {
channelB = channel;
});
// # Create more than one year older posts
// # Get Epoch value
const createDate = new Date().setMonth(new Date().getMonth() - 14);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDate);
cy.apiPostWithCreateDate(channelB.id, postText, token, createDate);
// * Run the job and verify more than one year older post is deleted
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText);
// * Verify more than one year older post is not deleted
verifyPostNotDeleted(testTeam, channelB, postText);
});
});
it('MM-T4105 - Assign Global Policy = Forever & Custom Policy = 1 year to Teams', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('MyPolicy', 'days', '365');
// # Add a team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'MyPolicy', '1 year', '1 team, 0 channels');
});
});
// # Create new Team and Channel
let newTeam;
let channelB;
cy.apiCreateTeam('team', 'Team1').then(({team}) => {
cy.apiCreateChannel(team.id, 'test_channel', 'channelB').then(({channel}) => {
newTeam = team;
channelB = channel;
});
});
// # Create more than one year older posts
// # Get Epoch value
const createDate = new Date().setMonth(new Date().getMonth() - 14);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDate);
cy.apiPostWithCreateDate(channelB.id, postText, token, createDate);
// * Run the job and verify more than one year older post has been deleted
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText);
// * Verify more then one year older post is not deleted
verifyPostNotDeleted(newTeam, channelB, postText);
});
});
it('MM-T4102 - Assign Global Policy = Forever & Custom Policy = 30 days to Teams', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('MyPolicy', 'days', '30');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'MyPolicy', '30 days', '1 team, 0 channels');
});
});
// # Create new Team and Channel
let channelB;
let newTeam;
cy.apiCreateTeam('team', 'Team1').then(({team}) => {
cy.apiCreateChannel(team.id, 'test_channel', 'channelB').then(({channel}) => {
channelB = channel;
newTeam = team;
});
});
// # Create more than one year older post
// # Get Epoch value
const createDate = new Date().setDate(new Date().getDate() - 32);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDate);
cy.apiPostWithCreateDate(channelB.id, postText, token, createDate);
// * Run the job and verify 32 days older post is deleted
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText);
// * Verify 32 days old post is not deleted
verifyPostNotDeleted(newTeam, channelB, postText);
});
});
it('MM-T4104 - Assign Global policy = Forever & Custom Policy = 5 and 10 days to Teams', () => {
// # Create a new Channel
let testChannel2;
cy.apiCreateChannel(testTeam.id, 'test_channel', 'TestChannel2').then(({channel}) => {
testChannel2 = channel;
});
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('MyPolicy', 'days', '5');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'MyPolicy', '5 days', '1 team, 0 channels');
});
});
// # Create new Team and Channels
let newTeam;
let channelA;
let channelB;
cy.apiCreateTeam('team', 'Team1').then(({team}) => {
newTeam = team;
// # Create new Channel
cy.apiCreateChannel(team.id, 'test_channel', 'test_channelC').then(({channel}) => {
channelB = channel;
});
cy.apiCreateChannel(team.id, 'test_channel', 'Channel-A').then(({channel}) => {
channelA = channel;
// # Create second policy
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('MyPolicy1', 'days', '10');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([newTeam.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'MyPolicy1', '10 days', '1 team, 0 channels');
});
});
});
});
// # Create more 3,7, and 12 days older posts
// # Get Epoch values
const createDate1 = new Date().setDate(new Date().getDate() - 7);
const createDate2 = new Date().setDate(new Date().getDate() - 3);
const createDate3 = new Date().setDate(new Date().getDate() - 12);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDate1);
cy.apiPostWithCreateDate(testChannel2.id, postText, token, createDate2);
cy.apiPostWithCreateDate(channelA.id, postText, token, createDate3);
cy.apiPostWithCreateDate(channelB.id, postText, token, createDate2);
// * Run the job and Verify 7 days older post in testChannel is deleted
runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText);
// * Verify 3 days older post in testChennel2 is not deleted
verifyPostNotDeleted(testTeam, testChannel2, postText);
// * Verify 12 days older post in ChannelA is deleted
cy.visit(`/${newTeam.name}/channels/${channelA.name}`);
cy.findAllByTestId('postView').should('have.length', 1);
cy.findAllByTestId('postView').should('not.contain', postText);
// * Verify 3 days older post in channelB is not deleted
verifyPostNotDeleted(newTeam, channelB, postText);
});
});
it('MM-T4019 - Global Data Retention policy', () => {
[
{input: '365', result: '1 year'},
{input: '700', result: '700 days'},
{input: '730', result: '2 years'},
{input: '600', result: '600 days'},
].forEach(({input, result}) => {
gotoGlobalPolicy();
// # Edit global policy message retention
editGlobalPolicyMessageRetention(input, result);
});
});
});

View File

@@ -0,0 +1,107 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
import {
runDataRetentionAndVerifyPostDeleted,
gotoGlobalPolicy,
editGlobalPolicyMessageRetention,
} from './helpers';
describe('Data Retention - Global and Custom Policy', () => {
let testTeam;
let testChannel;
let users;
const postText = 'This is testing';
before(() => {
cy.apiRequireLicenseForFeature('DataRetention');
cy.apiUpdateConfig({
ServiceSettings: {
EnableUserAccessTokens: true,
},
});
cy.apiInitSetup().then(({team, channel, user}) => {
testTeam = team;
testChannel = channel;
users = user.id;
});
});
beforeEach(() => {
cy.apiDeleteAllCustomRetentionPolicies();
cy.intercept({
method: 'POST',
url: '/api/v4/data_retention/policies',
}).as('createCustomPolicy');
// # Go to data retention settings page
cy.uiGoToDataRetentionPage();
});
it('MM-T4100 - Assign Global Policy = 5 days & Custom Policy = 10 days to channels', () => {
let newChannel;
let newTeam;
// # Edit Global Policy to 5 days
gotoGlobalPolicy();
editGlobalPolicyMessageRetention('5', '5 days');
// # Create a new team
cy.apiCreateTeam('team', 'Team1').then(({team}) => {
cy.apiCreateChannel(team.id, 'test_channel', 'Channel-A').then(({channel}) => {
newChannel = channel;
newTeam = team;
});
});
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('MyPolicy', 'days', '10');
// # Add channel to the policy
cy.uiAddChannelsToCustomPolicy([testChannel.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'MyPolicy', '10 days', '0 teams, 1 channel');
});
});
// # Create more than 7 days older post
// # Get Epoch value
const createDate = new Date().setDate(new Date().getDate() - 7);
cy.apiCreateToken(users).then(({token}) => {
// # Create posts
cy.apiPostWithCreateDate(newChannel.id, postText, token, createDate);
cy.apiPostWithCreateDate(testChannel.id, postText, token, createDate);
// * Run the job and verify 7 days older post in newChannel has been deleted
runDataRetentionAndVerifyPostDeleted(newTeam, newChannel, postText);
// * Verify 7 days older post in testChannel was not deleted
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
cy.findAllByTestId('postView').should('have.length', 2);
cy.findAllByTestId('postView').should('contain', postText);
});
});
});

View File

@@ -0,0 +1,561 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @system_console @with_feature_flag
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Data Retention', () => {
let testTeam;
let testChannel;
before(() => {
cy.apiRequireLicenseForFeature('DataRetention');
cy.apiInitSetup().then(({team, channel}) => {
testTeam = team;
testChannel = channel;
});
});
beforeEach(() => {
cy.apiDeleteAllCustomRetentionPolicies();
cy.intercept({
method: 'POST',
url: '/api/v4/data_retention/policies',
}).as('createCustomPolicy');
// # Go to data retention settings page
cy.uiGoToDataRetentionPage();
});
describe('Custom policy creation', () => {
it('MM-T4005 - Create custom policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 1', 'days', '60');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Add 1 channel to the policy from the modal
cy.uiAddRandomChannelToCustomPolicy(1);
// # Save policy
cy.uiGetButton('Save').click();
// * Check custom policy table is visible
cy.get('#custom_policy_table .DataGrid').should('be.visible');
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy response
cy.uiVerifyPolicyResponse(interception.response.body, 1, 1, 60, 'Policy 1');
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(interception.response.body.id, 'Policy 1', '60 days', '1 team, 1 channel');
});
});
});
it('MM-T4006 - Policies count', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 1', 'days', '60');
// # Add channel to the policy
cy.uiAddRandomChannelToCustomPolicy();
// # Save policy
cy.uiGetButton('Save').click();
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 2', 'days', '160');
// # Add channel to the policy
cy.uiAddRandomChannelToCustomPolicy();
// # Save policy
cy.uiGetButton('Save').click();
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 3', 'days', '100');
// # Add channel to the policy
cy.uiAddRandomChannelToCustomPolicy();
// # Save policy
cy.uiGetButton('Save').click();
// * Assert the pagination is correct
cy.findByText('1 - 3 of 3').scrollIntoView().should('be.visible');
cy.apiGetCustomRetentionPolicies().then((result) => {
// * Assert the total policy count is 3
expect(result.body.total_count).to.equal(3);
});
});
it('MM-T4007 - show policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 1', 'days', '60');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Add 1 channel to the policy from the modal
cy.uiAddRandomChannelToCustomPolicy(1);
// # Save policy
cy.uiGetButton('Save').click();
cy.findByText('1 - 1 of 1').scrollIntoView().should('be.visible');
});
it('MM-T4008 - Update custom policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 2', 'years', '2');
// # Add team to the policy
cy.uiAddRandomTeamToCustomPolicy();
// # Save policy
cy.uiGetButton('Save').click();
// * Check custom policy table is visible
cy.get('#custom_policy_table .DataGrid').should('be.visible');
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
cy.uiVerifyPolicyResponse(interception.response.body, 1, 0, 730, 'Policy 2');
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 2', '2 years', '1 team, 0 channels');
// # Go to edit custom data retention page
cy.uiClickEditCustomPolicyRow(policyId);
});
// * Verify custom policy page header
cy.get('.DataRetentionSettings .admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Custom Retention Policy');
// # Remove team from policy
cy.get('.PolicyTeamsList .DataGrid').within(() => {
cy.findByRole('link', {name: 'Remove'}).should('be.visible').click();
});
// # Add channel to the policy
cy.uiAddRandomChannelToCustomPolicy();
// # Save policy
cy.uiGetButton('Save').click();
// * Check custom policy table is visible
cy.get('#custom_policy_table .DataGrid').should('be.visible');
// * Verify custom policy data table
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 2', '2 years', '0 teams, 1 channel');
});
// # Send GET request to verify policy updated correctly
cy.apiGetCustomRetentionPolicy(policyId).then((result) => {
// * Assert response body team_count is 0
expect(result.body.team_count).to.equal(0);
// * Assert response body channel_count is 1
expect(result.body.channel_count).to.equal(1);
// * Assert response body post_duration is 730
expect(result.body.post_duration).to.equal(730);
// * Assert response body display_name is correct
expect(result.body.display_name).to.equal('Policy 2');
});
});
});
it('MM-T4009 - Delete a custom policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Add policy name
cy.uiGetTextbox('Policy name').clear().type('Policy 3');
// # Add channel to the policy
cy.uiAddRandomChannelToCustomPolicy();
// # Save policy
cy.uiGetButton('Save').click();
// * Check custom policy table is visible
cy.get('#custom_policy_table .DataGrid').should('be.visible');
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
cy.uiVerifyPolicyResponse(interception.response.body, 0, 1, -1, 'Policy 3');
const policyId = interception.response.body.id;
cy.get('#custom_policy_table .DataGrid').within(() => {
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 3', 'Keep forever', '0 teams, 1 channel');
cy.get(`#customWrapper-${policyId}`).trigger('mouseover').click();
// # Delete a policy
cy.findByRole('button', {name: 'Delete'}).should('be.visible').click();
// # Wait for deletion
cy.wait(TIMEOUTS.ONE_SEC);
// * Assert the policy row no longer exists
cy.get(`#customDescription-${policyId}`).should('not.exist');
});
});
});
});
describe('Teams in a custom Policy', () => {
it('MM-T4010 - Show policy teams information', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 1', 'years', '2');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
cy.uiVerifyPolicyResponse(interception.response.body, 1, 0, 730, 'Policy 1');
const policyId = interception.response.body.id;
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 1', '2 years', '1 team, 0 channels');
// # Go to edit custom data retention page
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.uiClickEditCustomPolicyRow(policyId);
});
cy.get('.DataRetentionSettings .admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Custom Retention Policy');
// * Verify Team data table exists
cy.get('.PolicyTeamsList .DataGrid').within(() => {
cy.get(`#team-name-${testTeam.id}`).should('be.visible');
});
// * GET the team for the policy and verify it is correct
cy.apiGetCustomRetentionPolicyTeams(policyId).then((result) => {
expect(result.body.teams[0].id).to.equal(testTeam.id);
});
});
});
it('MM-T4012 - Search teams in policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 1', 'years', '2');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Add channel to the policy
cy.uiAddRandomTeamToCustomPolicy();
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
cy.uiVerifyPolicyResponse(interception.response.body, 2, 0, 730, 'Policy 1');
const policyId = interception.response.body.id;
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 1', '2 years', '2 teams, 0 channels');
// # Go to edit custom data retention page
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.uiClickEditCustomPolicyRow(policyId);
});
cy.get('.DataRetentionSettings .admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Custom Retention Policy');
cy.get('.PolicyTeamsList .DataGrid').within(() => {
// # Find the team table search box and type in team name
cy.findByRole('textbox').should('be.visible').clear().type(testTeam.name);
cy.wait(TIMEOUTS.ONE_SEC);
// * Verify the team is visible after search
cy.get(`#team-name-${testTeam.id}`).should('be.visible').invoke('text').should('include', testTeam.display_name);
});
// * Search the team for the policy using the API and verify it is correct
cy.apiSearchCustomRetentionPolicyTeams(policyId, testTeam.display_name).then((result) => {
expect(result.body[0].id).to.equal(testTeam.id);
});
});
});
it('MM-T4018 - Number of teams in policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 1', 'years', '2');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Add channels to the policy
cy.uiAddRandomTeamToCustomPolicy(2);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
cy.uiVerifyPolicyResponse(interception.response.body, 3, 0, 730, 'Policy 1');
const policyId = interception.response.body.id;
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 1', '2 years', '3 teams, 0 channels');
// # Go to edit custom data retention page
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.uiClickEditCustomPolicyRow(policyId);
});
cy.get('.DataRetentionSettings .admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Custom Retention Policy');
// * Verify team table pagination
cy.get('.PolicyTeamsList .DataGrid').within(() => {
cy.findByText('1 - 3 of 3').scrollIntoView().should('be.visible');
});
// * GET the teams for the policy and verify the count is correct
cy.apiGetCustomRetentionPolicyTeams(policyId).then((result) => {
expect(result.body.teams.length).to.equal(3);
});
});
});
it('MM-T4011 - Add team in policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('MyPolicy', 'days', '60');
// # Add team to the policy
cy.uiAddTeamsToCustomPolicy([testTeam.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
// * Verify team table pagination
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.get('.DataGrid_rows .DataGrid_cell').first().should('contain.text', 'MyPolicy').click();
});
cy.get('.DataGrid_row .DataGrid_cell').first().should('contain', testTeam.display_name);
});
});
describe('Channels in a custom Policy', () => {
it('MM-T4017 - Total channels in policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 1', 'years', '2');
// # Add channel to the policy
cy.uiAddChannelsToCustomPolicy([testChannel.display_name]);
// # Add 2 channels to the policy from the modal
cy.uiAddRandomChannelToCustomPolicy(2);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
cy.uiVerifyPolicyResponse(interception.response.body, 0, 3, 730, 'Policy 1');
const policyId = interception.response.body.id;
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 1', '2 years', '0 teams, 3 channels');
// # Go to edit custom data retention page
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.uiClickEditCustomPolicyRow(policyId);
});
cy.get('.DataRetentionSettings .admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Custom Retention Policy');
// * Verify Channel pagination
cy.get('.PolicyChannelsList .DataGrid').within(() => {
cy.findByText('1 - 3 of 3').scrollIntoView().should('be.visible');
});
// * GET the channels for the policy and verify the count
cy.apiGetCustomRetentionPolicyChannels(policyId).then((result) => {
expect(result.body.channels.length).to.equal(3);
});
});
});
it('MM-T4014 - Add channel in policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 1', 'years', '2');
// # Add channel to the policy
cy.uiAddChannelsToCustomPolicy([testChannel.display_name]);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
cy.uiVerifyPolicyResponse(interception.response.body, 0, 1, 730, 'Policy 1');
const policyId = interception.response.body.id;
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 1', '2 years', '0 teams, 1 channel');
// * GET the channel for the policy and verify it is correct
cy.apiGetCustomRetentionPolicyChannels(policyId).then((result) => {
expect(result.body.channels[0].id).to.equal(testChannel.id);
});
});
});
it('MM-T4015 - Delete channel in policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 1', 'years', '1');
// # Add channel to the policy
cy.uiAddChannelsToCustomPolicy([testChannel.display_name]);
// # Add 2 channels to the policy
cy.uiAddRandomChannelToCustomPolicy(2);
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
cy.uiVerifyPolicyResponse(interception.response.body, 0, 3, 365, 'Policy 1');
const policyId = interception.response.body.id;
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 1', '1 year', '0 teams, 3 channels');
// # Go to edit custom data retention page
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.uiClickEditCustomPolicyRow(policyId);
});
cy.get('.DataRetentionSettings .admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Custom Retention Policy');
// # Remove channel from policy
cy.get('.PolicyChannelsList .DataGrid').within(() => {
cy.findAllByRole('link', {name: 'Remove'}).first().should('exist').click();
});
// # Save policy
cy.uiGetButton('Save').click();
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 1', '1 year', '0 teams, 2 channels');
// * GET the channel for the policy and verify the count is correct
cy.apiGetCustomRetentionPolicyChannels(policyId).then((result) => {
expect(result.body.channels.length).to.equal(2);
});
});
});
it('MM-T4016 - Search channels in policy', () => {
// # Go to create custom data retention page
cy.uiClickCreatePolicy();
// # Fill out policy details
cy.uiFillOutCustomPolicyFields('Policy 1', 'years', '2');
// # Add channel to the policy
cy.uiAddChannelsToCustomPolicy([testChannel.display_name]);
// # Add channel to the policy
cy.uiAddRandomChannelToCustomPolicy();
// # Save policy
cy.uiGetButton('Save').click();
cy.wait('@createCustomPolicy').then((interception) => {
// * Verify create policy api response
cy.uiVerifyPolicyResponse(interception.response.body, 0, 2, 730, 'Policy 1');
const policyId = interception.response.body.id;
// * Verify custom policy data table
cy.uiVerifyCustomPolicyRow(policyId, 'Policy 1', '2 years', '0 teams, 2 channels');
// # Go to edit custom data retention page
cy.get('#custom_policy_table .DataGrid').within(() => {
cy.uiClickEditCustomPolicyRow(policyId);
});
cy.get('.DataRetentionSettings .admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Custom Retention Policy');
// # Scroll down the custom policy form page
cy.get('.DataRetentionSettings .admin-console__wrapper').scrollTo('bottom');
cy.get('.PolicyChannelsList .DataGrid').within(() => {
// This will not type the space for display name?
cy.findByRole('textbox').should('be.visible').clear().type(testChannel.name);
cy.wait(TIMEOUTS.ONE_SEC);
cy.get(`#channel-name-${testChannel.id}`).should('be.visible').invoke('text').should('include', testChannel.display_name);
});
cy.apiSearchCustomRetentionPolicyChannels(policyId, testChannel.display_name).then((result) => {
expect(result.body[0].id).to.equal(testChannel.id);
});
});
});
});
});

View File

@@ -0,0 +1,130 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console @compliance_export
import {
downloadAndUnzipExportFile,
verifyActianceXMLFile,
verifyPostsCSVFile,
} from './helpers';
describe('Compliance Export', () => {
const downloadsFolder = Cypress.config('downloadsFolder');
let newTeam;
let newChannel;
let botId;
let botName;
before(() => {
cy.apiRequireLicenseForFeature('Compliance');
cy.apiUpdateConfig({
MessageExportSettings: {
ExportFormat: 'csv',
DownloadExportResults: true,
},
ServiceSettings: {
EnforceMultifactorAuthentication: false,
},
});
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
cy.apiLogin(sysadmin);
//# Create a test bot
cy.apiCreateBot().then(({bot}) => {
({user_id: botId, display_name: botName} = bot);
cy.apiPatchUserRoles(bot.user_id, ['system_admin', 'system_user']);
});
cy.apiInitSetup().then(({team, channel}) => {
newTeam = team;
newChannel = channel;
// # Do initial export
exportCompliance();
});
});
});
after(() => {
cy.shellRm('-rf', downloadsFolder);
});
it('MM-T1175_1 - UserType identifies that the message is posted by a bot', () => {
const message = `This is CSV bot message from ${botName} at ${Date.now()}`;
// # Post bot message
postBotMessage(newTeam, newChannel, botId, message);
// # Go to Compliance page and run report
exportCompliance();
// # Download and Unzip exported file
const targetFolder = `${downloadsFolder}/${Date.now().toString()}`;
downloadAndUnzipExportFile(targetFolder);
// * Export file should contain bot messages
verifyPostsCSVFile(
targetFolder,
'have.string',
`${message},message,bot`,
);
});
it('MM-T1175_2 - UserType identifies that the message is posted by a bot', () => {
const message = `This is XML bot message from ${botName} at ${Date.now()}`;
// # Post bot message
postBotMessage(newTeam, newChannel, botId, message);
// # Go to Compliance and enable run export
exportCompliance('Actiance XML');
// # Download and Unzip exported File
const targetFolder = `${downloadsFolder}/${Date.now().toString()}`;
downloadAndUnzipExportFile(targetFolder);
// * Export file should message from bot
verifyActianceXMLFile(
targetFolder,
'have.string',
message,
);
verifyActianceXMLFile(
targetFolder,
'have.string',
'<UserType>bot</UserType>',
);
});
});
function postBotMessage(newTeam, newChannel, botId, message) {
cy.apiCreateToken(botId).then(({token}) => {
// # Logout to allow posting as bot
cy.apiLogout();
cy.apiCreatePost(newChannel.id, message, '', {attachments: [{pretext: 'Look some text', text: 'This is text'}]}, token);
// # Re-login to validate post presence
cy.apiAdminLogin();
cy.visit(`/${newTeam.name}/channels/${newChannel.name}`);
// * Validate post was created
cy.findByText(message).should('be.visible');
});
}
function exportCompliance(type) {
cy.uiGoToCompliancePage();
cy.uiEnableComplianceExport(type);
cy.uiExportCompliance();
}

View File

@@ -0,0 +1,288 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console @compliance_export
import {
downloadAndUnzipExportFile,
editLastPost,
gotoTeamAndPostImage,
verifyActianceXMLFile,
verifyPostsCSVFile,
} from './helpers';
describe('Compliance Export', () => {
const ExportFormatActiance = 'Actiance XML';
const downloadsFolder = Cypress.config('downloadsFolder');
let newTeam;
let newUser;
let newChannel;
let adminUser;
before(() => {
cy.apiRequireLicenseForFeature('Compliance');
cy.apiUpdateConfig({
MessageExportSettings: {
ExportFormat: 'csv',
DownloadExportResults: true,
},
});
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
adminUser = sysadmin;
cy.apiLogin(adminUser);
cy.apiInitSetup().then(({team, user, channel}) => {
newTeam = team;
newUser = user;
newChannel = channel;
});
});
});
after(() => {
cy.shellRm('-rf', downloadsFolder);
});
it('MM-T1172 - Compliance Export - Deleted file is indicated in CSV File Export', () => {
// # Go to compliance page and enable export
cy.uiGoToCompliancePage();
cy.uiEnableComplianceExport();
// # Navigate to a team and post an attachment
cy.visit(`/${newTeam.name}/channels/town-square`);
gotoTeamAndPostImage();
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Deleting last post
deleteLastPost();
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Download and extract export zip file
const targetFolder = `${downloadsFolder}/${Date.now().toString()}`;
downloadAndUnzipExportFile(targetFolder);
// * Verifying if export file contains delete
verifyPostsCSVFile(
targetFolder,
'have.string',
'deleted attachment',
);
});
it('MM-T1173 - Compliance Export - Deleted file is indicated in Actiance XML File Export', () => {
// # Go to compliance page and enable export
cy.uiGoToCompliancePage();
cy.uiEnableComplianceExport(ExportFormatActiance);
// # Navigate to a team and post an attachment
cy.visit(`/${newTeam.name}/channels/town-square`);
gotoTeamAndPostImage();
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Delete last post
deleteLastPost();
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Download and extract exported zip file
const targetFolder = `${downloadsFolder}/${Date.now().toString()}`;
downloadAndUnzipExportFile(targetFolder);
// * Verifying if export file contains deleted image
verifyActianceXMLFile(
targetFolder,
'have.string',
'delete file uploaded-image-400x400.jpg',
);
// * Verifying if image has been downloaded
cy.shellFind(targetFolder, /image-400x400.jpg/).then((files) => {
expect(files.length).not.to.equal(0);
});
});
it('MM-T3436 - Download Compliance Export Files - Actiance XML Format', () => {
// # Go to compliance page and enable export in Actiance XML format
cy.uiGoToCompliancePage();
cy.uiEnableComplianceExport(ExportFormatActiance);
// # Navigate to a team and post a message with an attachment
cy.visit(`/${newTeam.name}/channels/town-square`);
gotoTeamAndPostImage();
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// * Verify the Download option is provided for the export job
cy.get('@firstRow').findByText('Download').should('exist');
// # Download and extract exported zip file
const targetFolder = `${downloadsFolder}/${Date.now().toString()}`;
downloadAndUnzipExportFile(targetFolder);
// * Verifying if export file contains the posted message content
verifyActianceXMLFile(
targetFolder,
'have.string',
'file uploaded-image-400x400.jpg',
);
// * Verifying if the attached file is included in the export
cy.shellFind(targetFolder, /image-400x400.jpg/).then((files) => {
expect(files.length).not.to.equal(0);
});
});
it('MM-T1176 - Compliance export should include updated post after editing', () => {
// # Go to compliance page and enable export
cy.uiGoToCompliancePage();
cy.uiEnableComplianceExport(ExportFormatActiance);
// # Navigate to a team and post a message
cy.visit(`/${newTeam.name}/channels/town-square`);
cy.postMessage('Testing');
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Visit town-square channel and edit the last post
cy.visit(`/${newTeam.name}/channels/town-square`);
editLastPost('Hello');
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Download and extract exported zip file
const targetFolder = `${downloadsFolder}/${Date.now().toString()}`;
downloadAndUnzipExportFile(targetFolder);
// * Verifying if export file contains edited text
verifyActianceXMLFile(
targetFolder,
'have.string',
'<Content>Hello</Content>',
);
});
it('MM-T3305 - Verify Deactivated users are displayed properly in Compliance Exports', () => {
// # Post a message by Admin
cy.postMessageAs({
sender: adminUser,
message: `@${newUser.username} : Admin 1`,
channelId: newChannel.id,
});
cy.visit(`/${newTeam.name}/channels/${newChannel.id}`);
// # Deactivate the newly created user
cy.apiDeactivateUser(newUser.id);
// # Go to compliance page and enable export
cy.uiGoToCompliancePage();
cy.uiEnableComplianceExport(ExportFormatActiance);
cy.uiExportCompliance();
// # Download and extract exported zip file
let targetFolder = `${downloadsFolder}/${Date.now().toString()}`;
downloadAndUnzipExportFile(targetFolder);
// * Verifying if export file contains deactivated user info
verifyActianceXMLFile(
targetFolder,
'have.string',
`<LoginName>${newUser.username}@sample.mattermost.com</LoginName>`,
);
// # Post a message by Admin
cy.postMessageAs({
sender: adminUser,
message: `@${newUser.username} : Admin2`,
channelId: newChannel.id,
});
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Download and extract exported zip file
targetFolder = `${downloadsFolder}/${Date.now().toString()}`;
downloadAndUnzipExportFile(targetFolder);
// * Verifying export file should not contain deactivated user name
verifyActianceXMLFile(
targetFolder,
'not.have.string',
`<LoginName>${newUser.username}@sample.mattermost.com</LoginName>`,
);
// # Re-activate the user
cy.apiActivateUser(newUser.id);
// # Post a message by Admin
cy.postMessageAs({
sender: adminUser,
message: `@${newUser.username} : Admin3`,
channelId: newChannel.id,
});
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Download and extract exported zip file
targetFolder = `${downloadsFolder}/${Date.now().toString()}`;
downloadAndUnzipExportFile(targetFolder);
// * Verifying if export file contains deactivated user name
verifyActianceXMLFile(
targetFolder,
'have.string',
`<LoginName>${newUser.username}@sample.mattermost.com</LoginName>`,
);
});
});
function deleteLastPost() {
cy.apiGetTeamsForUser().then(({teams}) => {
const team = teams[0];
cy.visit(`/${team.name}/channels/town-square`);
cy.getLastPostId().then((lastPostId) => {
// # Click post dot menu in center.
cy.clickPostDotMenu(lastPostId);
// # Scan inside the post menu dropdown
cy.get(`#CENTER_dropdown_${lastPostId}`).should('exist').within(() => {
// # Click on the delete post button from the dropdown
cy.findByText('Delete').should('exist').click();
});
});
cy.get('.a11y__modal.modal-dialog').should('exist').and('be.visible').
within(() => {
// # Confirm click on the delete button for the post
cy.findByText('Delete').should('be.visible').click();
});
});
}

View File

@@ -0,0 +1,184 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import path from 'path';
import * as TIMEOUTS from '@/fixtures/timeouts';
export function downloadAndUnzipExportFile(targetFolder = '') {
// # Get the download link
cy.get('@firstRow').findByText('Download').parents('a').should('exist').then((fileAttachment) => {
// # Getting export file url
const fileURL = fileAttachment.attr('href');
const targetFilePath = path.join(targetFolder);
const zipFile = targetFilePath + '.zip';
// # Download zip file
cy.request({url: fileURL, encoding: 'binary'}).then((response) => {
expect(response.status).to.equal(200);
cy.writeFile(zipFile, response.body, 'binary');
});
// # Unzip exported file then "csv_export.zip"
cy.shellUnzip(zipFile, targetFilePath);
cy.shellFind(targetFilePath, /csv_export.zip/).then((files) => {
cy.shellUnzip(files[files.length - 1], targetFilePath);
});
});
}
export function verifyPostsCSVFile(targetFolder, type, match) {
cy.readFile(`${targetFolder}/posts.csv`).
should('exist').
and(type, match);
}
export function verifyActianceXMLFile(targetFolder, type, match) {
cy.readFile(`${targetFolder}/actiance_export.xml`).
should('exist').
and(type, match);
}
export function verifyExportedMessagesCount(expectedNumber) {
// * Verifying number of exported messages
cy.get('@firstRow').find('td:eq(4)').should('have.text', `${expectedNumber} messages exported.`);
}
export function editLastPost(message) {
cy.getLastPostId().then(() => {
cy.uiGetPostTextBox().clear().type('{uparrow}');
// # Edit Post Input should appear
cy.get('#edit_textbox').should('be.visible');
// # Update the post message and type ENTER
cy.get('#edit_textbox').invoke('val', '').type(message);
cy.get('#create_post').findByText('Save').should('be.visible').click();
// * Edit modal should not be visible
cy.get('#edit_textbox').should('not.exist');
});
}
export function gotoTeamAndPostImage() {
cy.uiGetPostTextBox().then((createPostEl) => {
if (createPostEl.find('.file-preview__container').length === 1) {
// # Remove images from post message footer if exist
cy.waitUntil(() => cy.uiGetFileUploadPreview().then((filePreviewEl) => {
if (filePreviewEl.find('.post-image.normal').length > 0) {
cy.get('.file-preview__remove > .icon').click();
}
return filePreviewEl.find('.post-image.normal').length === 0;
}));
}
const file = {
filename: 'image-400x400.jpg',
originalSize: {width: 400, height: 400},
thumbnailSize: {width: 400, height: 400},
};
cy.get('#fileUploadInput').attachFile(file.filename);
// # Wait until the image is uploaded
cy.uiWaitForFileUploadPreview();
cy.postMessage(`file uploaded-${file.filename}`);
});
}
export function gotoGlobalPolicy() {
// # Click edit on global policy data table
cy.get('#global_policy_table .DataGrid .MenuWrapper').trigger('mouseover').click();
cy.findByRole('button', {name: /edit/i}).should('be.visible').click();
cy.get('.DataRetentionSettings .admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Global Retention Policy');
}
export function editGlobalPolicyMessageRetention(input, result) {
cy.get('.DataRetentionSettings #global_direct_message_dropdown #DropdownInput_channel_message_retention').as('dropDown');
// * Checking if Global Policy is already created
cy.request({
headers: {'X-Requested-With': 'XMLHttpRequest'},
url: '/api/v4/data_retention/policy',
method: 'GET',
}).then((response) => {
expect(response.status).to.equal(200);
if (response.body.message_deletion_enabled === true) {
// # Click message retention dropdown and select 'Keep forever' option
cy.get('@dropDown').click();
cy.get('.channel_message_retention_dropdown__menu .channel_message_retention_dropdown__option span.option_forever').should('be.visible').click();
}
});
// # Click message retention dropdown and select 'Days' option
cy.get('@dropDown').click();
cy.get('.channel_message_retention_dropdown__menu .channel_message_retention_dropdown__option span.option_days').should('be.visible').click();
// # Input retention days
cy.get('.DataRetentionSettings #global_direct_message_dropdown input#channel_message_retention_input').clear().type(input);
// # Save Global Policy
cy.findByRole('button', {name: 'Save'}).should('be.visible').click();
// * Assert global policy data table is visible
cy.get('#global_policy_table .DataGrid').should('be.visible');
// * Assert global policy message retention is correct
cy.findByTestId('global_message_retention_cell').within(() => {
cy.get('span').should('have.text', result);
});
}
export function editGlobalPolicyFileRetention(input, result) {
// # Click file retention dropdown
cy.get('.DataRetentionSettings #global_file_dropdown #DropdownInput_file_retention').should('be.visible').click();
// # Select days from file retention dropdown
cy.get('.file_retention_dropdown__menu .file_retention_dropdown__option span.option_days').should('be.visible').click();
// # Input retention days
cy.get('.DataRetentionSettings #global_file_dropdown input#file_retention_input').clear().type(input);
// # Save Global Policy
cy.findByRole('button', {name: 'Save'}).should('be.visible').click();
// * Assert global policy data table is visible
cy.get('#global_policy_table .DataGrid').should('be.visible');
// * Assert global policy file retention is correct
cy.findByTestId('global_file_retention_cell').within(() => {
cy.get('span').should('have.text', result);
});
}
export function runDataRetentionAndVerifyPostDeleted(testTeam, testChannel, postText) {
cy.uiGoToDataRetentionPage();
cy.findByRole('button', {name: 'Run Deletion Job Now'}).click();
// # Small wait to ensure new row is add
cy.wait(TIMEOUTS.FIVE_SEC);
// # Waiting for Data Retention process to finish
cy.get('.job-table__table').find('tbody > tr').eq(0).as('firstRow');
cy.get('@firstRow').within(() => {
cy.get('td:eq(0)', {timeout: TIMEOUTS.FOUR_MIN}).should('have.text', 'Success');
});
// * Verifying if post has been deleted
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
cy.reload();
cy.findAllByTestId('postView').should('have.length', 1);
cy.findAllByTestId('postView').should('not.contain', postText);
}
export function verifyPostNotDeleted(testTeam, testChannel, postText, expectedNoOfPosts = 2) {
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
cy.findAllByTestId('postView').should('have.length', expectedNoOfPosts);
if (expectedNoOfPosts === 2) {
cy.findAllByTestId('postView').should('contain', postText);
} else {
cy.findAllByTestId('postView').should('not.contain', postText);
}
}

View File

@@ -0,0 +1,98 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @system_console @compliance_export @not_cloud
// Requires "mattermost-minio" docker instance to be accessible at http://localhost:9000
// and a bucket named "mattermost-test". Bucket can be created manually in the UI or by:
// ``docker exec mattermost-minio sh -c 'mkdir -p /data/mattermost-test'``
import {gotoTeamAndPostImage} from './helpers';
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Compliance Export', () => {
let teamName;
before(() => {
cy.shouldNotRunOnCloudEdition();
cy.apiRequireLicenseForFeature('Compliance');
cy.apiUpdateConfig({
MessageExportSettings: {
ExportFormat: 'csv',
DownloadExportResults: true,
},
});
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
cy.apiLogin(sysadmin);
cy.apiInitSetup().then(({team}) => {
teamName = team.name;
});
// # Visit a channel and post a message so it has something to be exported initially
cy.visit('/');
cy.postMessage('hello');
// # Go to compliance page, enable export and do export
cy.uiGoToCompliancePage();
cy.uiEnableComplianceExport();
cy.uiExportCompliance();
});
});
it('MM-T3439 - Download Compliance Export Files - S3 Bucket Storage', () => {
// # Go to file storage settings Page
cy.visit('/admin_console/environment/file_storage');
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'File Storage');
const {
minioAccessKey,
minioSecretKey,
minioS3Bucket,
minioS3Endpoint,
minioS3SSL,
} = Cypress.expose();
// # Update S3 Storage settings
cy.findByTestId('FileSettings.DriverNamedropdown').select('amazons3');
cy.findByTestId('FileSettings.AmazonS3Bucketinput').clear().type(minioS3Bucket);
cy.findByTestId('FileSettings.AmazonS3AccessKeyIdinput').clear().type(minioAccessKey);
cy.findByTestId('FileSettings.AmazonS3SecretAccessKeyinput').clear().type(minioSecretKey);
cy.findByTestId('FileSettings.AmazonS3Endpointinput').clear().type(minioS3Endpoint);
cy.findByTestId(`FileSettings.AmazonS3SSL${minioS3SSL}`).check();
// # Save file storage settings
cy.uiSaveConfig();
// # Test connection and verify that it's successful
cy.findByRole('button', {name: 'Test Connection'}).click();
cy.findByText('Connection was successful').should('be.visible');
// # Navigate to a team and post an attachment
cy.visit(`/${teamName}/channels/town-square`);
gotoTeamAndPostImage();
// # Go to compliance page and start export
cy.uiGoToCompliancePage();
cy.uiExportCompliance();
// # Get the first row
cy.get('.job-table__table').find('tbody > tr').eq(0).as('firstRow');
// # Get the download link
cy.get('@firstRow').findByText('Download').parents('a').should('exist').then((fileAttachment) => {
const fileURL = fileAttachment.attr('href');
// * Download link should not exist this time
cy.apiDownloadFileAndVerifyContentType(fileURL);
});
});
});

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @system_console @enterprise @not_cloud
import {FixedPublicLinks} from '@/utils';
describe('Edition and License', () => {
before(() => {
cy.shouldNotRunOnCloudEdition();
// * Check if server has license
cy.apiRequireLicense();
// # Go to admin console
cy.visit('/admin_console');
});
it('MM-T899 - Edition and License: Verify Privacy Policy link points to correct URL', () => {
// * Find text and verify its corresponding public link
[
{text: 'Privacy Policy', link: FixedPublicLinks.PrivacyPolicy},
{text: 'Enterprise Edition Terms of Use', link: FixedPublicLinks.TermsOfService},
].forEach(({text, link}) => {
cy.findByText(text).
scrollIntoView().
should('be.visible').
and('have.attr', 'href').
and('include', link);
});
});
});

View File

@@ -0,0 +1,58 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @not_cloud
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Environment', () => {
before(() => {
cy.shouldNotRunOnCloudEdition();
cy.apiInitSetup();
});
it('MM-T994 - Fields editable when enabled, but not saveable until validated', () => {
// * Check if server has license for Elasticsearch
cy.apiRequireLicenseForFeature('Elasticsearch');
cy.visit('/admin_console/environment/elasticsearch');
// * Verify the ElasticSearch fields are disabled
cy.findByTestId('connectionUrlinput').should('be.disabled');
cy.findByTestId('skipTLSVerificationfalse').should('be.disabled');
cy.findByTestId('usernameinput').should('be.disabled');
cy.findByTestId('passwordinput').should('be.disabled');
cy.findByTestId('snifftrue').should('be.disabled');
cy.findByTestId('snifffalse').should('be.disabled');
cy.findByTestId('enableSearchingtrue').should('be.disabled');
cy.findByTestId('enableSearchingfalse').should('be.disabled');
cy.findByTestId('enableAutocompletetrue').should('be.disabled');
cy.findByTestId('enableAutocompletefalse').should('be.disabled');
cy.visit('/admin_console/environment/elasticsearch');
// # Enable Elasticsearch
cy.findByTestId('enableIndexingtrue').check();
// * Verify the ElasticSearch fields are enabled
cy.findByTestId('connectionUrlinput').should('not.be.disabled');
cy.findByTestId('skipTLSVerificationfalse').should('not.be.disabled');
cy.findByTestId('usernameinput').should('not.be.disabled');
cy.findByTestId('passwordinput').should('not.be.disabled');
cy.findByTestId('snifftrue').should('not.be.disabled');
cy.findByTestId('snifffalse').should('not.be.disabled');
cy.get('.sidebar-section').first().click();
// * Verify the behavior when Yes, Discard button in the confirmation message is clicked
cy.get('#confirmModalButton').should('be.visible').and('have.text', 'Yes, Discard').click().wait(TIMEOUTS.HALF_SEC);
cy.get('.confirmModal').should('not.exist');
});
});

View File

@@ -0,0 +1,579 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('group configuration', () => {
let groupID;
let testTeam;
let testChannel;
before(() => {
cy.apiRequireLicenseForFeature('LDAP');
cy.apiInitSetup({teamPrefix: {name: 'aaa-test', displayName: 'AAA Test'}}).then(({team, channel}) => {
testTeam = team;
testChannel = channel;
});
});
beforeEach(() => {
// # Link a group
cy.apiGetLDAPGroups().then((result) => {
cy.apiLinkGroup(result.body.groups[0].primary_key).then((linkGroupRes) => {
groupID = linkGroupRes.body.id;
// # Unlink group teams and channels
cy.apiGetGroupTeams(groupID).then((response) => {
response.body.forEach((item) => {
cy.apiUnlinkGroupTeam(groupID, item.team_id);
});
});
cy.apiGetGroupChannels(groupID).then((response) => {
response.body.forEach((item) => {
cy.apiUnlinkGroupChannel(groupID, item.channel_id);
});
});
// # Go to the group configuration view of the linked group
cy.visit(`/admin_console/user_management/groups/${groupID}`);
cy.get('#adminConsoleWrapper', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').
find('.admin-console__header').should('have.text', 'Group Configuration');
// * Check that it has no associated teams or channels
verifyNoTeamsOrChannelsIsVisible();
});
});
});
it("MM-58840 Groups - can't navigate to invalid URL", () => {
// # Visit the invalid URL.
cy.visit('/admin_console/user_management/groups/invalid');
// * Verify that the user is seeing the listing (subroute not matched)
cy.findByText('AD/LDAP Groups').should('be.visible');
});
describe('adding a team', () => {
it('does not add a team without saving', () => {
addGroupSyncable('team', () => {
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the team that was added dissappears
verifyNoTeamsOrChannelsIsVisible();
});
});
it('does add a team when saved', () => {
addGroupSyncable('team', (teamName) => {
// # Save the settings
savePage();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Test that the team persisted
teamOrChannelIsPresent(teamName);
// * Ensure that server error is blank
cy.get('.error-message').should('be.empty');
});
});
});
describe('adding a channel', () => {
it('shows default channels', () => {
// # Search for off-topic
cy.get('#add_team_or_channel').should('be.visible').click();
cy.get('.dropdown-menu').find('#add_channel').should('be.visible').click();
cy.get('#selectItems input').typeWithForce('off-');
// * Check that the off-topic channels are displayed
cy.get('.more-modal__details').should('have.length.greaterThan', 1);
cy.findByText(`(${testTeam.display_name})`).should('exist');
});
it('does not add a channel without saving', () => {
addGroupSyncable('channel', () => {
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the channel that was added dissappears
verifyNoTeamsOrChannelsIsVisible();
});
});
it('does add a channel when saved', () => {
addGroupSyncable('channel', (channelName) => {
// # Save the settings
savePage();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Test that the team persisted
teamOrChannelIsPresent(channelName);
// * Ensure that server error is blank
cy.get('.error-message').should('be.empty');
});
});
});
describe('removing a team', () => {
it('does not remove a team without saving', () => {
cy.apiGetTeamsForUser().then(({teams}) => {
// # Link a team
const team = teams[0];
cy.apiLinkGroupTeam(groupID, team.id);
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the team was added to the view
teamOrChannelIsPresent(team.display_name);
// # Click remove and confirm
removeAndConfirm(team.display_name);
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the team is still visible
teamOrChannelIsPresent(team.display_name);
});
});
it('does remove a team when saved', () => {
cy.apiGetTeamsForUser().then(({teams}) => {
// # Link a team
const team = teams[0];
cy.apiLinkGroupTeam(groupID, team.id);
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the team was added to the view
teamOrChannelIsPresent(team.display_name);
// # Click remove and confirm
removeAndConfirm(team.display_name);
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Save the settings
savePage();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the team is no longer present
verifyNoTeamsOrChannelsIsVisible();
});
});
});
describe('removing a channel', () => {
it('does not remove a channel without saving', () => {
// # Link a channel
cy.apiLinkGroupChannel(groupID, testChannel.id);
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the channel was added to the view
teamOrChannelIsPresent(testChannel.display_name);
// # Click remove
cy.findByTestId(`${testChannel.display_name}_groupsyncable_remove`).click();
cy.get('#confirmModalButton').should('be.visible').click();
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the team is still visible
teamOrChannelIsPresent(testChannel.display_name);
});
it('does remove a channel when saved', () => {
// # Link a channel
cy.apiLinkGroupChannel(groupID, testChannel.id);
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the channel was added to the view
teamOrChannelIsPresent(testChannel.display_name);
cy.get('.group-teams-and-channels-row', {timeout: TIMEOUTS.ONE_MIN}).not('.has-children').should('have.length', 2);
// # Click remove
cy.findByTestId(`${testChannel.display_name}_groupsyncable_remove`).click();
cy.get('#confirmModalButton').should('be.visible').click();
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Save the settings
savePage();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the channel is no longer present
cy.get('.group-teams-and-channels-row', {timeout: TIMEOUTS.ONE_MIN}).scrollIntoView().should('have.length', 1);
});
});
describe('updating a team role', () => {
it('updates the role for a new team', () => {
// # Add a new team
addGroupSyncable('team', (teamName) => {
// # Update the role
const newRole = 'Team Admin';
changeRole(teamName, newRole);
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Save the settings
savePage();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Ensure the new role is visible
verifyNewRoleIsVisible(teamName, newRole);
});
});
it('updates the role for an existing team', () => {
// # Link a team
cy.apiLinkGroupTeam(groupID, testTeam.id);
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the team was added to the view
teamOrChannelIsPresent(testTeam.display_name);
// # Change the role
const newRole = 'Team Admin';
changeRole(testTeam.display_name, newRole);
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Save settings
savePage();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Ensure the new role is visible
verifyNewRoleIsVisible(testTeam.display_name, newRole);
});
it('does not update the role if not saved', () => {
// # Link a team
cy.apiLinkGroupTeam(groupID, testTeam.id);
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the team was added to the view
teamOrChannelIsPresent(testTeam.display_name);
// # Change the role
changeRole(testTeam.display_name, 'Team Admin');
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Ensure the new role is visible
verifyNewRoleIsVisible(testTeam.display_name, 'Member');
});
it('does not update the role of a removed team', () => {
// # Link a team
cy.apiLinkGroupTeam(groupID, testTeam.id);
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the team was added to the view
teamOrChannelIsPresent(testTeam.display_name);
// # Change the role
changeRole(testTeam.display_name, 'Team Admin');
removeAndConfirm(testTeam.display_name);
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Save settings
savePage();
// * Check the groupteam via the API to ensure the team was
// removed (delete_at != 0) and its role wasn't updated.
cy.apiGetGroupTeam(groupID, testTeam.id).then(({body}) => {
expect(body.delete_at).to.not.eq(0);
expect(body.scheme_admin).to.eq(false);
});
});
});
describe('updating a channel role', () => {
it('updates the role for a new channel', () => {
// # Add a new channel
addGroupSyncable('channel', (channelName) => {
// # Update the role
const newRole = 'Channel Admin';
changeRole(channelName, newRole);
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Save the settings
savePage();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Ensure the new role is visible
verifyNewRoleIsVisible(channelName, newRole);
});
});
it('updates the role for an existing channel', () => {
// # Link a channel
cy.apiLinkGroupChannel(groupID, testChannel.id);
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the channel was added to the view
teamOrChannelIsPresent(testChannel.display_name);
// # Change the role
const newRole = 'Channel Admin';
changeRole(testChannel.display_name, newRole);
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Save settings
savePage();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Ensure the new role is visible
verifyNewRoleIsVisible(testChannel.display_name, newRole);
});
it('does not update the role if not saved', () => {
// # Link a channel
cy.apiLinkGroupChannel(groupID, testChannel.id);
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the channel was added to the view
teamOrChannelIsPresent(testChannel.display_name);
// # Change the role
changeRole(testChannel.display_name, 'Channel Admin');
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Ensure the new role is visible
verifyNewRoleIsVisible(testChannel.display_name, 'Member');
});
it('does not update the role of a removed channel', () => {
// # Link a channel
cy.apiLinkGroupChannel(groupID, testChannel.id);
// # Reload the page
cy.visit(`/admin_console/user_management/groups/${groupID}`);
// * Check that the channel was added to the view
teamOrChannelIsPresent(testChannel.display_name);
// # Change the role
changeRole(testChannel.display_name, 'Channel Admin');
cy.findByTestId(`${testChannel.display_name}_groupsyncable_remove`).click();
cy.get('#confirmModalButton').should('be.visible').click();
// # Click away
cy.get('.sidebar-section').first().click();
// * Ensure that discard warning appears
cy.get('.discard-changes-modal').should('be.visible');
// # Cancel navigating away
cy.get('#cancelModalButton').click();
// # Save settings
savePage();
// * Check the groupteam via the API to ensure the channel was
// removed (delete_at != 0) and its role wasn't updated.
cy.apiGetGroupChannel(groupID, testChannel.id).then(({body}) => {
expect(body.delete_at).to.not.eq(0);
expect(body.scheme_admin).to.eq(false);
});
});
});
});
function teamOrChannelIsPresent(name) {
cy.get('.group-teams-and-channels--body', {timeout: TIMEOUTS.ONE_MIN}).scrollIntoView().should('be.visible').within(() => {
cy.findByText(name).scrollIntoView().should('be.visible');
});
}
function addGroupSyncable(type, callback) {
cy.get('#add_team_or_channel', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').click();
cy.get('.dropdown-menu').find(`#add_${type}`).should('be.visible').click();
cy.get(`.${type}-selector-modal`).should('be.visible');
cy.get('#multiSelectList').find('.more-modal__row').find(type === 'channel' ? '.channel-name' : '.title').then(($elements) => {
const name = $elements[0].innerText;
cy.get('#multiSelectList').find('.more-modal__row').first().click();
cy.get('#saveItems').click();
// * Check that the team or channel was added to the view
teamOrChannelIsPresent(name);
callback(name);
});
}
function changeRole(teamOrChannel, newRole) {
cy.findByTestId(`${teamOrChannel}_current_role`, {timeout: TIMEOUTS.ONE_MIN}).click();
cy.get('.Menu__content').should('be.visible').findByText(newRole).click();
}
function savePage() {
cy.get('#saveSetting', {timeout: TIMEOUTS.TWO_SEC}).click();
cy.get('#saveSetting', {timeout: TIMEOUTS.TWO_SEC}).should('be.disabled');
}
function removeAndConfirm(name) {
cy.findByTestId(`${name}_groupsyncable_remove`, {timeout: TIMEOUTS.ONE_MIN}).click();
cy.get('#confirmModalButton').should('be.visible').click();
verifyNoTeamsOrChannelsIsVisible();
}
function verifyNewRoleIsVisible(teamOrChannel, newRole) {
cy.findByTestId(`${teamOrChannel}_current_role`, {timeout: TIMEOUTS.ONE_MIN}).scrollIntoView().should('be.visible').findByText(newRole).should('be.visible');
}
function verifyNoTeamsOrChannelsIsVisible() {
cy.findByText('No teams or channels specified yet', {timeout: TIMEOUTS.ONE_MIN}).scrollIntoView().should('be.visible');
}

View File

@@ -0,0 +1,94 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import accessRules from '@/fixtures/system-roles-console-access';
import disabledTests from '@/fixtures/console-example-inputs';
import * as TIMEOUTS from '@/fixtures/timeouts';
function noAccessFunc(section) {
// * If it's a no-access permission, we just need to check that the section doesn't exist in the side bar
cy.findByTestId(section).should('not.exist');
}
function readOnlyFunc(section) {
// * If it's a read only permission, we need to make sure that the section does exist in the sidebar however the inputs in that section is disabled (read only)
cy.findByTestId(section).should('exist');
checkInputsShould('be.disabled', section);
}
function readWriteFunc(section) {
// * If we have read + write (can edit) permissions, we need to make the section exists and also that the inputs are all enabled
cy.findByTestId(section).should('exist');
checkInputsShould('be.enabled', section);
}
function checkInputsShould(shouldString, section) {
const {disabledInputs} = disabledTests.find((item) => item.section === section);
Cypress._.forEach(disabledInputs, ({path, selector}) => {
if (path.length && selector.length) {
cy.visit(path, {timeout: TIMEOUTS.HALF_MIN});
cy.findByTestId(selector, {timeout: TIMEOUTS.ONE_MIN}).should(shouldString);
}
});
}
export function makeUserASystemRole(testUsers, role) {
// # Login as each new role.
cy.apiAdminLogin();
// # Go the system console.
cy.visit('/admin_console/user_management/system_roles');
cy.get('.admin-console__header').within(() => {
cy.findByText('Delegated Granular Administration', {timeout: TIMEOUTS.ONE_MIN}).should('exist').and('be.visible');
});
// # Click on edit for the role
cy.findByTestId(`${role}_edit`).click();
// # Click Add People button
cy.findByRole('button', {name: 'Add People'}).click().wait(TIMEOUTS.HALF_SEC);
// # Type in user name
cy.findByRole('combobox', {name: 'Search for people'}).typeWithForce(`${testUsers[role].email}`);
// # Find the user and click on him
cy.get('#multiSelectList').should('be.visible').children().first().click({force: true});
// # Click add button
cy.findByRole('button', {name: 'Add'}).click().wait(TIMEOUTS.HALF_SEC);
// # Click save button
cy.findByRole('button', {name: 'Save'}).click().wait(TIMEOUTS.HALF_SEC);
}
export function forEachConsoleSection(testUsers, roleName) {
const ACCESS_NONE = 'none';
const ACCESS_READ_ONLY = 'read';
const ACCESS_READ_WRITE = 'read+write';
const user = testUsers[roleName];
// # Login as each new role.
cy.apiLogin(user);
// # Go the system console.
cy.visit('/admin_console');
cy.get('.admin-sidebar', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
accessRules.forEach((rule) => {
const {section} = rule;
const access = rule[roleName];
switch (access) {
case ACCESS_NONE:
noAccessFunc(section);
break;
case ACCESS_READ_ONLY:
readOnlyFunc(section);
break;
case ACCESS_READ_WRITE:
readWriteFunc(section);
break;
}
});
}

View File

@@ -0,0 +1,48 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @system_console @not_cloud
import {forEachConsoleSection, makeUserASystemRole} from './helpers';
describe('Limited console access', () => {
const roleNames = ['system_manager', 'system_user_manager', 'system_read_only_admin'];
const testUsers = {};
before(() => {
cy.shouldNotRunOnCloudEdition();
cy.apiRequireLicense();
Cypress._.forEach(roleNames, (roleName) => {
cy.apiCreateUser().then(({user}) => {
testUsers[roleName] = user;
});
});
});
it('MM-T3386 - Verify the Admin Role - System Manager -- KNOWN ISSUE: MM-42573', () => {
const role = 'system_manager';
// # Make the user a System Manager
makeUserASystemRole(testUsers, role);
// * Login as the new user and verify the role permissions (ensure they really are a system manager)
forEachConsoleSection(testUsers, role);
});
it('MM-T3388 - Verify the Admin Role - System Read Only Admin -- KNOWN ISSUE: MM-42573', () => {
const role = 'system_read_only_admin';
// # Make the user a System Ready Only Manager
makeUserASystemRole(testUsers, role);
// * Login as the new user and verify the role permissions (ensure they really are a system read only manager)
forEachConsoleSection(testUsers, role);
});
});

View File

@@ -0,0 +1,38 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
import {forEachConsoleSection, makeUserASystemRole} from './helpers';
describe('Limited console access', () => {
const roleNames = ['system_manager', 'system_user_manager', 'system_read_only_admin'];
const testUsers = {};
before(() => {
cy.apiRequireLicense();
Cypress._.forEach(roleNames, (roleName) => {
cy.apiCreateUser().then(({user}) => {
testUsers[roleName] = user;
});
});
});
it('MM-T3387 - Verify the Admin Role - System User Manager', () => {
const role = 'system_user_manager';
// # Make the user a System User Manager
makeUserASystemRole(testUsers, role);
// * Login as the new user and verify the role permissions (ensure they really are a system user manager)
forEachConsoleSection(testUsers, role);
});
});

View File

@@ -0,0 +1,52 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
describe('Main menu', () => {
before(() => {
// * Check if server has license
cy.apiRequireLicense();
// # Go to admin console
cy.visit('/admin_console');
// # Open the hamburger menu
cy.get('button > span[class="menu-icon"]').click();
});
it('MM-T913 About opens About modal', () => {
// # click to open about modal
cy.findByText('About Mattermost').click();
// * Verify server link text has correct link destination and opens in a new tab
verifyLink('server', 'https://github.com/mattermost/mattermost-server/blob/master/NOTICE.txt');
// * Verify link text has correct link destination and opens in a new tab
verifyLink('desktop', 'https://github.com/mattermost/desktop/blob/master/NOTICE.txt');
// * Verify link text has correct matches link destination and opens in a new tab
verifyLink('mobile', 'https://github.com/mattermost/mattermost-mobile/blob/master/NOTICE.txt');
// * Verify version exists in modal
cy.get('[data-testid="aboutModalVersionInfo"]').should('contain.text', 'Server Version:');
// * Verify licensed to exists in modal
cy.findByText('Licensed to:').should('be.visible');
});
});
const verifyLink = (text, link) => {
// * Verify link opens in new tab
cy.get('a[href="' + link + '"]').scrollIntoView().should('have.attr', 'target', '_blank');
// * Verify link text matches correct href value
cy.get('a[href="' + link + '"]').contains(text);
};

View File

@@ -0,0 +1,156 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
import {hexToRgbArray, rgbArrayToString} from '@/utils';
describe('System Console OpenId Connect', () => {
const FAKE_SETTING = '********************************';
const SERVICE_PROVIDER_LABEL = 'Select service provider:';
const DISCOVERY_ENDPOINT_LABEL = 'Discovery Endpoint:';
const CLIENT_ID_LABEL = 'Client ID:';
const CLIENT_SECRET_LABEL = 'Client Secret:';
const OPENID_LINK_NAME = 'OpenID Connect';
const SAVE_BUTTON_NAME = 'Save';
before(() => {
// * Check if server has license
cy.apiRequireLicense();
});
beforeEach(() => {
// # Go to the System Scheme page as System Admin
cy.apiAdminLogin();
cy.visit('/admin_console');
});
it('MM-T3623 - Set to Generic OpenId', () => {
cy.findByRole('link', {name: OPENID_LINK_NAME}).click();
// # Click the OpenId header dropdown
cy.wait(TIMEOUTS.FIVE_SEC);
cy.findByLabelText(SERVICE_PROVIDER_LABEL).select('openid').wait(TIMEOUTS.ONE_SEC);
cy.findByLabelText('Button Name:').clear().type('TestButtonTest');
cy.get('#OpenIdSettings\\.ButtonColor-inputColorValue').clear().type('#c02222');
cy.findByLabelText(DISCOVERY_ENDPOINT_LABEL).clear().type('http://test.com/.well-known/openid-configuration');
cy.findByLabelText(CLIENT_ID_LABEL).clear().type('OpenIdId');
cy.findByLabelText(CLIENT_SECRET_LABEL).clear().type('OpenIdSecret');
cy.findByRole('button', {name: SAVE_BUTTON_NAME}).click().wait(TIMEOUTS.ONE_SEC);
// * Get config from API
cy.apiGetConfig().then(({config}) => {
expect(config.OpenIdSettings.Secret).to.equal(FAKE_SETTING);
expect(config.OpenIdSettings.Id).to.equal('OpenIdId');
expect(config.OpenIdSettings.DiscoveryEndpoint).to.equal('http://test.com/.well-known/openid-configuration');
});
verifyOAuthLogin('TestButtonTest', '#c02222', Cypress.config('baseUrl') + '/oauth/openid/login');
});
it('MM-T3620 - Set to Google OpenId', () => {
cy.findByRole('link', {name: OPENID_LINK_NAME}).click();
// # Click the OpenId header dropdown
cy.wait(TIMEOUTS.FIVE_SEC);
cy.findByLabelText(SERVICE_PROVIDER_LABEL).select('google').wait(TIMEOUTS.ONE_SEC);
cy.findByLabelText(CLIENT_ID_LABEL).clear().type('GoogleId');
cy.findByLabelText(CLIENT_SECRET_LABEL).clear().type('GoogleSecret');
cy.findByRole('button', {name: SAVE_BUTTON_NAME}).click().wait(TIMEOUTS.ONE_SEC);
// * Get config from API
cy.apiGetConfig().then(({config}) => {
expect(config.GoogleSettings.Secret).to.equal(FAKE_SETTING);
expect(config.GoogleSettings.Id).to.equal('GoogleId');
expect(config.GoogleSettings.DiscoveryEndpoint).to.equal('https://accounts.google.com/.well-known/openid-configuration');
});
verifyOAuthLogin('Google', '', Cypress.config('baseUrl') + '/oauth/google/login');
});
it('MM-T3621 - Set to Gitlab OpenId', () => {
cy.findByRole('link', {name: OPENID_LINK_NAME}).click();
// # Click the OpenId header dropdown
cy.wait(TIMEOUTS.FIVE_SEC);
cy.findByLabelText(SERVICE_PROVIDER_LABEL).select('gitlab').wait(TIMEOUTS.ONE_SEC);
cy.findByLabelText('GitLab Site URL:').clear().type('https://gitlab.com');
cy.findByLabelText(CLIENT_ID_LABEL).clear().type('GitlabId');
cy.findByLabelText(CLIENT_SECRET_LABEL).clear().type('GitlabSecret');
cy.findByRole('button', {name: SAVE_BUTTON_NAME}).click().wait(TIMEOUTS.ONE_SEC);
// * Get config from API
cy.apiGetConfig().then(({config}) => {
expect(config.GitLabSettings.Secret).to.equal(FAKE_SETTING);
expect(config.GitLabSettings.Id).to.equal('GitlabId');
expect(config.GitLabSettings.DiscoveryEndpoint).to.equal('https://gitlab.com/.well-known/openid-configuration');
});
verifyOAuthLogin('GitLab', '', Cypress.config('baseUrl') + '/oauth/gitlab/login');
});
it('MM-T3622 - Set to Exchange OpenId', () => {
cy.findByRole('link', {name: OPENID_LINK_NAME}).click();
// # Click the OpenId header dropdown
cy.wait(TIMEOUTS.FIVE_SEC);
cy.findByLabelText(SERVICE_PROVIDER_LABEL).select('office365').wait(TIMEOUTS.ONE_SEC);
cy.findByLabelText('Directory (tenant) ID:').clear().type('common');
cy.findByLabelText(CLIENT_ID_LABEL).clear().type('Office365Id');
cy.findByLabelText(CLIENT_SECRET_LABEL).clear().type('Office365Secret');
cy.findByRole('button', {name: SAVE_BUTTON_NAME}).click().wait(TIMEOUTS.ONE_SEC);
// * Get config from API
cy.apiGetConfig().then(({config}) => {
expect(config.Office365Settings.Secret).to.equal(FAKE_SETTING);
expect(config.Office365Settings.Id).to.equal('Office365Id');
expect(config.Office365Settings.DiscoveryEndpoint).to.equal('https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration');
});
verifyOAuthLogin('Entra ID', '', Cypress.config('baseUrl') + '/oauth/office365/login');
});
});
const verifyOAuthLogin = (text, color, href) => {
cy.uiOpenSystemConsoleMainMenu('Log Out');
cy.waitUntil(() => cy.url().then((url) => {
return url.includes('/login');
}));
cy.url().then((url) => {
const withExtra = url.includes('?extra=expired') ? '?extra=expired' : '';
// * Verify oauth login link
cy.get('.external-login-button').then((btn) => {
expect(btn.prop('href')).equal(`${href}${withExtra}`);
if (color) {
const rbgArr = hexToRgbArray(color);
expect(btn[0].style.color).equal(rgbArrayToString(rbgArr));
expect(btn[0].style.borderColor).equal(rgbArrayToString(rbgArr));
}
cy.get('.external-login-button-label').should('contain', text);
});
});
};

View File

@@ -0,0 +1,195 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('System Console > Site Statistics', () => {
let testTeam;
const statDataTestIds = [
'totalActiveUsers',
'totalTeams',
'totalChannels',
'totalPosts',
'totalSessions',
'totalCommands',
'incomingWebhooks',
'outgoingWebhooks',
'dailyActiveUsers',
'monthlyActiveUsers',
'websocketConns',
'masterDbConns',
'replicaDbConns'];
const titleTestIds = [
'totalActiveUsersTitle',
'totalTeamsTitle',
'totalChannelsTitle',
'totalPostsTitle',
'totalSessionsTitle',
'totalCommandsTitle',
'incomingWebhooksTitle',
'outgoingWebhooksTitle',
'dailyActiveUsersTitle',
'monthlyActiveUsersTitle',
'websocketConnsTitle',
'masterDbConnsTitle',
'replicaDbConnsTitle'];
before(() => {
// * Check if server has license
cy.apiRequireLicense();
});
afterEach(() => {
// # Reset locale
cy.apiPatchMe({locale: 'en'});
});
it('MM-T904 Site Statistics displays expected content categories', () => {
cy.intercept('**/api/v4/**').as('resources');
// # Visit site statistics page.
cy.visit('/admin_console/reporting/system_analytics');
cy.wait('@resources');
// * Check that the header has loaded correctly and contains the expected text.
cy.get('.admin-console__header span', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').should('contain', 'System Statistics');
cy.wait(TIMEOUTS.ONE_SEC).waitUntil(() => cy.get('body').then((el) => {
return !el[0].innerText.includes('Loading');
}, {
timeout: TIMEOUTS.ONE_MIN,
interval: TIMEOUTS.FIVE_SEC,
errorMsg: 'Timeout error waiting "Loading..." indicator message to disappear',
}));
// * Check that the rows for the table were generated.
cy.get('.admin-console__content .row').should('have.length', 4);
// * Check that the title content for the stats is as expected.
cy.findByTestId('totalActiveUsersTitle').should('have.text', 'Total Activated Users');
// cy.findByTestId('seatPurchasedTitle').should('contain', 'Total paid users');
cy.findByTestId('totalTeamsTitle').should('contain', 'Total Teams');
cy.findByTestId('totalChannelsTitle').should('contain', 'Total Channels');
cy.findByTestId('totalPostsTitle').should('contain', 'Total Posts');
cy.findByTestId('totalSessionsTitle').should('contain', 'Total Sessions');
cy.findByTestId('totalCommandsTitle').should('contain', 'Total Commands');
cy.findByTestId('incomingWebhooksTitle').should('contain', 'Incoming Webhooks');
cy.findByTestId('outgoingWebhooksTitle').should('contain', 'Outgoing Webhooks');
cy.findByTestId('dailyActiveUsersTitle').should('contain', 'Daily Active Users');
cy.findByTestId('monthlyActiveUsersTitle').should('contain', 'Monthly Active Users');
cy.findByTestId('websocketConnsTitle').should('contain', 'WebSocket Conns');
cy.findByTestId('masterDbConnsTitle').should('contain', 'Master DB Conns');
cy.findByTestId('replicaDbConnsTitle').should('contain', 'Replica DB Conns');
statDataTestIds.forEach((locator) => {
cy.findByTestId(locator).invoke('text').then(parseFloat).should('be.gte', 0);
});
});
it('MM-T902 - Reporting ➜ Site statistics line graphs show same date', () => {
cy.intercept('**/api/v4/**').as('resources');
let newChannel;
// # Create and visit new channel
cy.apiInitSetup().then(({channel}) => {
newChannel = channel;
});
// # Create a bot and get userID
cy.apiCreateBot().then(({bot}) => {
const botUserId = bot.user_id;
cy.externalUpdateUserRoles(botUserId, 'system_user system_post_all system_admin');
// # Get token from bots id
cy.apiAccessToken(botUserId, 'Create token').then(({token}) => {
//# Add bot to team
cy.apiAddUserToTeam(newChannel.team_id, botUserId);
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
// # Post message as bot to the new channel
cy.postBotMessage({token, channelId: newChannel.id, message: 'this is bot message', createAt: yesterday.getTime()}).then(() => {
cy.visit('/admin_console');
cy.wait('@resources');
cy.dbRefreshPostStats().then(() => {
// * Find site statistics and click it
cy.findByTestId('reporting.system_analytics', {timeout: TIMEOUTS.ONE_MIN}).click();
// * Expand the details
cy.findByTestId('details-expander', {timeout: TIMEOUTS.ONE_MIN}).click();
let totalPostsDataSet;
let totalPostsFromBots;
let activeUsersWithPosts;
// # Grab all data from the 3 charts from there data labels
cy.findByTestId('totalPostsLineChart').then((el) => {
totalPostsDataSet = el[0].dataset.labels;
cy.findByTestId('totalPostsFromBotsLineChart').then((el2) => {
totalPostsFromBots = el2[0].dataset.labels;
cy.findByTestId('activeUsersWithPostsLineChart').then((el3) => {
activeUsersWithPosts = el3[0].dataset.labels;
// * Assert that all the dates are the same
expect(totalPostsDataSet).equal(totalPostsFromBots);
expect(totalPostsDataSet).equal(activeUsersWithPosts);
expect(totalPostsFromBots).equal(activeUsersWithPosts);
});
});
});
});
});
});
});
});
it('MM-T905 - Site Statistics card labels in different languages', () => {
cy.apiInitSetup().then(({team}) => {
testTeam = team;
// # Login as admin and set the language to french
cy.apiAdminLogin();
cy.visit(`/${testTeam.name}/channels/off-topic`);
cy.uiOpenSettingsModal('Display').then(() => {
cy.findByText('Language').click();
cy.get('#displayLanguage').click();
cy.findByText('Français (Alpha)').click();
cy.uiSave();
});
// * Once in site statistics, check and make sure the boxes are truncated or not according to image on test
cy.visit('/admin_console/reporting/system_analytics');
titleTestIds.forEach((id) => {
let expectedResult = false;
if (id === 'totalCommandsTitle' || id === 'masterDbConnsTitle' || id === 'replicaDbConnsTitle') {
expectedResult = true;
}
cy.findByTestId(id, {timeout: TIMEOUTS.ONE_MIN}).then((el) => {
const titleSpan = el[0].childNodes[0];
// * All the boxes on System Statistics page should have UNTRUNCATED titles when in french except Total Commands, Master DB Conns, and Replica DB Conns.
// * The following asserts if the they are truncated or not. If false, it means they are not truncated. If true, they are truncated.
expect(titleSpan.scrollWidth > titleSpan.clientWidth).equal(expectedResult);
});
});
});
});
});

View File

@@ -0,0 +1,61 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @not_cloud @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('System console', () => {
before(() => {
cy.shouldNotRunOnCloudEdition();
// * Check if server has license
cy.apiRequireLicense();
});
it('MM-T897_1 - Focus should be in System Console search box on opening System Console or refreshing pages in System Console', () => {
const pageIds = ['reporting\\/system_analytics', 'reporting\\/team_statistics', 'reporting\\/server_logs', 'user_management\\/users', 'user_management\\/teams'];
cy.visit('/admin_console');
// * Assert the ID of the element is the ID of admin sidebar filter
cy.focused().should('have.id', 'adminSidebarFilter');
cy.wait(TIMEOUTS.ONE_SEC);
pageIds.forEach((id) => {
// # Go to another page
cy.get(`#${id}`).click();
// * Ensure focus is lost
cy.focused().should('not.have.id', 'adminSidebarFilter');
// * Reload and ensure the focus is back on the search component
cy.reload();
cy.focused().should('have.id', 'adminSidebarFilter');
cy.wait(TIMEOUTS.ONE_SEC);
});
});
it('MM-T897_2 - System Console menu footer should not cut off at the bottom', () => {
cy.visit('/admin_console');
// * Scroll to the last item of the page and ensure it can be clicked
cy.findByTestId('experimental.feature_flags').scrollIntoView().click();
});
it('MM-T1634 - Search box should remain visible / in the header as you scroll down the settings list in the left-hand-side', () => {
cy.visit('/admin_console');
// * Scroll to bottom of left hand side
cy.findByTestId('experimental.feature_flags').scrollIntoView().click();
// * To check if the sidebar is in view, try to click it
cy.get('#adminSidebarFilter').should('be.visible').click();
});
});

View File

@@ -0,0 +1,68 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Settings', () => {
before(() => {
cy.apiRequireLicense();
});
it('MM-T1181 Compliance and Auditing: Run a report, it appears in the job table', () => {
cy.visit('/admin_console/compliance/monitoring');
// # Enable compliance reporting
cy.findByTestId('ComplianceSettings.Enabletrue').click();
cy.findByTestId('saveSetting').should('be.enabled').click().wait(TIMEOUTS.HALF_SEC);
// # Fill up the boxes
cy.get('#desc').clear().type('sample report');
const now = new Date();
cy.get('#to').clear().type(now.toLocaleDateString());
now.setDate(now.getDate() - 1);
cy.get('#from').clear().type(now.toLocaleDateString());
// # Run compliance reports
cy.get('#run-button').click().wait(TIMEOUTS.HALF_SEC);
cy.findByText('Reload Completed Compliance Reports').click().wait(TIMEOUTS.HALF_SEC);
// * Ensure that reports appear
cy.get('.compliance-panel__table tbody').children().should('have.length.greaterThan', 0);
// * Ensure that the report is correct
cy.get('.compliance-panel__table tbody tr').first().should('contain.text', 'Download');
cy.get('.compliance-panel__table tbody tr').first().should('contain.text', 'sample report');
});
it('MM-T1635 Channel listing is displayed correctly with proper team name', () => {
let teamName;
cy.visit('/admin_console/user_management/channels');
// # Get the team name
cy.get('#channels .DataGrid .DataGrid_rows > :nth-child(1)').
within(() => {
cy.get('.DataGrid_cell:nth-of-type(2)').
invoke('text').
then((name) => {
teamName = name;
// # Click on the channel
return cy.get('.DataGrid_cell').first().click();
});
}).then(() => {
// * Confirm that the team name is same
cy.get('#channel_profile .channel-team').should('have.text', 'Team' + teamName);
});
});
});

View File

@@ -0,0 +1,76 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @system_console @enterprise @cloud_only
import * as TIMEOUTS from '@/fixtures/timeouts';
import {adminConsoleNavigation} from '@/utils/admin_console';
describe('System Console - Cloud', () => {
before(() => {
// * Check if server has license for Cloud
cy.apiRequireLicenseForFeature('Cloud');
const newSettings = {
ExperimentalSettings: {
RestrictSystemAdmin: true,
},
};
cy.apiUpdateConfig(newSettings);
// # Go to system admin then verify admin console URL and header
cy.visit('/admin_console');
cy.url().should('include', '/admin_console/billing/subscription');
cy.get('.admin-console__header', {timeout: TIMEOUTS.HALF_MIN}).
should('be.visible').
and('have.text', 'Subscription');
});
const serverType = 'cloud_enterprise';
adminConsoleNavigation.forEach((testCase, index) => {
const canNavigate = testCase.type.includes(serverType);
const testTitle = `MM-T4264_${index + 1} ${canNavigate ? 'can' : 'cannot'} navigate to ${testCase.header}`;
const testFn = canNavigate ? verifyCanNavigate : verifyCannotNavigate;
it(testTitle, () => {
testFn(testCase);
});
});
});
function verifyCanNavigate(testCase) {
// # Click the link on the sidebar
cy.get('.admin-sidebar', {timeout: TIMEOUTS.ONE_MIN}).
should('be.visible').
findByText(testCase.sidebar).
scrollIntoView().
should('be.visible').
click();
// * Verify that it redirects to the URL and matches with the header
cy.url().should('include', testCase.url);
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).
should('be.visible').
and(testCase.headerContains ? 'contain' : 'have.text', testCase.header);
}
function verifyCannotNavigate(testCase) {
// # Header should not exist in sidebar
cy.get('.admin-sidebar', {timeout: TIMEOUTS.ONE_MIN}).
should('be.visible').
findByText(testCase.sidebar).
should('not.exist');
// # Visit the URL directly
cy.visit(testCase.url);
// * Verify that it redirects to Subscription page
cy.url().should('include', '/admin_console/billing/subscription');
}

View File

@@ -0,0 +1,70 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @e20_only @not_cloud @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
import {adminConsoleNavigation} from '@/utils/admin_console';
describe('System Console - Enterprise', () => {
before(() => {
cy.shouldNotRunOnCloudEdition();
// * Check if server has license
cy.apiRequireLicense();
// # Go to system admin then verify admin console URL and header
cy.visit('/admin_console/about/license');
cy.url().should('include', '/admin_console/about/license');
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).
should('be.visible').
and('have.text', 'Edition and License');
});
const serverType = 'e20';
adminConsoleNavigation.forEach((testCase, index) => {
const canNavigate = testCase.type.includes(serverType);
const testTitle = `MM-T4262_${index + 1} ${canNavigate ? 'can' : 'cannot'} navigate to ${testCase.header}`;
const testFn = canNavigate ? verifyCanNavigate : verifyCannotNavigate;
it(testTitle, () => {
testFn(testCase);
});
});
});
function verifyCanNavigate(testCase) {
// # Click the link on the sidebar
cy.get('.admin-sidebar', {timeout: TIMEOUTS.ONE_MIN}).
should('be.visible').
findByText(testCase.sidebar).
scrollIntoView().
should('be.visible').
click();
// * Verify that it redirects to the URL and matches with the header
cy.url().should('include', testCase.url);
cy.get(`${testCase.headerSelector || '.admin-console__header'}`, {timeout: TIMEOUTS.ONE_MIN}).
should('be.visible').
and(testCase.headerContains ? 'contain' : 'have.text', testCase.header);
}
function verifyCannotNavigate(testCase) {
// # Header should not exist in sidebar
cy.get('.admin-sidebar', {timeout: TIMEOUTS.ONE_MIN}).
should('be.visible').
findByText(testCase.sidebar).
should('not.exist');
// # Visit the URL directly
cy.visit(testCase.url);
// * Verify that it redirects to Edition and License page
cy.url().should('include', '/admin_console/about/license');
}

View File

@@ -0,0 +1,54 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @not_cloud @enterprise @system_console
describe('Support Packet Generation', () => {
before(() => {
cy.apiRequireLicense();
cy.apiUpdateConfig({
LogSettings: {
FileLevel: 'ERROR',
},
});
});
it('MM-T3849 - Commercial Support Dialog UI - E10/E20 License', () => {
// # Go to System Console
cy.visit('/admin_console');
goToSupportPacketGenerationModal();
cy.get('div.AlertBanner__body span').should('have.text', 'Before downloading the Support Packet, set Output Logs to File to true and set File Log Level to DEBUG here.');
});
it('MM-T3818 - Commercial Support Dialog UI - Links', () => {
// # Go to System Console
cy.visit('/admin_console');
goToSupportPacketGenerationModal();
// * Verify that the "submit a support ticket." link exist and points to Customer Support Request page
cy.findByText('submit a support ticket').should('have.attr', 'href').and('include', 'https://support.mattermost.com/hc/en-us/requests/new');
// * Verify that the "here" link exist and points to Logging admin page
cy.findByRole('link', {name: 'here'}).should('have.attr', 'href').and('include', '/admin_console/environment/logging');
});
});
const goToSupportPacketGenerationModal = () => {
// # Open system menu and click Customer Support
cy.findByRole('button', {name: 'Menu Icon'}).should('exist').click();
cy.findByRole('button', {name: 'Commercial Support'}).click();
// * Ensure the download Support Packet button exist and that text regarding setting the proper settings exist
cy.findByRole('button', {name: 'Download Support Packet'}).should('exist');
};

View File

@@ -0,0 +1,97 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('System Scheme', () => {
before(() => {
cy.apiRequireLicense();
});
beforeEach(() => {
cy.apiResetRoles();
// # Go to `User Management / Permissions` section
cy.visit('/admin_console/user_management/permissions');
});
it('MM-T2862 Default permissions set inherited from system scheme', () => {
// # Click on `Edit Scheme` under `System Scheme`
cy.findByTestId('systemScheme-link').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// # Make a few scheme changes
cy.findByTestId('all_users-public_channel-create_public_channel-checkbox').should('have.class', 'checked').click();
cy.findByTestId('all_users-private_channel-create_private_channel-checkbox').should('have.class', 'checked').click();
cy.findByTestId('all_users-teams-invite_guest-checkbox').should('not.have.class', 'checked').click();
// # Save scheme
cy.get('#saveSetting').click().wait(TIMEOUTS.TWO_SEC);
// # Go back to the `Permission Schemes` page
cy.visit('/admin_console/user_management/permissions');
// # Click `New Team Override Scheme`
cy.findByTestId('team-override-schemes-link').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// * Verify scheme settings modified earlier are reflected in this section
cy.findByTestId('all_users-public_channel-create_public_channel-checkbox').should('not.have.class', 'checked');
cy.findByTestId('all_users-private_channel-create_private_channel-checkbox').should('not.have.class', 'checked');
cy.findByTestId('all_users-teams_team_scope-invite_guest-checkbox').should('have.class', 'checked');
});
it('MM-T2863 Reset system scheme defaults will revert permissions to defaults', () => {
// # Click on `Edit Scheme` under `System Scheme`
cy.findByTestId('systemScheme-link').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// # Click on `Reset to defaults`
cy.findByTestId('resetPermissionsToDefault').scrollIntoView().should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// # Confirm the dialog
cy.get('#confirmModalButton').click().wait(TIMEOUTS.TWO_SEC);
// # Make a few changes to the scheme
cy.findByTestId('guests-guest_create_private_channel-checkbox').should('not.have.class', 'checked').click();
cy.findByTestId('all_users-public_channel-create_public_channel-checkbox').should('have.class', 'checked').click();
cy.findByTestId('all_users-private_channel-create_private_channel-checkbox').should('have.class', 'checked').click();
// # Save changes
cy.get('#saveSetting').click().wait(TIMEOUTS.HALF_SEC);
// # Go back to the `Permission Schemes` page
cy.visit('/admin_console/user_management/permissions');
// # Click on `Edit Scheme` under `System Scheme`
cy.findByTestId('systemScheme-link').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// * Verify previous scheme changes have been saved
cy.findByTestId('guests-guest_create_private_channel-checkbox').should('have.class', 'checked');
cy.findByTestId('all_users-public_channel-create_public_channel-checkbox').should('not.have.class', 'checked');
cy.findByTestId('all_users-private_channel-create_private_channel-checkbox').should('not.have.class', 'checked');
// # Click on `Reset to defaults`
cy.findByTestId('resetPermissionsToDefault').scrollIntoView().should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// # Confirm the dialog
cy.get('#confirmModalButton').scrollIntoView().click().wait(TIMEOUTS.HALF_SEC);
// # Save changes
cy.get('#saveSetting').click().wait(TIMEOUTS.TWO_SEC);
// # Reload the page
cy.reload();
// * Verify scheme settings have been reset to defaults
cy.findByTestId('guests-guest_create_private_channel-checkbox').should('not.have.class', 'checked');
cy.findByTestId('all_users-public_channel-create_public_channel-checkbox').should('have.class', 'checked');
cy.findByTestId('all_users-private_channel-create_private_channel-checkbox').should('have.class', 'checked');
});
});

View File

@@ -0,0 +1,260 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @system_console
import {getAdminAccount} from '@/support/env';
describe('System Scheme Channel Mentions Permissions Test', () => {
let testUser;
let testTeam;
let testChannel;
before(() => {
// * Check if server has license
cy.apiRequireLicense();
cy.apiInitSetup().then(({team, channel, user}) => {
testUser = user;
testTeam = team;
testChannel = channel;
});
});
beforeEach(() => {
cy.apiAdminLogin();
cy.apiResetRoles();
});
it('MM-23018 - Enable and Disable Channel Mentions', () => {
checkChannelPermission(
'use_channel_mentions',
() => channelMentionsPermissionCheck(true),
() => channelMentionsPermissionCheck(false),
testUser,
testTeam,
testChannel,
);
});
it('MM-24379 - Enable and Disable Create Post', () => {
checkChannelPermission(
'create_post',
() => createPostPermissionCheck(true),
() => createPostPermissionCheck(false),
testUser,
testTeam,
testChannel,
);
});
});
const setUserTeamAndChannelMemberships = (user, team, channel, channelAdmin = false, teamAdmin = false) => {
const admin = getAdminAccount();
// # Set user as regular system user
cy.externalUpdateUserRoles(user.id, 'system_user');
// # Get team membership
cy.externalRequest({user: admin, method: 'put', path: `teams/${team.id}/members/${user.id}/schemeRoles`, data: {scheme_user: true, scheme_admin: teamAdmin}});
// # Get channel membership
cy.externalRequest({user: admin, method: 'put', path: `channels/${channel.id}/members/${user.id}/schemeRoles`, data: {scheme_user: true, scheme_admin: channelAdmin}});
};
const saveConfig = () => {
cy.get('#saveSetting').click();
cy.waitUntil(() => cy.get('#saveSetting').then((el) => {
return el[0].innerText === 'Save';
}));
};
const enablePermission = (permissionCheckBoxTestId) => {
cy.findByTestId(permissionCheckBoxTestId).then((el) => {
if (!el.hasClass('checked')) {
el.click();
}
});
};
const removePermission = (permissionCheckBoxTestId) => {
cy.findByTestId(permissionCheckBoxTestId).then((el) => {
if (el.hasClass('checked')) {
el.click();
}
});
};
// # Checks to see if user recieved a system message warning after using @here
// # If enabled is true assumes the user has the permission enabled and checks for no system message
const channelMentionsPermissionCheck = (enabled) => {
// # Type @here and post it to the channel
cy.postMessage('@here ');
// # Get last post message text
cy.getLastPostId().then((postId) => {
if (enabled) {
// * Assert that the last message posted is not a system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('not.include.text', 'Channel notifications are disabled');
} else {
cy.uiWaitUntilMessagePostedIncludes('Channel notifications are disabled');
// * Assert that the last message posted is the system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('include.text', 'Channel notifications are disabled');
}
});
};
// # Checks to see if the post input is enabled or disalbed and that the API
// accepts or rejects the create post request.
const createPostPermissionCheck = (enabled) => {
if (enabled) {
// # Try post it to the channel
cy.uiGetPostTextBox().and('not.be.disabled');
cy.postMessage('test');
} else {
// # Ensure the input is disabled
cy.uiGetPostTextBox().and('be.disabled');
}
// # Get last post message text
cy.getLastPostId().then((postId) => {
if (enabled) {
// * Assert that the last message posted is not a system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('include.text', 'test');
}
});
};
const resetPermissionsToDefault = () => {
// # Login as sysadmin and navigate to system scheme page
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/permissions/system_scheme');
// # Click reset to defaults and confirm
cy.findByTestId('resetPermissionsToDefault').click();
cy.get('#confirmModalButton').click();
// # Save
saveConfig();
};
const checkChannelPermission = (permissionName, hasChannelPermissionCheckFunc, notHasChannelPermissionCheckFunc, testUser, testTeam, testChannel) => {
const guestsTestId = `guests-guest_${permissionName}-checkbox`;
const usersTestId = `all_users-posts-${permissionName}-checkbox`;
const channelTestId = `channel_admin-posts-${permissionName}-checkbox`;
const teamTestId = `team_admin-posts-${permissionName}-checkbox`;
const testIds = [guestsTestId, usersTestId, channelTestId, teamTestId];
const channelUrl = `/${testTeam.name}/channels/${testChannel.name}`;
// # Setup user as a regular channel member and team member
setUserTeamAndChannelMemberships(testUser, testTeam, testChannel);
// * Ensure user can use channel mentions by default
cy.apiLogin(testUser);
cy.visit(channelUrl);
hasChannelPermissionCheckFunc();
// # Go to system permissions scheme page as sysadmin
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/permissions/system_scheme');
// * Ensure permission is enabled at each scope by default
testIds.forEach((testId) => {
cy.findByTestId(testId).should('have.class', 'checked');
});
// # Remove permission from guests and save
removePermission(guestsTestId);
saveConfig();
// * Ensure that the permission removed is now removed
cy.findByTestId(guestsTestId).should('not.have.class', 'checked');
// # Remove permission from all users and save
removePermission(usersTestId);
saveConfig();
// * Ensure that the permission is not removed from all roles except All Members
cy.findByTestId(usersTestId).should('not.have.class', 'checked');
cy.findByTestId(channelTestId).should('have.class', 'checked');
cy.findByTestId(teamTestId).should('have.class', 'checked');
// # Remove permission for channel admins and save
removePermission(channelTestId);
saveConfig();
// * Ensure that the permission is removed from all roles except team admins
cy.findByTestId(teamTestId).should('have.class', 'checked');
cy.findByTestId(channelTestId).should('not.have.class', 'checked');
cy.findByTestId(usersTestId).should('not.have.class', 'checked');
// # Enable permission for channel admins and save
enablePermission(channelTestId);
saveConfig();
// * Ensure that the permission is only removed from regular users
cy.findByTestId(teamTestId).should('have.class', 'checked');
cy.findByTestId(channelTestId).should('have.class', 'checked');
cy.findByTestId(usersTestId).should('not.have.class', 'checked');
// # Setup user as a regular channel member
setUserTeamAndChannelMemberships(testUser, testTeam, testChannel);
// * Ensure user cannot use channel mentions
cy.apiLogin(testUser);
cy.visit(channelUrl);
notHasChannelPermissionCheckFunc();
// # Setup user as a channel admin
setUserTeamAndChannelMemberships(testUser, testTeam, testChannel, true, false);
// * Ensure user can use channel mentions as channel admin
cy.apiLogin(testUser);
cy.visit(channelUrl);
hasChannelPermissionCheckFunc();
// # Navigate back to system scheme as sysadmin and remove permission from channel admins
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/permissions/system_scheme');
removePermission(channelTestId);
saveConfig();
// # Log back in as regular user
cy.apiLogin(testUser);
cy.visit(channelUrl);
// * Ensure user cannot use channel mentions as channel admin
notHasChannelPermissionCheckFunc();
// # Setup user as a team admin
setUserTeamAndChannelMemberships(testUser, testTeam, testChannel, true, true);
// * Ensure user can use channel mentions as team admin
cy.apiLogin(testUser);
cy.visit(channelUrl);
hasChannelPermissionCheckFunc();
// # Navigate back to system scheme as sysadmin and remove permission from team admins
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/permissions/system_scheme');
removePermission(teamTestId);
saveConfig();
// # Log back in as regular user
cy.apiLogin(testUser);
cy.visit(channelUrl);
// * Ensure user cannot use channel mentions as team admin
notHasChannelPermissionCheckFunc();
// # Reset permissions back to defaults
resetPermissionsToDefault();
};

View File

@@ -0,0 +1,98 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
import {getRandomId} from '@/utils';
import * as TIMEOUTS from '@/fixtures/timeouts';
const permissions = ['create_private_channel', 'edit_post', 'delete_post', 'reactions', 'use_channel_mentions', 'use_group_mentions'];
const getButtonId = (permission) => {
return 'guests-guest_' + permission + '-checkbox';
};
const disableAllGuestPermissions = () => {
permissions.forEach((permission) => {
cy.findByTestId(getButtonId(permission)).then((btn) => {
if (btn.hasClass('checked')) {
btn.click();
}
});
});
};
const enableAllGuestPermissions = () => {
permissions.forEach((permission) => {
cy.findByTestId(getButtonId(permission)).then((btn) => {
if (!btn.hasClass('checked')) {
btn.click();
}
});
});
};
const verifyAllGuestPermissions = (selected) => {
permissions.forEach((permission) => {
if (selected) {
cy.findByTestId(getButtonId(permission)).should('have.class', 'checked');
} else {
cy.findByTestId(getButtonId(permission)).should('not.have.class', 'checked');
}
});
};
describe('Team Scheme Guest Permissions Test', () => {
before(() => {
// * Check if server has license
cy.apiRequireLicense();
});
it('MM- - Enable and Disable all guest permission', () => {
// # Go to team override scheme.
cy.visit('/admin_console/user_management/permissions/team_override_scheme');
// # create unique scheme name
const randomId = getRandomId();
cy.get('#scheme-name').type(`TestScheme-${randomId}{enter}`);
// // # Wait until the groups retrieved and show up
cy.wait(TIMEOUTS.HALF_SEC);
// # Check all the boxes currently unchecked
enableAllGuestPermissions();
// # Save if possible (if previous test ended abruptly all permissions may already be enabled)
cy.get('#saveSetting').click().wait(TIMEOUTS.HALF_SEC);
// # Reload the team scheme.
cy.findByText(`TestScheme-${randomId}`).siblings('.actions').children('.edit-button').click().wait(TIMEOUTS.HALF_SEC);
// * Ensure all checkboxes are checked
verifyAllGuestPermissions(true);
// # Uncheck all the boxes currently checked
disableAllGuestPermissions();
// # Save the page
cy.get('#saveSetting').click().wait(TIMEOUTS.HALF_SEC);
// #Reload the team scheme.
cy.findByText(`TestScheme-${randomId}`).siblings('.actions').children('.edit-button').click().wait(TIMEOUTS.HALF_SEC);
// * Ensure all checkboxes have the correct unchecked state
verifyAllGuestPermissions(false);
cy.findByTestId('permission-scheme-cancel-button').should('be.visible').click();
//Clean up - Delete scheme
cy.findByText(`TestScheme-${randomId}`).siblings('.actions').children('.delete-button').click().wait(TIMEOUTS.HALF_SEC);
cy.get('#confirmModalButton').click();
});
});

View File

@@ -0,0 +1,210 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Team members test', () => {
let testTeam;
let user1;
let user2;
let sysadmin;
before(() => {
// # Login as sysadmin
cy.apiAdminLogin().then((res) => {
sysadmin = res.user;
});
// * Check if server has license
cy.apiRequireLicense();
cy.apiInitSetup().then(({team, channel, user}) => {
user1 = user;
testTeam = team;
cy.apiCreateUser().then(({user: otherUser}) => {
user2 = otherUser;
cy.apiAddUserToTeam(testTeam.id, user2.id).then(() => {
cy.apiAddUserToChannel(channel.id, user2.id);
});
});
});
});
it("MM-58840 Teams - can't navigate to invalid URL", () => {
// # Visit the invalid URL.
cy.visit('/admin_console/user_management/teams/invalid');
// * Verify that the user is seeing the listing (subroute not matched)
cy.findByText('Mattermost Teams').should('be.visible');
});
it('MM-23938 - Team members block is only visible when team is not group synced', () => {
// # Visit the team page
cy.visit(`/admin_console/user_management/teams/${testTeam.id}`);
// * Assert that the members block is visible on non group synced team
cy.get('#teamMembers').scrollIntoView().should('be.visible');
// # Click the sync group members switch
cy.findByTestId('syncGroupSwitch').
scrollIntoView().
findByRole('button').
click({force: true});
// * Assert that the members block is no longer visible
cy.get('#teamMembers').should('not.exist');
});
it('MM-23938 - Team members block can search for users, remove users, add users and modify their roles', () => {
// # Visit the team page
cy.visit(`/admin_console/user_management/teams/${testTeam.id}`);
// * Assert that the members block is visible on non group synced team
cy.get('#teamMembers').scrollIntoView().should('be.visible');
// # Search for user1 that we know is in the team
searchFor(user1.email);
// # Wait till loading complete and then remove the only visible user
cy.get('#teamMembers .DataGrid_loading').should('not.exist');
cy.get('#teamMembers .UserGrid_removeRow a').should('be.visible').click();
// # Attempt to save
cy.get('#saveSetting').click();
// * Assert that confirmation modal contains the right message
cy.get('#confirmModalBody').should('be.visible').and('contain', '1 user will be removed.').and('contain', 'Are you sure you wish to remove this user?');
// # Cancel
cy.get('#cancelModalButton').click();
// # Search for user2 that we know is in the team
searchFor(user2.email);
// # Wait till loading complete and then remove the only visible user
cy.get('#teamMembers .DataGrid_loading').should('not.exist');
cy.get('#teamMembers .UserGrid_removeRow a').should('be.visible').click();
// # Attempt to save
cy.get('#saveSetting').click();
// * Assert that confirmation modal contains the right message
cy.get('#confirmModalBody').should('be.visible').and('contain', '2 users will be removed.').and('contain', 'Are you sure you wish to remove these users?');
// # Confirm Save
cy.get('#confirmModalButton').click();
// # Check that the members block is no longer visible meaning that the save has succeeded and we were redirected out
cy.get('#teamMembers').should('not.exist');
// # Visit the team page
cy.visit(`/admin_console/user_management/teams/${testTeam.id}`);
// # Search for user1 that we know is no longer in the team
searchFor(user1.email);
// * Assert that no matching users found
cy.get('#teamMembers .DataGrid_rows').should('contain', 'No users found');
// # Search for user2 that we know is no longer in the team
searchFor(user2.email);
// * Assert that no matching users found
cy.get('#teamMembers .DataGrid_rows').should('contain', 'No users found');
// # Open the add members modal
cy.get('#addTeamMembers').click();
// # Enter user1 and user2 emails
cy.get('#addUsersToTeamModal input').typeWithForce(`${user1.email}{enter}${user2.email}{enter}`);
// # Confirm add the users
cy.get('#addUsersToTeamModal #saveItems').click();
// # Search for user1
searchFor(user1.email);
// * Assert that the user is now added to the members block and contains text denoting that they are New
cy.get('#teamMembers .DataGrid_rows').children(0).should('contain', user1.email).and('contain', 'New');
// # Open the user role dropdown menu
cy.get(`#userGridRoleDropdown_${user1.username}`).click();
// * Verify that the menu is opened
cy.get('.Menu__content').should('be.visible').within(() => {
// # Make the user an admin
cy.findByText('Make Team Admin').should('be.visible').click();
});
// # Search for user2
searchFor(user2.email);
// * Assert that the user is now added to the members block and contains text denoting that they are New
cy.get('#teamMembers .DataGrid_rows').children(0).should('contain', user2.email).and('contain', 'New');
// # Search for sysadmin
searchFor(sysadmin.email);
// * Assert that searching for users after adding users returns only relevant search results
cy.get('#teamMembers .DataGrid_rows').children(0).should('contain', sysadmin.email);
// # Attempt to save
saveConfig();
// # Visit the team page
cy.visit(`/admin_console/user_management/teams/${testTeam.id}`);
// # Search user1 that we know is now in the team again
searchFor(user1.email);
cy.get('#teamMembers .DataGrid_loading').should('not.exist');
// * Assert that the user is now saved as an admin
cy.get('#teamMembers .DataGrid_rows').children(0).should('contain', user1.email).and('not.contain', 'New').and('contain', 'Team Admin');
// # Open the user role dropdown menu
cy.get(`#userGridRoleDropdown_${user1.username}`).click();
// * Verify that the menu is opened
cy.get('.Menu__content').should('be.visible').within(() => {
// # Make the user a regular member again
cy.findByText('Make Team Member').should('be.visible').click();
});
// * Assert user1 is now back to being a regular member
cy.get('#teamMembers .DataGrid_rows').children(0).should('contain', user1.email).and('not.contain', 'New').and('contain', 'Member');
// # Search user2 that we know is now in the team again
searchFor(user2.email);
cy.get('#teamMembers .DataGrid_loading').should('not.exist');
// * Assert user2 is now saved as a regular member
cy.get('#teamMembers .DataGrid_rows').children(0).should('contain', user2.email).and('not.contain', 'New').and('contain', 'Member');
// # Attempt to save
saveConfig();
});
});
function searchFor(searchTerm) {
cy.get('#teamMembers .DataGrid_search input[type="text"]').scrollIntoView().clear().type(searchTerm);
cy.wait(TIMEOUTS.HALF_SEC); // Timeout required to wait for timeout that happens when search input changes
}
function saveConfig() {
// # Click save
cy.get('#saveSetting').click();
// # Check that the members block is no longer visible meaning that the save has succeeded and we were redirected out
cy.get('#teamMembers').should('not.exist');
}

View File

@@ -0,0 +1,100 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Team Scheme', () => {
let testTeam;
const schemeName = 'Test Team Scheme';
before(() => {
cy.apiRequireLicense();
cy.apiCreateTeam('team-scheme-test', 'Scheme Test').then(({team}) => {
testTeam = team;
});
deleteExistingTeamOverrideSchemes();
});
beforeEach(() => {
// # Go to `User Management / Permissions` section
cy.visit('/admin_console/user_management/permissions');
});
it('MM-T2855 Create a Team Override Scheme', () => {
// # Click `New Team Override Scheme`
cy.findByTestId('team-override-schemes-link').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// # Type Name and Description
cy.get('#scheme-name').should('be.visible').type(schemeName);
cy.get('#scheme-description').type('Description');
// # Click `Add Teams`
cy.findByTestId('add-teams').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// # Find and select testTeam
cy.get('#selectItems input').typeWithForce(testTeam.display_name).wait(TIMEOUTS.HALF_SEC);
cy.get('#multiSelectList div.more-modal__row.clickable').eq(0).click().wait(TIMEOUTS.HALF_SEC);
// # Save scheme
cy.get('#saveItems').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// # Modify the permissions scheme
const checkId = 'all_users-public_channel-create_public_channel-checkbox';
cy.findByTestId(checkId).click();
// # Save scheme
cy.get('#saveSetting').click().wait(TIMEOUTS.TWO_SEC);
// * Verify user is returned to the `Permission Schemes` page
cy.url().should('include', '/admin_console/user_management/permissions');
// * Verify the newly created scheme is visible
cy.findByTestId('permissions-scheme-summary').within(() => {
cy.get('.permissions-scheme-summary--header').should('include.text', schemeName);
cy.get('.permissions-scheme-summary--teams').should('include.text', testTeam.display_name);
});
// * Verify permission got changed as expected
cy.findByTestId(schemeName + '-edit').click().wait(TIMEOUTS.HALF_SEC);
cy.findByTestId(checkId).should('not.have.class', 'checked');
});
it('MM-T2857 Delete Scheme', () => {
// # Click `Delete` for the scheme created above
cy.findByTestId(schemeName + '-delete').click().wait(TIMEOUTS.HALF_SEC);
// # Click `Cancel` on the confirmation dialog
cy.get('#cancelModalButton').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// * Verify the scheme is still visibile
cy.findByTestId('permissions-scheme-summary').within(() => {
cy.get('.permissions-scheme-summary--header').should('include.text', schemeName);
cy.get('.permissions-scheme-summary--teams').should('include.text', testTeam.display_name);
});
// # Click `Delete` for the scheme created above
cy.findByTestId(schemeName + '-delete').click().wait(TIMEOUTS.HALF_SEC);
// # Click `Yes, Delete` on the confirmation dialog
cy.get('#confirmModalButton').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
// * Verify the scheme is not visibile anymore
cy.findByTestId('permissions-scheme-summary').should('not.exist');
});
});
const deleteExistingTeamOverrideSchemes = () => {
cy.apiGetSchemes('team').then(({schemes}) => {
schemes.forEach((scheme) => {
cy.apiDeleteScheme(scheme.id);
});
});
};

View File

@@ -0,0 +1,291 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @system_console
import {getAdminAccount} from '@/support/env';
describe('Team Scheme Channel Mentions Permissions Test', () => {
let testUser;
let testTeam;
let testChannel;
before(() => {
// * Check if server has license
cy.apiRequireLicense();
cy.apiInitSetup().then(({team, channel, user}) => {
testUser = user;
testTeam = team;
testChannel = channel;
});
// Delete any existing team override schemes
deleteExistingTeamOverrideSchemes();
});
beforeEach(() => {
cy.apiAdminLogin();
cy.apiResetRoles();
});
it('MM-23018 - Create a team override scheme', () => {
// # Visit the permissions page
cy.visit('/admin_console/user_management/permissions/team_override_scheme');
// # Give the new team scheme a name
cy.get('#scheme-name').type('Test Team Scheme');
// # Assign the new team scheme to the test team using the add teams modal
cy.findByTestId('add-teams').click();
cy.get('#selectItems input').typeWithForce(testTeam.display_name);
cy.get('.team-info-block').then((el) => {
el.click();
});
cy.get('#saveItems').click();
// # Save config
cy.get('#saveSetting').click();
// * Ensure that the team scheme was created and assigned to the team
cy.findByTestId('permissions-scheme-summary').within(() => {
cy.get('.permissions-scheme-summary--header').should('include.text', 'Test Team Scheme');
cy.get('.permissions-scheme-summary--teams').should('include.text', testTeam.display_name);
});
});
it('MM-23018 - Enable and Disable Channel Mentions for team scheme', () => {
checkChannelPermission(
'use_channel_mentions',
() => channelMentionsPermissionCheck(true),
() => channelMentionsPermissionCheck(false),
testUser,
testTeam,
testChannel,
);
});
it('MM-24379 - Enable and Disable Create Post for team scheme -- KNOWN ISSUE:MM-42020', () => {
checkChannelPermission(
'create_post',
() => createPostPermissionCheck(true),
() => createPostPermissionCheck(false),
testUser,
testTeam,
testChannel,
);
});
});
const setUserTeamAndChannelMemberships = (user, team, channel, channelAdmin = false, teamAdmin = false) => {
const admin = getAdminAccount();
// # Set user as regular system user
cy.externalUpdateUserRoles(user.id, 'system_user');
// # Get team membership
cy.externalRequest({user: admin, method: 'put', path: `teams/${team.id}/members/${user.id}/schemeRoles`, data: {scheme_user: true, scheme_admin: teamAdmin}});
// # Get channel membership
cy.externalRequest({user: admin, method: 'put', path: `channels/${channel.id}/members/${user.id}/schemeRoles`, data: {scheme_user: true, scheme_admin: channelAdmin}});
};
const saveConfig = () => {
cy.get('#saveSetting').click();
cy.url().should('equal', `${Cypress.config('baseUrl')}/admin_console/user_management/permissions`);
};
const enablePermission = (permissionCheckBoxTestId) => {
cy.findByTestId(permissionCheckBoxTestId).then((el) => {
if (!el.hasClass('checked')) {
el.click();
}
});
};
const removePermission = (permissionCheckBoxTestId) => {
cy.findByTestId(permissionCheckBoxTestId).then((el) => {
if (el.hasClass('checked')) {
el.click();
}
});
};
const deleteExistingTeamOverrideSchemes = () => {
cy.apiGetSchemes('team').then(({schemes}) => {
schemes.forEach((scheme) => {
cy.apiDeleteScheme(scheme.id);
});
});
};
// # Checks to see if user recieved a system message warning after using @here
// # If enabled is true assumes the user has the permission enabled and checks for no system message
const channelMentionsPermissionCheck = (enabled) => {
// # Type @here and post it to the channel
cy.postMessage('@here ');
// # Get last post message text
cy.getLastPostId().then((postId) => {
if (enabled) {
// * Assert that the last message posted is not a system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('not.include.text', 'Channel notifications are disabled');
} else {
cy.uiWaitUntilMessagePostedIncludes('Channel notifications are disabled');
// * Assert that the last message posted is the system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('include.text', 'Channel notifications are disabled');
}
});
};
// # Checks to see if the post input is enabled or disalbed and that the API
// accepts or rejects the create post request.
const createPostPermissionCheck = (enabled) => {
if (enabled) {
// # Try post it to the channel
cy.uiGetPostTextBox().should('not.be.disabled');
cy.postMessage('test');
} else {
// # Ensure the input is disabled
cy.uiGetPostTextBox().should('be.disabled');
}
// # Get last post message text
cy.getLastPostId().then((postId) => {
if (enabled) {
// * Assert that the last message posted is not a system message informing us we are not allowed to use channel mentions
cy.get(`#postMessageText_${postId}`).should('include.text', 'test');
}
});
};
const checkChannelPermission = (permissionName, hasChannelPermissionCheckFunc, notHasChannelPermissionCheckFunc, testUser, testTeam, testChannel) => {
const channelUrl = `/${testTeam.name}/channels/${testChannel.name}`;
// # Setup user as a regular channel member
setUserTeamAndChannelMemberships(testUser, testTeam, testChannel);
// * Ensure user can use channel mentions by default
cy.apiLogin(testUser);
cy.visit(channelUrl);
hasChannelPermissionCheckFunc();
// # Login as sysadmin again
cy.apiAdminLogin();
// # Get team scheme URL
cy.apiGetSchemes('team').then(({schemes}) => {
const teamScheme = schemes[0];
const url = `admin_console/user_management/permissions/team_override_scheme/${teamScheme.id}`;
// todo: add checks for guests once mattermost-webapp/pull/5061 is merged
const usersTestId = `all_users-posts-${permissionName}-checkbox`;
const channelTestId = `${teamScheme.default_channel_admin_role}-posts-${permissionName}-checkbox`;
const teamTestId = `${teamScheme.default_team_admin_role}-posts-${permissionName}-checkbox`;
const testIds = [usersTestId, channelTestId, teamTestId];
// # Visit the scheme page
cy.visit(url);
// * Ensure permission is enabled at each scope by default
testIds.forEach((testId) => {
cy.findByTestId(testId).should('have.class', 'checked');
});
// # Remove permission from all users and save
removePermission(usersTestId);
saveConfig();
cy.visit(url);
// * Ensure that the permission is not removed for channel admins and team admins
cy.findByTestId(usersTestId).should('not.have.class', 'checked');
cy.findByTestId(channelTestId).should('have.class', 'checked');
cy.findByTestId(teamTestId).should('have.class', 'checked');
// # Remove permission for channel admins and save
removePermission(channelTestId);
saveConfig();
cy.visit(url);
// * Ensure that the permission is removed from all roles except team admins
cy.findByTestId(teamTestId).should('have.class', 'checked');
cy.findByTestId(channelTestId).should('not.have.class', 'checked');
cy.findByTestId(usersTestId).should('not.have.class', 'checked');
// # Enable permission for channel admins and save
enablePermission(channelTestId);
saveConfig();
cy.visit(url);
// * Ensure that the permission is only removed from all users
cy.findByTestId(teamTestId).should('have.class', 'checked');
cy.findByTestId(channelTestId).should('have.class', 'checked');
cy.findByTestId(usersTestId).should('not.have.class', 'checked');
// # Setup user as a regular channel member
setUserTeamAndChannelMemberships(testUser, testTeam, testChannel);
// * Ensure user cannot use channel mentions
cy.apiLogin(testUser);
cy.visit(channelUrl);
notHasChannelPermissionCheckFunc();
// # Setup user as a channel admin
setUserTeamAndChannelMemberships(testUser, testTeam, testChannel, true, false);
// * Ensure user can use channel mentions as channel admin
cy.apiLogin(testUser);
cy.visit(channelUrl);
hasChannelPermissionCheckFunc();
// # Navigate back to team scheme as sysadmin
cy.apiAdminLogin();
cy.visit(url);
// # Remove permission from channel admins and save
removePermission(channelTestId);
saveConfig();
cy.visit(url);
// # Log back in as regular user
cy.apiLogin(testUser);
cy.visit(channelUrl);
// * Ensure user cannot use channel mentions as channel admin
notHasChannelPermissionCheckFunc();
// # Setup user as a team admin
setUserTeamAndChannelMemberships(testUser, testTeam, testChannel, true, true);
// * Ensure user can use channel mentions as team admin
cy.apiLogin(testUser);
cy.visit(channelUrl);
hasChannelPermissionCheckFunc();
// # Navigate back to system scheme as sysadmin
cy.apiAdminLogin();
cy.visit(url);
// # Remove permission from team admins and save
removePermission(teamTestId);
saveConfig();
cy.visit(url);
// # Log back in as regular user
cy.apiLogin(testUser);
cy.visit(channelUrl);
// * Ensure user cannot use channel mentions as team admin
notHasChannelPermissionCheckFunc();
});
};

View File

@@ -0,0 +1,162 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @system_console
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('User Management', () => {
let testTeam;
let testChannel;
let testUser;
let testUsersForRoles;
const roleNames = ['system_manager', 'system_user_manager', 'system_read_only_admin'];
before(() => {
cy.apiRequireLicense();
cy.apiInitSetup().then(({team, channel, user}) => {
testChannel = channel;
testTeam = team;
testUser = user;
});
testUsersForRoles = {};
Cypress._.forEach(roleNames, (roleName) => {
cy.apiCreateUser().then(({user}) => {
testUsersForRoles[roleName] = user;
cy.apiAddUserToTeam(testTeam.id, user.id);
});
});
});
it('MM-T5596 Verify Admin can change user\'s settings from the user management in admin console', () => {
cy.apiAdminLogin();
cy.visit('/admin_console/user_management/users');
gotoUserConfigurationPage(testUser);
verifyManageUserSettingModal(testUser, true);
cy.findByRole('heading', {name: 'Reply notifications'}).scrollIntoView().click();
cy.get('#notificationCommentsNever').should('be.checked');
cy.get('#notificationCommentsAny').check();
cy.get('button#saveSetting').last().scrollIntoView().click();
cy.apiLogout();
cy.apiLogin(testUser);
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
cy.get('[aria-label="Settings"]').click();
cy.findByRole('heading', {name: 'Reply notifications'}).scrollIntoView().click();
cy.get('#notificationCommentsAny').should('be.checked');
cy.apiLogout();
});
roleNames.forEach((role) => {
it(`MM-T5597 Verify manage user's settings option is visible for role: ${role} with Can Edit access`, () => {
const writeAccess = true;
// TODO: remove below if loop after fixing Bug: https://mattermost.atlassian.net/browse/MM-59376
if (role !== 'system_manager' && role !== 'system_read_only_admin') {
// # Make the user a System User Manager
makeUserASystemRole(testUsersForRoles[role].email, role, writeAccess);
// * Login as the new user and verify the role permissions (ensure they really are a system user manager)
verifyAccessToUserSettings(testUsersForRoles[role], writeAccess);
}
});
});
roleNames.forEach((role) => {
it(`MM-T5597 Verify manage user's settings option is Not visible for role: ${role} with Read only access`, () => {
const writeAccess = false;
// TODO: remove below if loop after fixing Bug: https://mattermost.atlassian.net/browse/MM-59376
if (role !== 'system_manager' && role !== 'system_read_only_admin') {
// # Make the user a System User Manager
makeUserASystemRole(testUsersForRoles[role].email, role, writeAccess);
// * Login as the new user and verify the role permissions (ensure they really are a system user manager)
verifyAccessToUserSettings(testUsersForRoles[role], writeAccess);
}
});
});
function gotoUserConfigurationPage(user) {
cy.intercept('**api/v4/reports/users?**').as('getUserList');
cy.get('#input_searchTerm').clear().type(user.id);
cy.wait('@getUserList');
cy.get('#systemUsersTable-cell-0_emailColumn').should('have.text', user.email).click();
cy.url().should('include', `user_management/user/${user.id}`);
}
function verifyManageUserSettingModal(user, writeAccess) {
if (writeAccess) {
cy.get('.manageUserSettingsBtn').should('be.visible').should('have.text', 'Manage User Settings').click();
cy.get('#genericModalLabel').should('be.visible').should('have.text', `Manage ${user.nickname}'s Settings`);
cy.get('#cancelModalButton').should('be.visible').should('have.text', 'Cancel');
cy.get('#confirmModalButton').should('be.visible').should('have.text', 'Manage User Settings').click();
cy.get('span#accountSettingsModalLabel').should('be.visible').should('have.text', `Manage ${user.nickname}'s Settings`);
cy.get('.adminModeBadge').should('be.visible').should('have.text', 'Admin Mode');
} else {
cy.get('.manageUserSettingsBtn').should('not.exist');
}
}
function makeUserASystemRole(userEmail, role, writeAccess) {
// # Login as each new role.
cy.apiAdminLogin();
// # Go the system console.
cy.visit('/admin_console/user_management/system_roles');
cy.get('.admin-console__header').within(() => {
cy.findByText('Delegated Granular Administration', {timeout: TIMEOUTS.ONE_MIN}).should('exist').and('be.visible');
});
// # Click on edit for the role
cy.findByTestId(`${role}_edit`).click();
cy.get('button#systemRolePermissionDropdownuser_management_users').click();
cy.get('div.PermissionSectionDropdownOptions_label').filter(`:contains("${writeAccess ? 'Can edit' : 'Read only'}")`).should('have.text', writeAccess ? 'Can edit' : 'Read only').click();
// # Click Add People button
cy.findByRole('button', {name: 'Add People'}).click().wait(TIMEOUTS.HALF_SEC);
// # Type in user name
cy.findByRole('combobox', {name: 'Search for people'}).typeWithForce(`${userEmail}`);
// # Find the user and click on him
cy.get('#multiSelectList').should('be.visible').children().first().click({force: true});
// # Click add button
cy.findByRole('button', {name: 'Add'}).click().wait(TIMEOUTS.HALF_SEC);
// # Click save button
cy.findByRole('button', {name: 'Save'}).click().wait(TIMEOUTS.HALF_SEC);
cy.apiLogout();
}
function verifyAccessToUserSettings(user, writeAccess) {
// # Login as each new role.
cy.apiLogin(user);
// # Go the system console.
cy.visit('/admin_console/user_management/users');
gotoUserConfigurationPage(user);
verifyManageUserSettingModal(user, writeAccess);
cy.apiLogout();
}
});