Move /e2e -> /e2e-tests
Этот коммит содержится в:
@@ -0,0 +1,321 @@
|
||||
// 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 @accessibility
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('Verify Accessibility Support in different input fields', () => {
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
testTeam = team;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiCreateChannel(testTeam.id, 'accessibility', 'accessibility').then(({channel}) => {
|
||||
testChannel = channel;
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1456 Verify Accessibility Support in Input fields in Invite People Flow', () => {
|
||||
// # Open team menu and click 'Invite People'
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
// # Click invite members if needed
|
||||
cy.get('.InviteAs').findByTestId('inviteMembersLink').click();
|
||||
|
||||
cy.findByTestId('InviteView__copyInviteLink').then((el) => {
|
||||
const copyInviteLinkAriaLabel = el.attr('aria-label');
|
||||
expect(copyInviteLinkAriaLabel).to.match(/^team invite link/i);
|
||||
});
|
||||
|
||||
// * Verify Accessibility Support in Add or Invite People input field
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').should('have.attr', 'aria-label', 'Add or Invite People').and('have.attr', 'aria-autocomplete', 'list');
|
||||
cy.get('.users-emails-input__placeholder').should('have.text', 'Enter a name or email address');
|
||||
});
|
||||
|
||||
// # Click on Invite Guests link
|
||||
cy.findByTestId('inviteGuestLink').should('be.visible').click();
|
||||
|
||||
// * Verify Accessibility Support in Invite People input field
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').should('have.attr', 'aria-label', 'Add or Invite People').and('have.attr', 'aria-autocomplete', 'list');
|
||||
cy.get('.users-emails-input__placeholder').should('have.text', 'Enter a name or email address');
|
||||
});
|
||||
|
||||
// * Verify Accessibility Support in Search and Add Channels input field
|
||||
cy.get('.channels-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').should('have.attr', 'aria-label', 'Search and Add Channels').and('have.attr', 'aria-autocomplete', 'list');
|
||||
cy.get('.channels-input__placeholder').should('have.text', `e.g. ${testChannel.display_name}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1457 Verify Accessibility Support in Search Autocomplete', () => {
|
||||
// # Adding at least five other users in the channel
|
||||
for (let i = 0; i < 5; i++) {
|
||||
cy.apiCreateUser().then(({user}) => { // eslint-disable-line
|
||||
cy.apiAddUserToTeam(testTeam.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(testChannel.id, user.id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// * Verify Accessibility support in search input
|
||||
cy.get('#searchBox').should('have.attr', 'aria-describedby', 'searchbar-help-popup').and('have.attr', 'aria-label', 'Search').focus();
|
||||
cy.get('#searchbar-help-popup').should('be.visible').and('have.attr', 'role', 'tooltip');
|
||||
|
||||
// # Ensure User list is cached once in UI
|
||||
cy.get('#searchBox').type('from:').wait(TIMEOUTS.FIVE_SEC);
|
||||
|
||||
// # Trigger the user autocomplete again
|
||||
cy.get('#searchBox').clear().type('from:').wait(TIMEOUTS.FIVE_SEC).type('{downarrow}{downarrow}');
|
||||
|
||||
// * Verify Accessibility Support in search autocomplete
|
||||
verifySearchAutocomplete(2);
|
||||
|
||||
// # Press Down arrow twice and verify if focus changes
|
||||
cy.focused().type('{downarrow}{downarrow}');
|
||||
verifySearchAutocomplete(4);
|
||||
|
||||
// # Press Up arrow and verify if focus changes
|
||||
cy.focused().type('{uparrow}');
|
||||
verifySearchAutocomplete(3);
|
||||
|
||||
// # Type the in: filter and ensure channel list is cached once
|
||||
cy.get('#searchBox').clear().type('in:').wait(TIMEOUTS.FIVE_SEC);
|
||||
|
||||
// # Trigger the channel autocomplete again
|
||||
cy.get('#searchBox').clear().type('in:').wait(TIMEOUTS.FIVE_SEC).type('{downarrow}{downarrow}');
|
||||
|
||||
// * Verify Accessibility Support in search autocomplete
|
||||
verifySearchAutocomplete(2, 'channel');
|
||||
|
||||
// # Press Up arrow and verify if focus changes
|
||||
cy.focused().type('{uparrow}{uparrow}');
|
||||
verifySearchAutocomplete(0, 'channel');
|
||||
});
|
||||
|
||||
it('MM-T1455 Verify Accessibility Support in Message Autocomplete', () => {
|
||||
// # Adding at least one other user in the channel
|
||||
cy.apiCreateUser().then(({user}) => {
|
||||
cy.apiAddUserToTeam(testTeam.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(testChannel.id, user.id).then(() => {
|
||||
// * Verify Accessibility support in post input field
|
||||
cy.uiGetPostTextBox().should('have.attr', 'aria-label', `write to ${testChannel.display_name}`).clear().focus();
|
||||
|
||||
// # Ensure User list is cached once in UI
|
||||
cy.uiGetPostTextBox().type('@').wait(TIMEOUTS.FIVE_SEC);
|
||||
|
||||
// # Select the first user in the list
|
||||
cy.get('#suggestionList').find('.suggestion-list__item').eq(0).within((el) => {
|
||||
cy.get('.suggestion-list__main').invoke('text').then((text) => {
|
||||
cy.wrap(el).parents('body').find('#post_textbox').clear().type(text);
|
||||
});
|
||||
});
|
||||
|
||||
// # Trigger the user autocomplete again
|
||||
cy.uiGetPostTextBox().clear().type('@').wait(TIMEOUTS.FIVE_SEC).type('{uparrow}{uparrow}{downarrow}');
|
||||
|
||||
// * Verify Accessibility Support in message autocomplete
|
||||
verifyMessageAutocomplete(1);
|
||||
|
||||
// # Press Up arrow and verify if focus changes
|
||||
cy.focused().type('{downarrow}{uparrow}{uparrow}');
|
||||
|
||||
// * Verify Accessibility Support in message autocomplete
|
||||
verifyMessageAutocomplete(0);
|
||||
|
||||
// # Trigger the channel autocomplete filter and ensure channel list is cached once
|
||||
cy.uiGetPostTextBox().clear().type('~').wait(TIMEOUTS.FIVE_SEC);
|
||||
|
||||
// # Trigger the channel autocomplete again
|
||||
cy.uiGetPostTextBox().clear().type('~').wait(TIMEOUTS.FIVE_SEC).type('{downarrow}{downarrow}');
|
||||
|
||||
// * Verify Accessibility Support in message autocomplete
|
||||
verifyMessageAutocomplete(2, 'channel');
|
||||
|
||||
// # Press Up arrow and verify if focus changes
|
||||
cy.focused().type('{downarrow}{uparrow}{uparrow}');
|
||||
|
||||
// * Verify Accessibility Support in message autocomplete
|
||||
verifyMessageAutocomplete(1, 'channel');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1458 Verify Accessibility Support in Main Post Input', () => {
|
||||
cy.get('#advancedTextEditorCell').within(() => {
|
||||
// * Verify Accessibility Support in Main Post input
|
||||
cy.uiGetPostTextBox().should('have.attr', 'aria-label', `write to ${testChannel.display_name}`).and('have.attr', 'role', 'textbox').clear().focus().type('test');
|
||||
|
||||
// # Set a11y focus on the textbox
|
||||
cy.get('#FormattingControl_bold').focus().tab({shift: true});
|
||||
|
||||
// * Verify if the focus is on the preview button
|
||||
cy.get('#PreviewInputTextButton').should('be.focused').and('have.attr', 'aria-label', 'preview').tab();
|
||||
|
||||
// * Verify if the focus is on the bold button
|
||||
cy.get('#FormattingControl_bold').should('be.focused').and('have.attr', 'aria-label', 'bold').tab();
|
||||
|
||||
// * Verify if the focus is on the italic button
|
||||
cy.get('#FormattingControl_italic').should('be.focused').and('have.attr', 'aria-label', 'italic').tab();
|
||||
|
||||
// * Verify if the focus is on the strike through button
|
||||
cy.get('#FormattingControl_strike').should('be.focused').and('have.attr', 'aria-label', 'strike through').tab();
|
||||
|
||||
// * Verify if the focus is on the heading button
|
||||
cy.get('#FormattingControl_heading').should('be.focused').and('have.attr', 'aria-label', 'heading').tab();
|
||||
|
||||
// * Verify if the focus is on the link button
|
||||
cy.get('#FormattingControl_link').should('be.focused').and('have.attr', 'aria-label', 'link').tab();
|
||||
|
||||
// * Verify if the focus is on the code block button
|
||||
cy.get('#FormattingControl_code').should('be.focused').and('have.attr', 'aria-label', 'code').tab();
|
||||
|
||||
// * Verify if the focus is on the preview button
|
||||
cy.get('#FormattingControl_quote').should('be.focused').and('have.attr', 'aria-label', 'quote').tab();
|
||||
|
||||
// * Verify if the focus is on the bulleted list button
|
||||
cy.get('#FormattingControl_ul').should('be.focused').and('have.attr', 'aria-label', 'bulleted list').tab();
|
||||
|
||||
// * Verify if the focus is on the numbered list button
|
||||
cy.get('#FormattingControl_ol').should('be.focused').and('have.attr', 'aria-label', 'numbered list').tab();
|
||||
|
||||
// * Verify if the focus is on the formatting options button
|
||||
cy.get('#toggleFormattingBarButton').should('be.focused').and('have.attr', 'aria-label', 'formatting').tab();
|
||||
|
||||
// * Verify if the focus is on the attachment icon
|
||||
cy.get('#fileUploadButton').should('be.focused').and('have.attr', 'aria-label', 'attachment').tab();
|
||||
|
||||
// * Verify if the focus is on the emoji picker
|
||||
cy.get('#emojiPickerButton').should('be.focused').and('have.attr', 'aria-label', 'select an emoji').tab();
|
||||
});
|
||||
|
||||
// * Verify if the focus is on the help link
|
||||
cy.findByTestId('SendMessageButton').should('be.focused');
|
||||
});
|
||||
|
||||
it('MM-T1490 Verify Accessibility Support in RHS Input', () => {
|
||||
// # Wait till page is loaded
|
||||
cy.uiGetPostTextBox().clear();
|
||||
|
||||
// # Post a message and open RHS
|
||||
const message = `hello${Date.now()}`;
|
||||
cy.postMessage(message);
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// # Mouseover the post and click post comment icon.
|
||||
cy.clickPostCommentIcon(postId);
|
||||
});
|
||||
|
||||
cy.get('#rhsContainer').within(() => {
|
||||
// * Verify Accessibility Support in RHS input
|
||||
cy.uiGetReplyTextBox().should('have.attr', 'aria-label', 'reply to this thread...').and('have.attr', 'role', 'textbox').focus().type('test').tab({shift: true}).tab().tab();
|
||||
|
||||
// * Verify if the focus is on the preview button
|
||||
cy.get('#PreviewInputTextButton').should('be.focused').and('have.attr', 'aria-label', 'preview').tab();
|
||||
|
||||
// * Verify if the focus is on the bold button
|
||||
cy.get('#FormattingControl_bold').should('be.focused').and('have.attr', 'aria-label', 'bold').tab();
|
||||
|
||||
// * Verify if the focus is on the italic button
|
||||
cy.get('#FormattingControl_italic').should('be.focused').and('have.attr', 'aria-label', 'italic').tab();
|
||||
|
||||
// * Verify if the focus is on the strike through button
|
||||
cy.get('#FormattingControl_strike').should('be.focused').and('have.attr', 'aria-label', 'strike through').tab();
|
||||
|
||||
// * Verify if the focus is on the hidden controls button
|
||||
cy.get('#HiddenControlsButtonRHS_COMMENT').should('be.focused').and('have.attr', 'aria-label', 'show hidden formatting options').tab();
|
||||
|
||||
// * Verify if the focus is on the hidden heading button
|
||||
cy.get('#FormattingControl_heading').should('be.focused').and('have.attr', 'aria-label', 'heading').tab();
|
||||
|
||||
// * Verify if the focus is on the hidden link button
|
||||
cy.get('#FormattingControl_link').should('be.focused').and('have.attr', 'aria-label', 'link').tab();
|
||||
|
||||
// * Verify if the focus is on the hidden code button
|
||||
cy.get('#FormattingControl_code').should('be.focused').and('have.attr', 'aria-label', 'code').tab();
|
||||
|
||||
// * Verify if the focus is on the hidden quote button
|
||||
cy.get('#FormattingControl_quote').should('be.focused').and('have.attr', 'aria-label', 'quote').tab();
|
||||
|
||||
// * Verify if the focus is on the hidden bulleted list button
|
||||
cy.get('#FormattingControl_ul').should('be.focused').and('have.attr', 'aria-label', 'bulleted list').tab();
|
||||
|
||||
// * Verify if the focus is on the hidden numbered list button
|
||||
cy.get('#FormattingControl_ol').should('be.focused').and('have.attr', 'aria-label', 'numbered list').tab();
|
||||
|
||||
// * Verify if the focus is on the formatting options button
|
||||
cy.get('#toggleFormattingBarButton').should('be.focused').and('have.attr', 'aria-label', 'formatting').tab();
|
||||
|
||||
// * Verify if the focus is on the attachment icon
|
||||
cy.get('#fileUploadButton').should('be.focused').and('have.attr', 'aria-label', 'attachment').tab();
|
||||
|
||||
// * Verify if the focus is on the emoji picker
|
||||
cy.get('#emojiPickerButton').should('be.focused').and('have.attr', 'aria-label', 'select an emoji').tab();
|
||||
|
||||
// * Verify if the focus is on the Reply button
|
||||
cy.findByTestId('SendMessageButton').should('be.focused');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getUserMentionAriaLabel(displayName) {
|
||||
return displayName.
|
||||
replace('(you)', '').
|
||||
replace(/[@()]/g, '').
|
||||
toLowerCase().
|
||||
trim();
|
||||
}
|
||||
|
||||
function verifySearchAutocomplete(index, type = 'user') {
|
||||
cy.get('#search-autocomplete__popover').find('.suggestion-list__item').eq(index).should('be.visible').and('have.class', 'suggestion--selected').within((el) => {
|
||||
if (type === 'user') {
|
||||
cy.get('.suggestion-list__ellipsis').invoke('text').then((text) => {
|
||||
const usernameLength = 12;
|
||||
const displayName = text.substring(1, usernameLength) + ' ' + text.substring(usernameLength, text.length);
|
||||
const userAriaLabel = getUserMentionAriaLabel(displayName);
|
||||
cy.wrap(el).parents('#searchFormContainer').find('.sr-only').should('have.attr', 'aria-live', 'polite').and('have.text', userAriaLabel);
|
||||
});
|
||||
} else if (type === 'channel') {
|
||||
cy.get('.suggestion-list__ellipsis').invoke('text').then((text) => {
|
||||
const channel = text.split('~')[1].toLowerCase().trim();
|
||||
cy.wrap(el).parents('#searchFormContainer').find('.sr-only').should('have.attr', 'aria-live', 'polite').and('have.text', channel);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function verifyMessageAutocomplete(index, type = 'user') {
|
||||
cy.get('#suggestionList').find('.suggestion-list__item').eq(index).should('be.visible').and('have.class', 'suggestion--selected').within((el) => {
|
||||
if (type === 'user') {
|
||||
cy.get('.suggestion-list__ellipsis').invoke('text').then((fullText) => {
|
||||
cy.get('.suggestion-list__main').invoke('text').then((username) => {
|
||||
const usernameFullNameNickName = getUserMentionAriaLabel(`${username} ${fullText.split(username)[1]}`);
|
||||
cy.wrap(el).parents('.textarea-wrapper').find('.sr-only').should('have.attr', 'aria-live', 'polite').and('have.text', usernameFullNameNickName);
|
||||
});
|
||||
});
|
||||
} else if (type === 'channel') {
|
||||
cy.wrap(el).invoke('text').then((text) => {
|
||||
const channel = text.split('~')[0].toLowerCase().trim();
|
||||
cy.wrap(el).parents('.textarea-wrapper').find('.sr-only').should('have.attr', 'aria-live', 'polite').and('have.text', channel);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
// 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 @accessibility
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('Verify Accessibility Support in Modals & Dialogs', () => {
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
let testUser;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
cy.apiInitSetup({userPrefix: 'user000a'}).then(({team, channel, user}) => {
|
||||
testTeam = team;
|
||||
testChannel = channel;
|
||||
testUser = user;
|
||||
|
||||
cy.apiCreateUser().then(({user: newUser}) => {
|
||||
cy.apiAddUserToTeam(testTeam.id, newUser.id).then(() => {
|
||||
cy.apiAddUserToChannel(testChannel.id, newUser.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Login as sysadmin and visit the town-square
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
});
|
||||
|
||||
it('MM-T1454 Accessibility Support in Different Modals and Dialog screen', () => {
|
||||
// * Verify the accessibility support in Profile Dialog
|
||||
verifyUserMenuModal('Profile');
|
||||
|
||||
// * Verify the accessibility support in Team Settings Dialog
|
||||
verifyMainMenuModal('Team Settings');
|
||||
|
||||
// * Verify the accessibility support in Manage Members Dialog
|
||||
verifyMainMenuModal('Manage Members', `${testTeam.display_name} Members`);
|
||||
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// * Verify the accessibility support in Channel Edit Header Dialog
|
||||
verifyChannelMenuModal('Edit Channel Header', 'Edit Header for Off-Topic');
|
||||
|
||||
cy.wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify the accessibility support in Channel Edit Purpose Dialog
|
||||
verifyChannelMenuModal('Edit Channel Purpose', 'Edit Purpose for Off-Topic');
|
||||
|
||||
// * Verify the accessibility support in Rename Channel Dialog
|
||||
verifyChannelMenuModal('Rename Channel');
|
||||
});
|
||||
|
||||
it('MM-T1487 Accessibility Support in Manage Channel Members Dialog screen', () => {
|
||||
// # Visit test team and channel
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// # Open Channel Members Dialog
|
||||
cy.get('#channelHeaderDropdownIcon').click();
|
||||
cy.findByText('Manage Members').click().wait(TIMEOUTS.FIVE_SEC);
|
||||
|
||||
// * Verify the accessibility support in Manage Members Dialog
|
||||
cy.findByRole('dialog', {name: 'Off-Topic Members'}).within(() => {
|
||||
cy.findByRole('heading', {name: 'Off-Topic Members'});
|
||||
|
||||
// # Set focus on search input
|
||||
cy.findByPlaceholderText('Search users').
|
||||
focus().
|
||||
type(' {backspace}').
|
||||
wait(TIMEOUTS.HALF_SEC).
|
||||
tab({shift: true}).tab();
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// # Press tab and verify focus on first user's profile image
|
||||
cy.focused().tab();
|
||||
cy.findByAltText('sysadmin profile image').should('be.focused');
|
||||
|
||||
// # Press tab and verify focus on first user's username
|
||||
cy.focused().tab();
|
||||
cy.focused().should('have.text', '@sysadmin');
|
||||
|
||||
// # Press tab and verify focus on second user's profile image
|
||||
cy.focused().tab();
|
||||
cy.findByAltText(`${testUser.username} profile image`).should('be.focused');
|
||||
|
||||
// # Press tab and verify focus on second user's username
|
||||
cy.focused().tab();
|
||||
cy.focused().should('have.text', `@${testUser.username}`);
|
||||
|
||||
// # Press tab and verify focus on second user's dropdown option
|
||||
cy.focused().tab();
|
||||
cy.focused().should('have.class', 'dropdown-toggle').and('contain', 'Channel Member');
|
||||
|
||||
// * Verify accessibility support in search total results
|
||||
cy.get('#searchableUserListTotal').should('have.attr', 'aria-live', 'polite');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function verifyMainMenuModal(menuItem, modalName) {
|
||||
cy.uiGetLHSHeader().click();
|
||||
verifyModal(menuItem, modalName);
|
||||
}
|
||||
|
||||
function verifyChannelMenuModal(menuItem, modalName) {
|
||||
cy.get('#channelHeaderDropdownIcon').click();
|
||||
verifyModal(menuItem, modalName);
|
||||
}
|
||||
|
||||
function verifyUserMenuModal(menuItem) {
|
||||
cy.uiGetSetStatusButton().click();
|
||||
verifyModal(menuItem);
|
||||
}
|
||||
|
||||
function verifyModal(menuItem, modalName) {
|
||||
// * Verify that menu is open
|
||||
cy.findByRole('menu');
|
||||
|
||||
// # Click menu item
|
||||
cy.findByText(menuItem).click();
|
||||
|
||||
// * Verify the modal
|
||||
const name = modalName || menuItem;
|
||||
cy.findByRole('dialog', {name}).within(() => {
|
||||
cy.findByRole('heading', {name});
|
||||
cy.uiClose();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
// 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 @accessibility
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('Verify Accessibility Support in Modals & Dialogs', () => {
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
let testUser;
|
||||
let selectedRowText;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
cy.apiInitSetup({userPrefix: 'user000a'}).then(({team, channel, user}) => {
|
||||
testTeam = team;
|
||||
testChannel = channel;
|
||||
testUser = user;
|
||||
|
||||
cy.apiCreateUser().then(({user: newUser}) => {
|
||||
cy.apiAddUserToTeam(testTeam.id, newUser.id).then(() => {
|
||||
cy.apiAddUserToChannel(testChannel.id, newUser.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Login as sysadmin and visit the town-square
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
});
|
||||
|
||||
it('MM-T1466 Accessibility Support in Direct Messages Dialog screen', () => {
|
||||
// * Verify the aria-label in create direct message button
|
||||
cy.uiAddDirectMessage().click();
|
||||
|
||||
// * Verify the accessibility support in Direct Messages Dialog
|
||||
cy.findAllByRole('dialog', 'Direct Messages').eq(0).within(() => {
|
||||
cy.findByRole('heading', 'Direct Messages');
|
||||
|
||||
// * Verify the accessibility support in search input
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
should('have.attr', 'aria-autocomplete', 'list');
|
||||
|
||||
// # Search for a text and then check up and down arrow
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
typeWithForce('s').
|
||||
wait(TIMEOUTS.HALF_SEC).
|
||||
typeWithForce('{downarrow}{downarrow}{downarrow}{uparrow}');
|
||||
cy.get('#multiSelectList').children().eq(2).should('have.class', 'more-modal__row--selected').within(() => {
|
||||
cy.get('.more-modal__name').invoke('text').then((user) => {
|
||||
selectedRowText = user.split(' - ')[0].replace('@', '');
|
||||
});
|
||||
|
||||
// * Verify image alt is displayed
|
||||
cy.get('img.Avatar').should('have.attr', 'alt', 'user profile image');
|
||||
});
|
||||
|
||||
// * Verify if the reader is able to read out the selected row
|
||||
cy.get('.filtered-user-list .sr-only').
|
||||
should('have.attr', 'aria-live', 'polite').
|
||||
and('have.attr', 'aria-atomic', 'true').
|
||||
invoke('text').then((text) => {
|
||||
expect(text).equal(selectedRowText);
|
||||
});
|
||||
|
||||
// # Search for an invalid text
|
||||
const additionalSearchTerm = 'somethingwhichdoesnotexist';
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).clear().
|
||||
typeWithForce(additionalSearchTerm).
|
||||
wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Check if reader can read no results
|
||||
cy.get('.multi-select__wrapper').should('have.attr', 'aria-live', 'polite').and('have.text', `No results found matching ${additionalSearchTerm}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1467 Accessibility Support in More Channels Dialog screen', () => {
|
||||
function getChannelAriaLabel(channel) {
|
||||
return channel.display_name.toLowerCase() + ', ' + channel.purpose.toLowerCase();
|
||||
}
|
||||
|
||||
// # Create atleast 2 channels
|
||||
let otherChannel;
|
||||
cy.apiCreateChannel(testTeam.id, 'z_accessibility', 'Z Accessibility', 'O', 'other purpose').then(({channel}) => {
|
||||
otherChannel = channel;
|
||||
});
|
||||
cy.apiCreateChannel(testTeam.id, 'accessibility', 'Accessibility', 'O', 'some purpose').then(({channel}) => {
|
||||
cy.apiLogin(testUser).then(() => {
|
||||
cy.reload();
|
||||
|
||||
// * Verify the aria-label in more public channels button
|
||||
cy.uiBrowseOrCreateChannel('Browse Channels').click();
|
||||
|
||||
// * Verify the accessibility support in More Channels Dialog
|
||||
cy.findByRole('dialog', {name: 'More Channels'}).within(() => {
|
||||
cy.findByRole('heading', {name: 'More Channels'});
|
||||
|
||||
// * Verify the accessibility support in search input
|
||||
cy.findByPlaceholderText('Search channels');
|
||||
|
||||
cy.waitUntil(() => cy.get('#moreChannelsList').then((el) => {
|
||||
return el[0].children.length === 2;
|
||||
}));
|
||||
|
||||
// # Focus on the Create Channel button and TAB twice
|
||||
cy.get('#createNewChannel').focus().tab().tab();
|
||||
|
||||
// * Verify channel name is highlighted and reader reads the channel name and channel description
|
||||
cy.get('#moreChannelsList').children().eq(0).within(() => {
|
||||
const selectedChannel = getChannelAriaLabel(channel);
|
||||
cy.findByLabelText(selectedChannel).should('be.focused');
|
||||
|
||||
// * Press Tab and verify if focus changes to Join button
|
||||
cy.focused().tab();
|
||||
cy.findByText('Join').parent().should('be.focused');
|
||||
|
||||
// * Verify previous button should no longer be focused
|
||||
cy.findByLabelText(selectedChannel).should('not.be.focused');
|
||||
});
|
||||
|
||||
// * Press Tab again and verify if focus changes to next row
|
||||
cy.focused().tab();
|
||||
cy.findByLabelText(getChannelAriaLabel(otherChannel)).should('be.focused');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1468 Accessibility Support in Add people to Channel Dialog screen', () => {
|
||||
// # Add atleast 5 users
|
||||
for (let i = 0; i < 5; i++) {
|
||||
cy.apiCreateUser().then(({user}) => { // eslint-disable-line
|
||||
cy.apiAddUserToTeam(testTeam.id, user.id);
|
||||
});
|
||||
}
|
||||
|
||||
// # Visit the test channel
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// # Open Add Members Dialog
|
||||
cy.get('#channelHeaderDropdownIcon').click();
|
||||
cy.findByText('Add Members').click();
|
||||
|
||||
// * Verify the accessibility support in Add people Dialog
|
||||
cy.findAllByRole('dialog').eq(0).within(() => {
|
||||
const modalName = `Add people to ${testChannel.display_name}`;
|
||||
cy.findByRole('heading', {name: modalName});
|
||||
|
||||
// * Verify the accessibility support in search input
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
should('have.attr', 'aria-autocomplete', 'list');
|
||||
|
||||
// # Search for a text and then check up and down arrow
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
typeWithForce('u').
|
||||
wait(TIMEOUTS.HALF_SEC).
|
||||
typeWithForce('{downarrow}{downarrow}{downarrow}{uparrow}');
|
||||
cy.get('#multiSelectList').
|
||||
children().eq(1).
|
||||
should('have.class', 'more-modal__row--selected').
|
||||
within(() => {
|
||||
cy.get('.more-modal__name').invoke('text').then((user) => {
|
||||
selectedRowText = user.split(' - ')[0].replace('@', '');
|
||||
});
|
||||
|
||||
// * Verify image alt is displayed
|
||||
cy.get('img.Avatar').should('have.attr', 'alt', 'user profile image');
|
||||
});
|
||||
|
||||
// * Verify if the reader is able to read out the selected row
|
||||
cy.get('.filtered-user-list .sr-only').
|
||||
should('have.attr', 'aria-live', 'polite').
|
||||
and('have.attr', 'aria-atomic', 'true').
|
||||
invoke('text').then((text) => {
|
||||
expect(text).equal(selectedRowText);
|
||||
});
|
||||
|
||||
// # Search for an invalid text and check if reader can read no results
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
typeWithForce('somethingwhichdoesnotexist').
|
||||
wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Check if reader can read no results
|
||||
cy.get('.custom-no-options-message').
|
||||
should('be.visible').
|
||||
and('contain', 'No matches found - Invite them to the team');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1515 Verify Accessibility Support in Invite People Flow', () => {
|
||||
// # Open Invite People
|
||||
cy.uiGetLHSHeader().click();
|
||||
cy.get('#invitePeople').should('be.visible').click();
|
||||
|
||||
// * Verify accessibility support in Invite People Dialog
|
||||
cy.get('.InvitationModal').should('have.attr', 'aria-modal', 'true').and('have.attr', 'aria-labelledby', 'invitation_modal_title').and('have.attr', 'role', 'dialog');
|
||||
cy.get('#invitation_modal_title').should('be.visible').and('contain.text', 'Invite people to');
|
||||
|
||||
// # Press tab
|
||||
cy.get('button.icon-close').focus().tab({shift: true}).tab();
|
||||
|
||||
// * Verify tab focuses on close button
|
||||
cy.get('button.icon-close').should('have.attr', 'aria-label', 'Close').and('be.focused');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// 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 @authentication
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
import {getRandomId} from '../../../../utils';
|
||||
|
||||
describe('Authentication', () => {
|
||||
let testTeam;
|
||||
|
||||
before(() => {
|
||||
cy.apiRequireLicense();
|
||||
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
testTeam = team;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Log in as a admin.
|
||||
cy.apiAdminLogin();
|
||||
});
|
||||
|
||||
it('MM-T1759 - Restrict Domains - Team invite open team', () => {
|
||||
// # Set restricted domain
|
||||
cy.apiUpdateConfig({
|
||||
TeamSettings: {
|
||||
RestrictCreationToDomains: 'mattermost.com, test.com',
|
||||
},
|
||||
}).then(() => {
|
||||
cy.visit(`/admin_console/user_management/teams/${testTeam.id}`);
|
||||
|
||||
cy.findByTestId('allowAllToggleSwitch', {timeout: TIMEOUTS.ONE_MIN}).click();
|
||||
|
||||
// # Click "Save"
|
||||
cy.findByText('Save').scrollIntoView().click();
|
||||
|
||||
// # Wait until we are at the Mattermost Teams page
|
||||
cy.findByText('Mattermost Teams', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
|
||||
|
||||
cy.apiLogout();
|
||||
|
||||
cy.visit(`/signup_user_complete/?id=${testTeam.invite_id}`);
|
||||
|
||||
cy.get('#input_email', {timeout: TIMEOUTS.ONE_MIN}).type(`Hossein_Is_The_Best_PROGRAMMER${getRandomId()}@BestInTheWorld.com`);
|
||||
|
||||
cy.get('#input_password-input').type('Test123456!');
|
||||
|
||||
cy.get('#input_name').clear().type(`HosseinIs2Cool${getRandomId()}`);
|
||||
|
||||
cy.findByText('Create Account').click();
|
||||
|
||||
// * Make sure account was not created successfully
|
||||
cy.findByText('The email you provided does not belong to an accepted domain. Please contact your administrator or sign up with a different email.').should('be.visible').and('exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1761 - Enable Open Server - Create link appears if email account creation is false and other signin methods are true', () => {
|
||||
// # Disable sign up with email but enable LDAP
|
||||
cy.apiUpdateConfig({
|
||||
EmailSettings: {
|
||||
EnableSignUpWithEmail: false,
|
||||
},
|
||||
LdapSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
}).then(() => {
|
||||
cy.apiLogout();
|
||||
cy.visit('/');
|
||||
|
||||
// * Assert that create account button is visible
|
||||
cy.findByText('Don\'t have an account?', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1766 - Authentication - Email - Creation with email = true', () => {
|
||||
// # Enable user account creation and set restricted domain
|
||||
cy.apiUpdateConfig({
|
||||
EmailSettings: {
|
||||
EnableSignUpWithEmail: true,
|
||||
},
|
||||
TeamSettings: {
|
||||
RestrictCreationToDomains: 'mattermost.com, test.com',
|
||||
},
|
||||
}).then(() => {
|
||||
cy.apiLogout();
|
||||
|
||||
cy.visit(`/signup_user_complete/?id=${testTeam.invite_id}`);
|
||||
|
||||
// * Email and Password option exist
|
||||
cy.findByText('Email address').should('exist').and('be.visible');
|
||||
cy.findByPlaceholderText('Choose a Password').should('exist').and('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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 @authentication @mfa
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
const authenticator = require('authenticator');
|
||||
|
||||
describe('Authentication', () => {
|
||||
let mfaSysAdmin;
|
||||
let testUser;
|
||||
let adminMFASecret;
|
||||
|
||||
before(() => {
|
||||
cy.apiRequireLicenseForFeature('MFA');
|
||||
|
||||
// # Do email test if setup properly
|
||||
cy.shouldHaveEmailEnabled();
|
||||
|
||||
cy.apiInitSetup().then(({user}) => {
|
||||
testUser = user;
|
||||
});
|
||||
|
||||
// # Create and login a newly created user as sysadmin
|
||||
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
|
||||
mfaSysAdmin = sysadmin;
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1778 - MFA - Enforced', () => {
|
||||
// # Log in as a admin.
|
||||
cy.apiLogin(mfaSysAdmin);
|
||||
|
||||
// # Navigate to System Console -> Authentication -> MFA Page.
|
||||
cy.visit('/admin_console/authentication/mfa');
|
||||
cy.findByText('Multi-factor Authentication', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('exist');
|
||||
|
||||
// # Ensure the setting 'Enable Multi factor authentication' is set to true in the MFA page.
|
||||
cy.findByTestId('ServiceSettings.EnableMultifactorAuthenticationtrue').check();
|
||||
|
||||
// # Also ensure that this MFA setting is enforced.
|
||||
cy.findByTestId('ServiceSettings.EnforceMultifactorAuthenticationtrue').check();
|
||||
|
||||
// # Click "Save".
|
||||
cy.findByText('Save').click().wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// # Get MFA secret
|
||||
cy.uiGetMFASecret(mfaSysAdmin.id).then((secret) => {
|
||||
adminMFASecret = secret;
|
||||
|
||||
// # Navigate to System Console -> User Management -> Users
|
||||
cy.visit('/admin_console/user_management/users');
|
||||
cy.get('#searchUsers', {timeout: TIMEOUTS.ONE_MIN}).type(testUser.email);
|
||||
|
||||
// * Remove MFA option not available for the user
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
cy.findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').click();
|
||||
cy.findByText('Remove MFA').should('not.exist');
|
||||
|
||||
cy.apiLogout();
|
||||
});
|
||||
|
||||
// # Login as test user
|
||||
cy.uiLogin(testUser);
|
||||
cy.wait(TIMEOUTS.THREE_SEC);
|
||||
|
||||
// * MFA page is shown
|
||||
cy.findByText('Multi-factor Authentication Setup', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('exist');
|
||||
});
|
||||
|
||||
// This test relies on the previous test for having MFA enabled (MM-T1778)
|
||||
it('MM-T1781 - MFA - Admin removes another users MFA', () => {
|
||||
// # Login as test user
|
||||
cy.apiLogin(testUser);
|
||||
cy.wait(TIMEOUTS.THREE_SEC);
|
||||
|
||||
// # Complete MFA setup which we didnt do for the test user
|
||||
cy.get('#mfa').wait(TIMEOUTS.HALF_SEC).find('.col-sm-12').then((p) => {
|
||||
const secretp = p.text();
|
||||
const testUserMFASecret = secretp.split(' ')[1];
|
||||
|
||||
const token = authenticator.generateToken(testUserMFASecret);
|
||||
cy.findByPlaceholderText('MFA Code').type(token);
|
||||
cy.findByText('Save').click();
|
||||
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
cy.findByText('Okay').click();
|
||||
|
||||
cy.apiLogout();
|
||||
});
|
||||
|
||||
cy.wait(TIMEOUTS.THREE_SEC);
|
||||
|
||||
// # Login back as admin.
|
||||
const adminMFAToken = authenticator.generateToken(adminMFASecret);
|
||||
cy.apiLoginWithMFA(mfaSysAdmin, adminMFAToken);
|
||||
|
||||
// # Navigate to System Console -> User Management -> Users
|
||||
cy.visit('/admin_console/user_management/users');
|
||||
cy.get('#searchUsers', {timeout: TIMEOUTS.ONE_MIN}).type(testUser.email);
|
||||
|
||||
// * Remove MFA option available for the user and click it
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
cy.findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').click();
|
||||
cy.findByText('Remove MFA').should('be.visible').click();
|
||||
|
||||
// # Navigate to System Console -> Authentication -> MFA Page.
|
||||
cy.visit('/admin_console/authentication/mfa');
|
||||
cy.findByText('Multi-factor Authentication', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('exist');
|
||||
|
||||
// # Also ensure that this MFA setting is enforced.
|
||||
cy.findByTestId('ServiceSettings.EnforceMultifactorAuthenticationfalse').check();
|
||||
|
||||
// # Click "Save".
|
||||
cy.findByText('Save').click().wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// # Login as test user
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit('/');
|
||||
|
||||
// * No MFA page is shown
|
||||
cy.findByText('Multi-factor Authentication Setup', {timeout: TIMEOUTS.ONE_MIN}).should('not.exist').and('not.exist');
|
||||
});
|
||||
|
||||
// This test relies on the previous test for having MFA enabled (MM-T1781)
|
||||
it('MM-T1782 - MFA - Removing MFA option hidden for users without MFA set up', () => {
|
||||
// # Login back as admin.
|
||||
const token = authenticator.generateToken(adminMFASecret);
|
||||
cy.apiLoginWithMFA(mfaSysAdmin, token);
|
||||
|
||||
// # Navigate to System Console -> User Management -> Users
|
||||
cy.visit('/admin_console/user_management/users');
|
||||
cy.get('#searchUsers', {timeout: TIMEOUTS.ONE_MIN}).type(testUser.email);
|
||||
|
||||
// * Remove MFA option available for the user and click it
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
cy.findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').click();
|
||||
cy.findByText('Remove MFA').should('not.exist');
|
||||
|
||||
// # Done with that MFA stuff so we disable it all
|
||||
cy.apiUpdateConfig({
|
||||
ServiceSettings: {
|
||||
EnableMultifactorAuthentication: false,
|
||||
EnforceMultifactorAuthentication: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('Managing bot accounts', () => {
|
||||
let botName;
|
||||
|
||||
before(() => {
|
||||
cy.apiRequireLicenseForFeature('LDAP');
|
||||
|
||||
// # Create a test bot
|
||||
cy.apiCreateBot().then(({bot}) => {
|
||||
botName = bot.username;
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1855 Bot cannot login', () => {
|
||||
cy.apiLogout();
|
||||
cy.visit('/login');
|
||||
|
||||
// # Remove autofocus from login input
|
||||
cy.get('.login-body-card-content').should('be.visible').focus();
|
||||
|
||||
// # Enter bot name in the email field
|
||||
cy.findByPlaceholderText('Email, Username or AD/LDAP Username', {timeout: TIMEOUTS.ONE_MIN}).clear().type(botName);
|
||||
|
||||
// # Enter random password in the password field
|
||||
cy.findByPlaceholderText('Password').clear().type('invalidPassword@#%(^!');
|
||||
|
||||
// # Hit enter to login
|
||||
cy.get('#saveSetting').should('not.be.disabled').click();
|
||||
|
||||
// * Verify appropriate error message is displayed for bot login
|
||||
cy.findByText('Bot login is forbidden.').should('exist').and('be.visible');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
// 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 @ldap_group
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('channel groups', () => {
|
||||
const groups = [];
|
||||
let testTeam;
|
||||
|
||||
before(() => {
|
||||
cy.apiRequireLicenseForFeature('LDAP');
|
||||
|
||||
// # Link 2 groups
|
||||
cy.apiGetLDAPGroups().then((result) => {
|
||||
for (let i = 0; i < 2; i++) {
|
||||
cy.apiLinkGroup(result.body.groups[i].primary_key).then((response) => {
|
||||
groups.push(response.body);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
cy.apiUpdateConfig({LdapSettings: {Enable: true}, ServiceSettings: {EnableTutorial: false}});
|
||||
|
||||
// # Create a new team and associate one group to the team
|
||||
cy.apiCreateTeam('team', 'Team').then(({team}) => {
|
||||
testTeam = team;
|
||||
cy.apiLinkGroupTeam(groups[0].id, team.id);
|
||||
|
||||
// # Group-constrain the channel
|
||||
cy.apiGetChannelByName(testTeam.name, 'off-topic').then(({channel}) => {
|
||||
cy.apiPatchChannel(channel.id, {group_constrained: true});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.apiDeleteTeam(testTeam.id, true);
|
||||
for (let i = 0; i < 2; i++) {
|
||||
cy.apiUnlinkGroup(groups[i].remote_id);
|
||||
}
|
||||
});
|
||||
|
||||
it('limits the listed groups if the parent team is group-constrained', () => {
|
||||
// # Visit a channel
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// # Open the Add Groups modal
|
||||
openAddGroupsToChannelModal();
|
||||
|
||||
// * Ensure at least 2 groups are listed
|
||||
let beforeCount;
|
||||
cy.get('#addGroupsToChannelModal').find('.more-modal__row').then((items) => {
|
||||
beforeCount = Cypress.$(items).length;
|
||||
});
|
||||
cy.get('#addGroupsToChannelModal').find('.more-modal__row').its('length').should('be.gte', 2);
|
||||
|
||||
// # Group-constrain the parent team
|
||||
cy.apiPatchTeam(testTeam.id, {group_constrained: true});
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// # Close and re-open the Add Groups modal again
|
||||
openAddGroupsToChannelModal();
|
||||
|
||||
// * Ensure that only 1 group is listed
|
||||
cy.get('#addGroupsToChannelModal').find('.more-modal__row').then((items) => {
|
||||
const newCount = beforeCount - 1;
|
||||
expect(items).to.have.length(newCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function openAddGroupsToChannelModal() {
|
||||
cy.get('#channelHeaderTitle', {timeout: TIMEOUTS.ONE_MIN}).click();
|
||||
cy.get('#channelManageGroups').should('be.visible');
|
||||
cy.get('#channelManageGroups').click();
|
||||
cy.findByText('Add Groups').should('exist');
|
||||
cy.findByText('Add Groups').click();
|
||||
cy.get('#addGroupsToChannelModal').should('be.visible');
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
// 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 @cloud_only @cloud_trial
|
||||
|
||||
import * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
import billing from '../../../../../fixtures/client_billing.json';
|
||||
|
||||
describe('System Console - after subscription scenarios', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
|
||||
// # Visit Subscription page
|
||||
cy.visit('/admin_console/billing/subscription');
|
||||
|
||||
// * Check for Subscription header
|
||||
cy.contains('.admin-console__header', 'Subscription').should('be.visible');
|
||||
|
||||
// # Click Subscribe Now button
|
||||
cy.contains('span', 'Upgrade Now').parent().click();
|
||||
|
||||
cy.intercept('POST', '/api/v4/cloud/payment/confirm').as('confirm');
|
||||
|
||||
cy.intercept('GET', '/api/v4/cloud/subscription').as('subscribe');
|
||||
|
||||
// # Enter card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.visa.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.visa.expDate);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(billing.visa.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test name');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('India{enter}', {force: true});
|
||||
cy.get('#input_address').clear().type('testaddress');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('#input_state').clear().type('teststate');
|
||||
cy.get('#input_postalCode').clear().type('4444');
|
||||
|
||||
// # Click Subscribe button
|
||||
cy.get('.RHS').find('button').last().should('be.enabled').click();
|
||||
|
||||
cy.wait(['@confirm', '@subscribe']);
|
||||
|
||||
// * Check for success message
|
||||
cy.findByText('You are now subscribed to Cloud Professional', {timeout: TIMEOUTS.TEN_SEC}).should('be.visible');
|
||||
|
||||
// # Click Let's go! button
|
||||
cy.get('#payment_complete_header').find('button').should('be.enabled').click();
|
||||
|
||||
// * Check for non existence of 'Your trial has started!' in banner message
|
||||
cy.contains('span', 'Your trial has started!').should('not.exist');
|
||||
|
||||
// * Check for non existence of 'Subscribe now' button in banner message
|
||||
cy.contains('span', 'Upgrade Now').parent().should('not.exist');
|
||||
});
|
||||
|
||||
describe('System Console - Subscription section', () => {
|
||||
it('MM-T4134 Downloading of invoice after subscription', () => {
|
||||
navigateToBillingScreen('#billing\\/subscription', 'Subscription');
|
||||
|
||||
cy.get('.BillingSummary__lastInvoice-productName').invoke('text').as('productName');
|
||||
|
||||
cy.get('.BillingSummary__lastInvoice-chargeAmount').invoke('text').as('totalCharge');
|
||||
|
||||
// * Check the content from the downloaded pdf file
|
||||
cy.get('.BillingSummary__lastInvoice-download >a').then((link) => {
|
||||
cy.request({
|
||||
url: link.prop('href'),
|
||||
encoding: 'binary',
|
||||
}).then(
|
||||
(response) => {
|
||||
const fileName = 'subscriptioninvoice';
|
||||
const filePath = Cypress.config('downloadsFolder') + '/' + fileName + '.pdf';
|
||||
cy.writeFile(filePath, response.body, 'binary');
|
||||
cy.task('getPdfContent', filePath).then((data) => {
|
||||
const allLines = data.text.split('\n');
|
||||
const prodLine = allLines.filter((line) => line.includes('Trial period for Cloud Free'));
|
||||
expect(prodLine.length).to.be.equal(1);
|
||||
const amountLine = allLines.filter((line) => line.includes('Amount paid'));
|
||||
expect(amountLine[0].includes('$0.00')).to.be.equal(true);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('System Console - Payment Information section', () => {
|
||||
it('MM-T4167 check for the card details in payment info screen', () => {
|
||||
navigateToBillingScreen('#billing\\/payment_info', 'Payment Information');
|
||||
|
||||
// * Check for last four digit of card and Expire date
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-cardInfo').within(() => {
|
||||
cy.get('span').eq(0).should('have.text', 'visa ending in 4242');
|
||||
cy.get('span').eq(1).should('have.text', 'Expires 04/2024');
|
||||
});
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('have.text', 'testaddress');
|
||||
cy.get('div').eq(1).should('have.text', 'testcity, teststate, 4444');
|
||||
cy.get('div').eq(2).should('have.text', 'IO');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4169 Check for see billing link navigation in edit payment info', () => {
|
||||
navigateToBillingScreen('#billing\\/payment_info', 'Payment Information');
|
||||
|
||||
// # Click edit button
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-editButton').click();
|
||||
|
||||
// * Check for See how billing works navigation
|
||||
cy.contains('span', 'See how billing works').parent().then((link) => {
|
||||
const getHref = () => link.prop('href');
|
||||
cy.wrap({href: getHref}).invoke('href').should('contains', '/cloud-billing.html');
|
||||
cy.wrap(link).should('have.attr', 'target', '_new');
|
||||
cy.wrap(link).should('have.attr', 'rel', 'noopener noreferrer');
|
||||
cy.request(link.prop('href')).its('status').should('eq', 200);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4170 Edit payment info', () => {
|
||||
navigateToBillingScreen('#billing\\/payment_info', 'Payment Information');
|
||||
|
||||
cy.intercept('GET', '/api/v4/cloud/customer').as('customer');
|
||||
|
||||
// # Click edit button
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-editButton').click();
|
||||
|
||||
cy.wait('@customer');
|
||||
|
||||
cy.intercept('POST', '/api/v4/cloud/payment').as('payment');
|
||||
|
||||
cy.intercept('POST', '/api/v4/cloud/payment/confirm').as('confirm');
|
||||
|
||||
cy.intercept('GET', '/api/v4/cloud/subscription').as('subscribe');
|
||||
|
||||
// # Enter card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.mastercard.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.mastercard.expDate);
|
||||
cy.get('[name="cvc"]').clear().should('be.enabled').type(billing.mastercard.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test newname');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('Algeria{enter}');
|
||||
cy.get('#input_address').clear().type('testnewaddress');
|
||||
cy.get('#input_city').clear().type('testnewcity');
|
||||
cy.get('#input_state').clear().type('testnewstate');
|
||||
cy.get('#input_postalCode').clear().type('3333');
|
||||
|
||||
// # Click Save Credit Card button
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
cy.wait(['@payment', '@confirm']);
|
||||
|
||||
cy.wait('@subscribe');
|
||||
|
||||
// * Check for last four digit of card and Expire date
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-cardInfo').within(() => {
|
||||
cy.get('span').eq(0).should('have.text', 'mastercard ending in 4444');
|
||||
cy.get('span').eq(1).should('have.text', 'Expires 04/2024');
|
||||
});
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('have.text', 'testnewaddress');
|
||||
cy.get('div').eq(1).should('have.text', 'testnewcity, testnewstate, 3333');
|
||||
cy.get('div').eq(2).should('have.text', 'DZ');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4171 disable Save Credit Card button in edit payment info', () => {
|
||||
navigateToBillingScreen('#billing\\/payment_info', 'Payment Information');
|
||||
|
||||
cy.intercept('GET', '/api/v4/cloud/customer').as('customer');
|
||||
|
||||
// # Click edit button
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-editButton').click();
|
||||
|
||||
cy.wait('@customer');
|
||||
|
||||
// # Enter card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.mastercard.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.mastercard.expDate);
|
||||
cy.get('[name="cvc"]').clear().should('be.enabled').type(billing.mastercard.cvc);
|
||||
});
|
||||
cy.get('#input_name').should('be.enabled').invoke('val', '');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").should('be.enabled').type('Algeria{enter}');
|
||||
cy.get('#input_address').should('be.enabled').invoke('val', '');
|
||||
cy.get('#input_city').should('be.enabled').invoke('val', '');
|
||||
cy.get('#input_state').should('be.enabled').clear().type('testnewstate');
|
||||
cy.get('#input_postalCode').should('be.enabled').clear().type('3333');
|
||||
|
||||
// * Check for disabling of Save Credit Card button
|
||||
cy.get('#saveSetting').should('not.be.enabled');
|
||||
|
||||
cy.get('#input_name').should('be.enabled').clear().type('test newname');
|
||||
cy.get('#input_address').should('be.enabled').clear().type('testnewaddress');
|
||||
cy.get('#input_address').should('be.enabled').clear().type('testcity');
|
||||
|
||||
// * Check for enabling of Save Credit Card button
|
||||
cy.get('#saveSetting').should('be.enabled');
|
||||
});
|
||||
|
||||
it('MM-T4172 Cancelling the edit payment info', () => {
|
||||
navigateToBillingScreen('#billing\\/payment_info', 'Payment Information');
|
||||
|
||||
// # Click edit button
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-editButton').click();
|
||||
|
||||
// # Click edit button
|
||||
cy.get(' .admin-console__header .back').click();
|
||||
|
||||
// * Check for Payment info header
|
||||
cy.contains('.admin-console__header', 'Payment Information').should('be.visible');
|
||||
|
||||
// # Click edit button
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-editButton').click();
|
||||
|
||||
// # Enter card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.unionpay.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.unionpay.expDate);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(billing.unionpay.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test newname');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('Albania{enter}');
|
||||
cy.get('#input_address').clear().type('testcanceladdress');
|
||||
cy.get('#input_city').clear().type('testcancelcity');
|
||||
cy.get('#input_state').clear().type('testcanceltate');
|
||||
cy.get('#input_postalCode').clear().type('2222');
|
||||
|
||||
// # Click Cancel button
|
||||
cy.get('.cancel-button').click();
|
||||
|
||||
// * Check for last four digit of card and Expire date
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-cardInfo').within(() => {
|
||||
cy.get('span').eq(0).should('not.have.text', 'unionpay ending in 0005');
|
||||
cy.get('span').eq(1).should('not.have.text', 'Expires 12/2012');
|
||||
});
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('not.have.text', 'testcanceladdress');
|
||||
cy.get('div').eq(1).should('not.have.text', 'testcancelcity, testcanceltate, 2222');
|
||||
cy.get('div').eq(2).should('not.have.text', 'AL');
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('System Console - Company Information section', () => {
|
||||
let customerInfo = {};
|
||||
before(() => {
|
||||
cy.intercept('GET', '/api/v4/cloud/customer').as('customerInfo');
|
||||
navigateToBillingScreen('#billing\\/company_info', 'Company Information');
|
||||
cy.wait('@customerInfo').its('response.body').then((customerDetails) => {
|
||||
customerInfo = customerDetails;
|
||||
});
|
||||
});
|
||||
it('MM-T4162 Validate the Company address after subscription', () => {
|
||||
navigateToBillingScreen('#billing\\/company_info', 'Company Information');
|
||||
|
||||
// * Check for persisted company name
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-name').should('have.text', customerInfo.name);
|
||||
|
||||
// * Check for employee number
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-numEmployees > span').should('include.text', customerInfo.num_employees);
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('have.text', customerInfo.billing_address.line1);
|
||||
if (customerInfo.billing_address.line2 !== '') {
|
||||
cy.get('div').eq(1).should('have.text', `${customerInfo.billing_address.line2}`);
|
||||
cy.get('div').eq(2).should('have.text', `${customerInfo.billing_address.city}, ${customerInfo.billing_address.state}, ${customerInfo.billing_address.postal_code}`);
|
||||
cy.get('div').eq(3).should('have.text', customerInfo.billing_address.country);
|
||||
} else if (customerInfo.billing_address.line2 === '') {
|
||||
cy.get('div').eq(1).should('have.text', `${customerInfo.billing_address.city}, ${customerInfo.billing_address.state}, ${customerInfo.billing_address.postal_code}`);
|
||||
cy.get('div').eq(2).should('have.text', customerInfo.billing_address.country);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4165 Editing billing address of the company after subscription', () => {
|
||||
navigateToBillingScreen('#billing\\/company_info', 'Company Information');
|
||||
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// * Check name of the company
|
||||
cy.get('#input_companyName').should('have.value', customerInfo.name);
|
||||
|
||||
// * Check the no of employees
|
||||
cy.get('#input_numEmployees').should('have.value', customerInfo.num_employees);
|
||||
|
||||
// # Enter the company info
|
||||
cy.get('#input_companyName').clear().type('test company name');
|
||||
cy.get('#input_numEmployees').clear().type('1000');
|
||||
cy.findByText('Same as Billing Address').prev().should('be.checked').click().should('not.be.checked');
|
||||
cy.contains('legend', 'Country').parent().find('.icon-chevron-down').click();
|
||||
cy.contains('legend', 'Country').parent().find("input[type='text']").type('India{enter}');
|
||||
cy.get('#input_address').type('testcompanyaddress');
|
||||
cy.get('#input_address2').type('testcompanyaddress2');
|
||||
cy.get('#input_city').clear().type('testcompanycity');
|
||||
cy.get('#input_state').type('testcompnaystate');
|
||||
cy.get('#input_postalCode').type('5555');
|
||||
|
||||
// # Click Save Info button
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
// * Check name of the company after editing it
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-name').should('have.text', 'test company name');
|
||||
|
||||
// * Check for employee number
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-numEmployees > span').should('include.text', '1000');
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('have.text', 'testcompanyaddress');
|
||||
cy.get('div').eq(1).should('have.text', 'testcompanyaddress2');
|
||||
cy.get('div').eq(2).should('have.text', 'testcompanycity, testcompnaystate, 5555');
|
||||
cy.get('div').eq(3).should('have.text', 'IO');
|
||||
});
|
||||
|
||||
// # Click on edit company info button again
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// * Check for edited company Info
|
||||
cy.get('#input_companyName').should('have.value', 'test company name');
|
||||
cy.get('#input_numEmployees').should('have.value', '1000');
|
||||
cy.contains('British Indian Ocean Territory').should('exist');
|
||||
cy.get('#input_address').should('have.value', 'testcompanyaddress');
|
||||
cy.get('#input_address2').should('have.value', 'testcompanyaddress2');
|
||||
cy.get('#input_city').should('have.value', 'testcompanycity');
|
||||
cy.get('#input_state').should('have.value', 'testcompnaystate');
|
||||
cy.get('#input_postalCode').should('have.value', '5555');
|
||||
|
||||
// # Enter the company name and no of employees
|
||||
cy.get('#input_companyName').clear().type('test company');
|
||||
cy.get('#input_numEmployees').clear().type('100');
|
||||
|
||||
// # Click to uncheck the 'Same as Billing Address' checkbox
|
||||
cy.findByText('Same as Billing Address').prev().should('not.be.checked').click().should('be.checked');
|
||||
|
||||
// # Click Save Info button
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('have.text', customerInfo.billing_address.line1);
|
||||
if (customerInfo.billing_address.line2 !== '') {
|
||||
cy.get('div').eq(1).should('have.text', `${customerInfo.billing_address.line2}`);
|
||||
cy.get('div').eq(2).should('have.text', `${customerInfo.billing_address.city}, ${customerInfo.billing_address.state}, ${customerInfo.billing_address.postal_code}`);
|
||||
cy.get('div').eq(3).should('have.text', customerInfo.billing_address.country);
|
||||
} else if (customerInfo.billing_address.line2 === '') {
|
||||
cy.get('div').eq(1).should('have.text', `${customerInfo.billing_address.city}, ${customerInfo.billing_address.state}, ${customerInfo.billing_address.postal_code}`);
|
||||
cy.get('div').eq(2).should('have.text', customerInfo.billing_address.country);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// # navigate to billing screens
|
||||
const navigateToBillingScreen = (linkLocator, headerName) => {
|
||||
cy.get(linkLocator).scrollIntoView().should('be.visible').click();
|
||||
cy.contains('.admin-console__header', headerName).should('be.visible');
|
||||
};
|
||||
@@ -0,0 +1,193 @@
|
||||
// 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 @cloud_only @cloud_trial
|
||||
|
||||
function simulateSubscription() {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription/invoices', {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: 'in_1Lz8b0I67GP2qpb43kcuMyFP',
|
||||
number: '8D53267B-0006',
|
||||
create_at: 1667263490000,
|
||||
total: 65,
|
||||
tax: 0,
|
||||
status: 'open',
|
||||
description: '',
|
||||
period_start: 1664582400000,
|
||||
period_end: 1667260800000,
|
||||
subscription_id: 'sub_K0AxuWCDoDD9Qq',
|
||||
line_items: [
|
||||
{
|
||||
price_id: 'price_1KLUYiI67GP2qpb48DXFukcJ',
|
||||
total: 65,
|
||||
quantity: 0.06451612903225806,
|
||||
price_per_unit: 1000,
|
||||
description: 'Cloud Professional',
|
||||
},
|
||||
],
|
||||
current_product_name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'in_1LntnKI67GP2qpb4VObu3NgP',
|
||||
number: '8D53267B-0005',
|
||||
create_at: 1664584986000,
|
||||
total: 733,
|
||||
tax: 0,
|
||||
status: 'failed',
|
||||
description: '',
|
||||
period_start: 1661990400000,
|
||||
period_end: 1664582400000,
|
||||
subscription_id: 'sub_K0AxuWCDoDD9Qq',
|
||||
line_items: [
|
||||
{
|
||||
price_id: 'price_1KLUZ2I67GP2qpb45uTS89eb',
|
||||
total: 733,
|
||||
quantity: 0.7333333333333333,
|
||||
price_per_unit: 999,
|
||||
description: 'Cloud Professional',
|
||||
},
|
||||
],
|
||||
current_product_name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'in_1LntnKI67GP2qpb4VObu3NgV',
|
||||
number: '8D53267B-0005',
|
||||
create_at: 1664584986000,
|
||||
total: 733,
|
||||
tax: 0,
|
||||
status: 'paid',
|
||||
description: '',
|
||||
period_start: 1661990400000,
|
||||
period_end: 1664582400000,
|
||||
subscription_id: 'sub_K0AxuWCDoDD9Qq',
|
||||
line_items: [
|
||||
{
|
||||
price_id: 'price_1KLUZ2I67GP2qpb45uTS89eb',
|
||||
total: 733,
|
||||
quantity: 0.7333333333333333,
|
||||
price_per_unit: 999,
|
||||
description: 'Cloud Professional',
|
||||
},
|
||||
],
|
||||
current_product_name: 'Cloud Professional',
|
||||
},
|
||||
],
|
||||
});
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: 'sub_test1',
|
||||
is_free_trial: 'true',
|
||||
customer_id: '5zqhakmibpgyix9juiwwkpfnmr',
|
||||
product_id: 'prod_K0AxuWCDoDD9Qq',
|
||||
seats: 25,
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body:
|
||||
[
|
||||
{
|
||||
id: 'prod_LSBESgGXq9KlLj',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
},
|
||||
{
|
||||
id: 'prod_K0AxuWCDoDD9Qq',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'prod_Jh6tBLcgWWOOog',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
describe('System Console - Billing History', () => {
|
||||
before(() => {
|
||||
simulateSubscription();
|
||||
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
|
||||
// # Visit the billing history url
|
||||
cy.visit('admin_console/billing/billing_history');
|
||||
|
||||
// * Check for billing history header
|
||||
cy.contains('.admin-console__header', 'Billing History').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T3491_1 Invoice is shown in a table', () => {
|
||||
cy.get('tr.BillingHistory__table-row').as('tableRows');
|
||||
|
||||
// * Check the first row where payment is pending
|
||||
cy.get('@tableRows').eq(0).find('td').eq(0).should('have.text', '10/01/2022');
|
||||
cy.get('@tableRows').eq(0).find('td.BillingHistory__table-total').should('have.text', '$0.65');
|
||||
cy.get('@tableRows').eq(0).find('div.BillingHistory__paymentStatus').as('invoiceRecord').should('have.text', 'Pending');
|
||||
cy.get('@invoiceRecord').find('.icon-check-circle-outline').should('be.visible');
|
||||
|
||||
// * Check the first row where payment has failed
|
||||
cy.get('@tableRows').eq(1).find('td').eq(0).should('have.text', '09/01/2022');
|
||||
cy.get('@tableRows').eq(1).find('td.BillingHistory__table-total').should('have.text', '$7.33');
|
||||
cy.get('@tableRows').eq(1).find('div.BillingHistory__paymentStatus').as('invoiceRecord').should('have.text', 'Payment failed');
|
||||
cy.get('@invoiceRecord').find('.icon-alert-outline').should('be.visible');
|
||||
|
||||
// * Check the first row where payment was successfull
|
||||
cy.get('@tableRows').eq(2).find('td').eq(0).should('have.text', '09/01/2022');
|
||||
cy.get('@tableRows').eq(2).find('td.BillingHistory__table-total').should('have.text', '$7.33');
|
||||
cy.get('@tableRows').eq(2).find('div.BillingHistory__paymentStatus').as('invoiceRecord').should('have.text', 'Paid');
|
||||
cy.get('@invoiceRecord').find('.icon-check-circle-outline').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T3491_2 Validate the contents of downloaded PDF invoice', () => {
|
||||
cy.get('tr.BillingHistory__table-row').as('tableRows');
|
||||
|
||||
// * Check for default record's length in grid
|
||||
cy.get('@tableRows').should('have.length', 3);
|
||||
|
||||
// * Check the invoice line
|
||||
cy.get('@tableRows').eq(1).find('td').eq(4).find('a').should('have.attr', 'href').and('include', 'invoices/in_1LntnKI67GP2qpb4VObu3NgP/pdf');
|
||||
cy.get('@tableRows').eq(2).find('td').eq(4).find('a').should('have.attr', 'href').and('include', 'invoices/in_1LntnKI67GP2qpb4VObu3NgV/pdf');
|
||||
});
|
||||
});
|
||||
|
||||
describe('System Console - Empty Billing Screen', () => {
|
||||
before(() => {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription/invoices', {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
],
|
||||
});
|
||||
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
|
||||
// # Visit the billing history url
|
||||
cy.visit('admin_console/billing/billing_history');
|
||||
|
||||
// * Check for billing history header
|
||||
cy.contains('.admin-console__header', 'Billing History').should('be.visible');
|
||||
});
|
||||
|
||||
it('should show empty screen picture and link to /cloud-billing.html', () => {
|
||||
cy.get('.BillingHistory__cardHeaderText-bottom').should('have.text', 'All of your invoices will be shown here');
|
||||
cy.get('.BillingHistory__noHistory-link').should('have.text', 'See how billing works').should('have.attr', 'href').and('include', 'cloud/cloud-billing/cloud-billing.html');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,691 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] 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 @cloud_only @cloud_trial
|
||||
|
||||
function simulateSubscriptionWithLimitsUsage(subscription, withLimits = {}, postsUsed) {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: subscription,
|
||||
}).as('subscription');
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: 'prod_1',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
},
|
||||
{
|
||||
id: 'prod_2',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
recurring_interval: 'month',
|
||||
},
|
||||
{
|
||||
id: 'prod_3',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
recurring_interval: 'month',
|
||||
},
|
||||
],
|
||||
}).as('products');
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/limits', {
|
||||
statusCode: 200,
|
||||
body: withLimits,
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/usage/posts', {
|
||||
count: postsUsed,
|
||||
});
|
||||
}
|
||||
|
||||
function simulateSubscription(subscription, withLimits = true) {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: subscription,
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: 'prod_1',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
recurring_interval: 'month',
|
||||
name: 'Cloud Free',
|
||||
cross_sells_to: '',
|
||||
},
|
||||
{
|
||||
id: 'prod_2',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
recurring_interval: 'month',
|
||||
name: 'Cloud Professional',
|
||||
cross_sells_to: 'prod_4',
|
||||
},
|
||||
{
|
||||
id: 'prod_3',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
recurring_interval: 'month',
|
||||
name: 'Cloud Enterprise',
|
||||
cross_sells_to: '',
|
||||
},
|
||||
{
|
||||
id: 'prod_4',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 96,
|
||||
recurring_interval: 'year',
|
||||
name: 'Cloud Professional Yearly',
|
||||
cross_sells_to: 'prod_2',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (withLimits) {
|
||||
cy.intercept('GET', '**/api/v4/cloud/limits', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
messages: {
|
||||
history: 10000,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
describe('Pricing modal', () => {
|
||||
let urlL;
|
||||
let nonAdminUser;
|
||||
|
||||
it('should not show Upgrade button in global header for non admin users', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.apiInitSetup().then(({user, offTopicUrl: url}) => {
|
||||
urlL = url;
|
||||
nonAdminUser = user;
|
||||
simulateSubscription(subscription);
|
||||
cy.apiLogin(user);
|
||||
cy.visit(url);
|
||||
});
|
||||
|
||||
// * Check that Upgrade button does not show
|
||||
cy.get('#UpgradeButton').should('not.exist');
|
||||
});
|
||||
|
||||
it('should check for ability to request upgrades for non admin users on free plans', () => {
|
||||
cy.apiLogout();
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
|
||||
const messageHistoryLimit = 8000;
|
||||
const messagesUsed = 4000;
|
||||
|
||||
const limits = {
|
||||
messages: {
|
||||
history: messageHistoryLimit,
|
||||
},
|
||||
teams: {
|
||||
active: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
};
|
||||
|
||||
simulateSubscriptionWithLimitsUsage(subscription, limits, messagesUsed);
|
||||
cy.apiLogin(nonAdminUser);
|
||||
cy.visit(urlL);
|
||||
|
||||
cy.get('#product_switch_menu').click();
|
||||
cy.get('#view_plans_cta').should('be.visible').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').find('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that on professsional card there a button for non admin user to request upgrade
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('be.enabled').should('have.text', 'Request admin to upgrade');
|
||||
|
||||
// * Check that on enterprise card there a button for non admin user to request upgrade
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#enterprise > .bottom > .bottom_container').find('#enterprise_action').should('be.enabled').should('have.text', 'Request admin to upgrade');
|
||||
});
|
||||
|
||||
it('should check for ability to request upgrades to enterprise for non admin users on professional monthly plans', () => {
|
||||
cy.apiLogout();
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
|
||||
const messageHistoryLimit = 8000;
|
||||
const messagesUsed = 4000;
|
||||
|
||||
const limits = {
|
||||
messages: {
|
||||
history: messageHistoryLimit,
|
||||
},
|
||||
teams: {
|
||||
active: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
};
|
||||
|
||||
simulateSubscriptionWithLimitsUsage(subscription, limits, messagesUsed);
|
||||
cy.apiLogin(nonAdminUser);
|
||||
cy.visit(urlL);
|
||||
|
||||
cy.get('#product_switch_menu').click();
|
||||
cy.get('#view_plans_cta').should('be.visible').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').find('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that on professsional card there a button for non admin user to request upgrade and it's disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('.planLabel').should('have.text', 'CURRENT PLAN');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('have.text', 'Request admin to upgrade').should('be.not.enabled');
|
||||
|
||||
// * Check that on enterprise card there a button for non admin user to request upgrade
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#enterprise > .bottom > .bottom_container').find('#enterprise_action').should('be.enabled').should('have.text', 'Request admin to upgrade');
|
||||
});
|
||||
|
||||
it('should not allow any requests for upgrades when on enterprise', () => {
|
||||
cy.apiLogout();
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_3',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
|
||||
const messageHistoryLimit = 8000;
|
||||
const messagesUsed = 4000;
|
||||
|
||||
const limits = {
|
||||
messages: {
|
||||
history: messageHistoryLimit,
|
||||
},
|
||||
teams: {
|
||||
active: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
};
|
||||
|
||||
simulateSubscriptionWithLimitsUsage(subscription, limits, messagesUsed);
|
||||
cy.apiLogin(nonAdminUser);
|
||||
cy.visit(urlL);
|
||||
|
||||
cy.get('#product_switch_menu').click();
|
||||
cy.get('#view_plans_cta').should('be.visible').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').find('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that on professsional card there a button for non admin user to request upgrade and it's disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('have.text', 'Request admin to upgrade').should('be.not.enabled');
|
||||
|
||||
// * Check that on enterprise card there a button for non admin user to request upgrade
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('.planLabel').should('have.text', 'CURRENT PLAN');
|
||||
cy.get('#enterprise > .bottom > .bottom_container').find('#enterprise_action').should('have.text', 'Request admin to upgrade').should('be.not.enabled');
|
||||
});
|
||||
|
||||
it('should show Upgrade button in global header for admin users and free sku', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// * Check that Upgrade button shows for admins
|
||||
cy.get('#UpgradeButton').should('exist');
|
||||
|
||||
// * Check for Upgrade button tooltip
|
||||
cy.get('#UpgradeButton').trigger('mouseover').then(() => {
|
||||
cy.get('#upgrade_button_tooltip').should('be.visible').contains('Only visible to system admins');
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Upgrade button in global header for admin users and enterprise trial sku', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_3',
|
||||
is_free_trial: 'true',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// * Check that Upgrade button shows for admins
|
||||
cy.get('#UpgradeButton').should('exist');
|
||||
});
|
||||
|
||||
it('should open pricing modal when Upgrade button clicked while in free sku', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').find('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
|
||||
// * Check that professsional card Upgrade button opens purchase modal
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('be.enabled').should('have.text', 'Upgrade').click();
|
||||
cy.get('.PurchaseModal').should('exist');
|
||||
|
||||
// * Check that the upgrade button tooltip does not exist on the purchase modal
|
||||
cy.get('#upgrade_button_tooltip').should('not.exist');
|
||||
|
||||
// * Close PurchaseModal
|
||||
cy.get('#closeIcon').click();
|
||||
|
||||
// # Open pricing modal again
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Check for contact sales CTA
|
||||
cy.get('#contact_sales_quote').contains('Contact Sales');
|
||||
|
||||
// * Check that enterprise card action button shows Try free for 30 days
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#start_cloud_trial_btn').contains('Try free for 30 days');
|
||||
});
|
||||
|
||||
it('should open pricing modal when Upgrade button clicked while in enterprise trial sku', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_3',
|
||||
is_free_trial: 'true',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free Downgrade card button exists
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').contains('Downgrade');
|
||||
|
||||
// * Check that professsional card Upgrade button is not disabled while on enterprise trial
|
||||
cy.get('#professional > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#professional_action').should('not.be.disabled');
|
||||
|
||||
// * Check that enterprise card action button is disabled
|
||||
cy.get('#enterprise > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#start_cloud_trial_btn').contains('Try free for 30 days');
|
||||
cy.get('#enterprise > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#start_cloud_trial_btn').should('be.disabled');
|
||||
});
|
||||
|
||||
it('should open pricing modal when Upgrade button clicked while in post trial free sku', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 100000000, // signifies that this subscription has trialled before
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
|
||||
// * Check that professsional card Upgrade button opens purchase modal
|
||||
cy.get('#professional > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#professional_action').click();
|
||||
cy.get('.PricingModal__body').should('exist');
|
||||
|
||||
// * Close PurchaseModal
|
||||
cy.get('button.close-x').click();
|
||||
|
||||
// * Contact Sales button shows and Contact sales for quote CTA should not show
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
cy.get('#contact_sales_quote').should('not.exist');
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#enterprise > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#enterprise_action').contains('Contact Sales');
|
||||
});
|
||||
|
||||
it('should open pricing modal when Switch to Yearly is button clicked while in monthly professional', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2', //professional monthly
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
|
||||
// * Check that professsional card Switch to Yearly button opens purchase modal
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('.planLabel').should('have.text', 'CURRENTLY ON MONTHLY BILLING');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('be.enabled').should('have.text', 'Switch to annual billing').click();
|
||||
cy.get('.PurchaseModal').should('exist');
|
||||
});
|
||||
|
||||
it('should have Upgrade button disabled while in yearly professional', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_4', //professional yearly
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
|
||||
// * Check that professsional card Switch to Yearly button opens purchase modal
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('.planLabel').should('have.text', 'CURRENT PLAN');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('not.be.enabled').should('have.text', 'Upgrade');
|
||||
});
|
||||
|
||||
it('should open cloud limits modal when free disclaimer CTA is clicked', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 100000000, // signifies that this subscription has trialled before
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Open cloud limits modal
|
||||
cy.get('#free_plan_data_restrictions_cta').contains('This plan has data restrictions.');
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free_plan_data_restrictions_cta').click();
|
||||
|
||||
cy.get('.CloudUsageModal').should('exist');
|
||||
cy.get('.CloudUsageModal').contains('Cloud Free limits');
|
||||
});
|
||||
|
||||
it('should not show free disclaimer CTA when on legacy starter product that has no limits', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 100000000, // signifies that this subscription has trialled before
|
||||
};
|
||||
cy.simulateSubscription(subscription, false);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * CTA should not show when there are no limits
|
||||
cy.get('#free_plan_data_restrictions_cta').should('not.exist');
|
||||
});
|
||||
|
||||
it('should allow downgrades from professional plans', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').should('not.be.disabled').contains('Downgrade');
|
||||
});
|
||||
|
||||
it('should not allow downgrades from enterprise trial', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_3',
|
||||
is_free_trial: 'true',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
});
|
||||
|
||||
it('should not allow downgrades from enterprise plans', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_3',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
|
||||
// * Check that professsional card Upgrade button is disabled while on non trial enterprise
|
||||
cy.get('#professional > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#professional_action').should('be.disabled');
|
||||
|
||||
// * Check that Trial button is disabled on enterprise trial
|
||||
cy.get('#enterprise > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#start_cloud_trial_btn').should('be.disabled');
|
||||
});
|
||||
|
||||
it('should not allow downgrades from yearly plans', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_4',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
cy.get('#pricingModal').get('#free').get('#free_action').should('not.be.disabled').contains('Contact Support');
|
||||
});
|
||||
|
||||
it('should not allow starting a trial from professional plans', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that Trial button is disabled on enterprise trial
|
||||
cy.get('#enterprise > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#start_cloud_trial_btn').should('be.disabled');
|
||||
});
|
||||
|
||||
it('Should display downgrade modal when downgrading from monthly professional to free', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
cy.wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Click the free action (downgrade).
|
||||
cy.get('#free').should('exist');
|
||||
cy.get('#free_action').should('be.enabled').click();
|
||||
|
||||
// * Check that the downgrade modal has appeard.
|
||||
cy.get('div.DowngradeTeamRemovalModal__body').should('exist');
|
||||
});
|
||||
|
||||
it('Should display a "Contact Support" CTA for downgrading when the current subscription is yearly and not on starter', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_4',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// * Click the free action (downgrade).
|
||||
cy.get('#free').should('exist').contains('Contact Support');
|
||||
cy.get('#free_action').should('be.enabled').click();
|
||||
});
|
||||
|
||||
it('Should not display a "Contact Support" CTA for downgrading when the current subscription is monthly and not on starter', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// # The free action button should not be disabled and contain the text "Downgrade".
|
||||
cy.get('#free').should('exist').contains('Downgrade');
|
||||
cy.get('#free_action').should('not.be.disabled');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,217 @@
|
||||
// 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 @cloud_only @cloud_trial
|
||||
|
||||
import {getRandomLetter} from '../../../../../utils/index';
|
||||
|
||||
describe('System Console - Company Information section', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
|
||||
// # Visit Company Information page
|
||||
cy.visit('/admin_console/billing/company_info');
|
||||
|
||||
// * Check for the Company Information header
|
||||
cy.contains('.admin-console__header', 'Company Information').should('be.visible');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Click on cancel button if exist
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.find('.cancel-button').length > 0) {
|
||||
cy.get('.cancel-button').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4164 Save Info button should not be enabled if any one of the mandatory field is filled with invalid data', () => {
|
||||
const companyName = getRandomLetter(30);
|
||||
|
||||
// # Click on Add Company Information button
|
||||
cy.contains('span', 'Company Information').parent().click();
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// # Enter valid company information
|
||||
cy.get('#input_companyName').clear().type(companyName);
|
||||
cy.get('#input_numEmployees').clear().type('10');
|
||||
cy.get('#DropdownInput_country_dropdown').click();
|
||||
cy.get("#DropdownInput_country_dropdown .DropDown__input > input[type='text']").type('India{enter}');
|
||||
cy.get('#input_address').clear().type('test address');
|
||||
cy.get('#input_address2').clear().type('test2');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('#input_state').clear().type('test');
|
||||
cy.get('#input_postalCode').clear().type('44455');
|
||||
|
||||
// * Check save button is enabled
|
||||
cy.get('#saveSetting').should('be.enabled');
|
||||
|
||||
// # Clear postal code
|
||||
cy.get('#input_postalCode').clear();
|
||||
|
||||
// * Check save button is disabled
|
||||
cy.get('#saveSetting').should('be.disabled');
|
||||
|
||||
// # Type valid postal code
|
||||
cy.get('#input_postalCode').type('44456');
|
||||
|
||||
// * Check save button is enabled
|
||||
cy.get('#saveSetting').should('be.enabled');
|
||||
|
||||
// # Clear city
|
||||
cy.get('#input_city').clear();
|
||||
|
||||
// * Check save button is disabled
|
||||
cy.get('#saveSetting').should('be.disabled');
|
||||
|
||||
// # Type valid city
|
||||
cy.get('#input_city').type('testcity');
|
||||
|
||||
// * Check save button is enabled
|
||||
cy.get('#saveSetting').should('be.enabled');
|
||||
|
||||
// # Clear company name
|
||||
cy.get('#input_companyName').clear();
|
||||
|
||||
// * Check save button is disabled
|
||||
cy.get('#saveSetting').should('be.disabled');
|
||||
});
|
||||
|
||||
it('MM-T4161 Adding the Company Information', () => {
|
||||
const companyName = getRandomLetter(30);
|
||||
|
||||
// # Click on Add Company Information button
|
||||
cy.contains('span', 'Company Information').parent().click();
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// # Enter company information
|
||||
cy.get('#input_companyName').clear().type(companyName);
|
||||
cy.get('#input_numEmployees').clear().type('10');
|
||||
cy.get('#DropdownInput_country_dropdown').click();
|
||||
cy.get("#DropdownInput_country_dropdown .DropDown__input > input[type='text']").type('India{enter}');
|
||||
cy.get('#input_address').clear().type('Add test address');
|
||||
cy.get('#input_address2').clear().type('Add test address2');
|
||||
cy.get('#input_city').clear().type('Addtestcity');
|
||||
cy.get('#input_state').clear().type('Addteststate');
|
||||
cy.get('#input_postalCode').clear().type('560089');
|
||||
|
||||
// # Click on Save Info button
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
// * Check for persisted company name
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-name').should('have.text', companyName);
|
||||
|
||||
// * Check for employee number
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-numEmployees > span').should('include.text', '10');
|
||||
|
||||
// * Check for country
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(3).should('have.text', 'British Indian Ocean Territory');
|
||||
|
||||
// * Check for city, state and postal code
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(2).should('have.text', 'Addtestcity, Addteststate, 560089');
|
||||
|
||||
// * Check for address 2
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(1).should('have.text', 'Add test address2');
|
||||
|
||||
// * Check for address 1
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(0).should('have.text', 'Add test address');
|
||||
});
|
||||
|
||||
it('MM-T4165 Editing the Company Information', () => {
|
||||
const companyName = getRandomLetter(30);
|
||||
|
||||
// # Click on edit Company Information button
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// # Enter company information
|
||||
cy.get('#input_companyName').clear().type(companyName);
|
||||
cy.get('#input_numEmployees').clear().type('10');
|
||||
cy.get('#DropdownInput_country_dropdown').click();
|
||||
cy.get("#DropdownInput_country_dropdown .DropDown__input > input[type='text']").type('India{enter}');
|
||||
cy.get('#input_address').clear().type('test address');
|
||||
cy.get('#input_address2').clear().type('test2');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('#input_state').clear().type('test');
|
||||
cy.get('#input_postalCode').clear().type('44455');
|
||||
|
||||
// # Click on Save Info button
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
// * Check for persisted company name
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-name').should('have.text', companyName);
|
||||
|
||||
// * Check for employee number
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-numEmployees > span').should('include.text', '10');
|
||||
|
||||
// * Check for country
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(3).should('have.text', 'British Indian Ocean Territory');
|
||||
|
||||
// * Check for city, state and postal code
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(2).should('have.text', 'testcity, test, 44455');
|
||||
|
||||
// * Check for address 2
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(1).should('have.text', 'test2');
|
||||
|
||||
// * Check for address 1
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(0).should('have.text', 'test address');
|
||||
});
|
||||
|
||||
it('MM-T4166 Cancelling of editing of company information details', () => {
|
||||
// # Click Add edit Information button
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// # Click back button of Edit Company Information
|
||||
cy.contains('span', 'Edit Company Information').prev().click();
|
||||
|
||||
// * Check for back functionality using back button of edit company information screen
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').should('be.visible');
|
||||
|
||||
// # Click Add Company Information button
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// # Enter company information
|
||||
cy.get('#input_companyName').clear().type('CancelcompanyName');
|
||||
cy.get('#input_numEmployees').clear().type('11');
|
||||
cy.get('#DropdownInput_country_dropdown').click();
|
||||
cy.get("#DropdownInput_country_dropdown .DropDown__input > input[type='text']").type('Albania{enter}');
|
||||
cy.get('#input_address').clear().type('canceltest address');
|
||||
cy.get('#input_address2').clear().type('canceltest2');
|
||||
cy.get('#input_city').clear().type('canceltestcity');
|
||||
cy.get('#input_state').clear().type('canceltest');
|
||||
cy.get('#input_postalCode').clear().type('560072');
|
||||
|
||||
// # Click cancel button
|
||||
cy.get('.cancel-button').click();
|
||||
|
||||
// * Check for visibility of Add Company Information button
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').should('be.visible');
|
||||
|
||||
// * Check for persisted company name
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-name').should('not.have.text', 'CancelcompanyName');
|
||||
|
||||
// * Check for employee number
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-numEmployees > span').should('not.include.text', '11');
|
||||
|
||||
// * Check for country
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(3).should('not.have.text', 'Albania');
|
||||
|
||||
// * Check for city, state and postal code
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(2).should('not.have.text', 'canceltestcity, canceltest, 560072');
|
||||
|
||||
// * Check for address 2
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(1).should('not.have.text', 'canceltest2');
|
||||
|
||||
// * Check for address 1
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(0).should('not.have.text', 'canceltest address');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
// 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 @cloud_only @cloud_trial
|
||||
describe('Feedback modal', () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
});
|
||||
|
||||
it('Should display feedback modal when downgrading to cloud free', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
|
||||
// # Intercepts the teams request to avoid team selection modal.
|
||||
cy.intercept('**/api/v4/usage/teams', {statusCode: 200, body: {active: 1, cloud_archived: 0}}).as('teams');
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
cy.wait('@teams');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// * Free action (downgrade) should exist.
|
||||
// # Click it.
|
||||
cy.get('#free_action').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
|
||||
// * Downgrade feedback should exist.
|
||||
cy.findByText('Please share your reason for downgrading').should('exist');
|
||||
|
||||
// * The submit (Downgrade) button should be disabled.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.disabled');
|
||||
|
||||
// # Click the free action (downgrade).
|
||||
cy.findByTestId('Exploring other solutions').click();
|
||||
|
||||
// # Click the submit for the downgrade feedback.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
|
||||
// * The downgrade modal should exist.
|
||||
cy.findByText('Downgrading your workspace').should('exist');
|
||||
});
|
||||
|
||||
it('Downgrade Feedback modal submit button should be disabled if no option is selected', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
|
||||
// # Intercepts the teams request to avoid team selection modal.
|
||||
cy.intercept('**/api/v4/usage/teams', {statusCode: 200, body: {active: 1, cloud_archived: 0}}).as('teams');
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
cy.wait('@teams');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// * Free action (downgrade) should exist.
|
||||
// # Click it.
|
||||
cy.get('#free_action').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
|
||||
// * Downgrade feedback should exist.
|
||||
cy.findByText('Please share your reason for downgrading').should('exist');
|
||||
|
||||
// * The submit (Downgrade) button should be disabled.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.disabled');
|
||||
});
|
||||
|
||||
it('Downgrade Feedback modal shows error state when "other" option is selected but not comments have been provided', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
|
||||
// # Intercepts the teams request to avoid team selection modal.
|
||||
cy.intercept('**/api/v4/usage/teams', {statusCode: 200, body: {active: 1, cloud_archived: 0}}).as('teams');
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
cy.wait('@teams');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// * Free action (downgrade) should exist.
|
||||
// # Click it.
|
||||
cy.get('#free_action').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
|
||||
// * Downgrade feedback should exist.
|
||||
cy.findByText('Please share your reason for downgrading').should('exist');
|
||||
|
||||
// * The submit (Downgrade) button should be disabled.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.disabled');
|
||||
|
||||
// # Click the other option, requiring extra comments.
|
||||
cy.get('input[value="Other"]').click();
|
||||
|
||||
// # Fill in the comments.
|
||||
cy.findByTestId('FeedbackModal__TextInput').type('Do not need it anymore.');
|
||||
|
||||
// * The submit (Downgrade) button should be enabled.
|
||||
// # Click it.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
});
|
||||
|
||||
it('Downgrade Feedback modal appears and downgrades after team selection modal is submitted', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
|
||||
// # Intercepts the teams request to avoid team selection modal.
|
||||
cy.intercept('**/api/v4/usage/teams', {statusCode: 200, body: {active: 2, cloud_archived: 0}}).as('teams');
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
cy.wait('@teams');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// * Free action (downgrade) should exist.
|
||||
// # Click it.
|
||||
cy.get('#free_action').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
|
||||
// * Team selection modal should exist.
|
||||
cy.findByText('Confirm Plan Downgrade').should('exist');
|
||||
|
||||
// The test-id is the team id, can't find it in any network requests for interception.
|
||||
// # Click the first team.
|
||||
cy.get('input[name="deleteTeamRadioGroup"]').first().click();
|
||||
|
||||
// Can't seem to get the button via findByText, use css selector instead.
|
||||
cy.get('.DowngradeTeamRemovalModal__buttons > .btn-primary').should('exist').should('be.enabled').click();
|
||||
|
||||
// * Downgrade feedback should exist.
|
||||
cy.findByText('Please share your reason for downgrading').should('exist');
|
||||
|
||||
// * The submit (Downgrade) button should be disabled.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.disabled');
|
||||
|
||||
// # Click the other option, requiring extra comments.
|
||||
cy.get('input[value="Other"]').click();
|
||||
|
||||
// # Fill in the comments.
|
||||
cy.findByTestId('FeedbackModal__TextInput').type('Do not need it anymore.');
|
||||
|
||||
// * The submit (Downgrade) button should be enabled.
|
||||
// # Click it.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,527 @@
|
||||
// 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 @cloud_only @cloud_trial
|
||||
|
||||
import {getAdminAccount} from '../../../../../support/env';
|
||||
|
||||
const admin = getAdminAccount();
|
||||
|
||||
interface Subscription{
|
||||
id: string;
|
||||
product_id: string;
|
||||
is_free_trial: string;
|
||||
trial_end_at: number;
|
||||
}
|
||||
|
||||
interface Limits {
|
||||
messages?: { history: number };
|
||||
teams?: { active: number; teamsLoaded: boolean };
|
||||
files?: { total_storage: number };
|
||||
}
|
||||
|
||||
function simulateFilesLimitReached(fileStorageUsageBytes: number) {
|
||||
cy.intercept('GET', '**/api/v4/usage/storage', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
bytes: fileStorageUsageBytes + 1, // increase workspace usage
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/limits', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
files: {
|
||||
total_storage: fileStorageUsageBytes,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Move to utils
|
||||
function simulateSubscription(subscription: Subscription, withLimits = {}) {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: subscription,
|
||||
}).as('subscription');
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: 'prod_1',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
},
|
||||
{
|
||||
id: 'prod_2',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'prod_3',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
},
|
||||
],
|
||||
}).as('products');
|
||||
|
||||
if (withLimits) {
|
||||
cy.intercept('GET', '**/api/v4/cloud/limits', {
|
||||
statusCode: 200,
|
||||
body: withLimits,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createUsersProcess(team: { id: string }, channel: { id: string }, times: number) {
|
||||
const users = [];
|
||||
for (let i = 0; i < times; i++) {
|
||||
cy.apiCreateUser({prefix: 'other'}).then(({user}) => {
|
||||
users.push(user);
|
||||
cy.apiAddUserToTeam(team.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
function userGroupsNotification() {
|
||||
cy.get('#product_switch_menu').click().then((() => {
|
||||
cy.get('#mattermost_feature_custom_user_groups-restricted-indicator').click();
|
||||
}));
|
||||
|
||||
cy.get('#FeatureRestrictedModal').should('exist');
|
||||
|
||||
cy.get('#button-plans').click();
|
||||
|
||||
cy.get('.close').click();
|
||||
}
|
||||
|
||||
function creatNewTeamNotification() {
|
||||
cy.get('.test-team-header').click().then(() => {
|
||||
cy.get('#mattermost_feature_create_multiple_teams-restricted-indicator').click();
|
||||
});
|
||||
cy.get('#FeatureRestrictedModal').should('exist');
|
||||
cy.get('#button-plans').as('notifyButton').should('have.text', 'Notify admin').click();
|
||||
cy.get('@notifyButton').should('have.text', 'Admin notified!');
|
||||
cy.get('@notifyButton').click();
|
||||
cy.get('@notifyButton').should('have.text', 'Already notified!').should('be.disabled');
|
||||
cy.get('.close').click();
|
||||
}
|
||||
|
||||
function createMessageLimitNotification() {
|
||||
cy.get('#product_switch_menu').click().then((() => {
|
||||
cy.get('#notify_admin_cta').click();
|
||||
}));
|
||||
}
|
||||
|
||||
function createFilesNotificationForProfessionalFeatures() {
|
||||
cy.get('#product_switch_menu').click().then((() => {
|
||||
cy.findByText('Notify admin').should('be.visible').click();
|
||||
cy.findByText('Admin notified!').should('be.visible').click();
|
||||
cy.findByText('Already notified!').should('be.visible').should('be.disabled');
|
||||
}));
|
||||
}
|
||||
|
||||
function createTrialNotificationForProfessionalFeatures() {
|
||||
cy.get('#product_switch_menu').click().then((() => {
|
||||
cy.get('#view_plans_cta').click();
|
||||
cy.get('#pricingModal').get('#professional').within(() => {
|
||||
cy.get('#notify_admin_cta').click();
|
||||
});
|
||||
cy.get('#closeIcon').click();
|
||||
}));
|
||||
}
|
||||
|
||||
function createTrialNotificationForEnterpriseFeatures() {
|
||||
cy.get('#product_switch_menu').click().then((() => {
|
||||
cy.get('#view_plans_cta').click();
|
||||
cy.get('#pricingModal').get('#enterprise').within(() => {
|
||||
cy.get('#notify_admin_cta').click();
|
||||
});
|
||||
cy.get('#closeIcon').click();
|
||||
}));
|
||||
}
|
||||
|
||||
function triggerNotifications(url, trial = false, _failOnStatusCode = true) {
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'POST',
|
||||
url: '/api/v4/users/trigger-notify-admin-posts',
|
||||
body: {
|
||||
trial_notification: trial,
|
||||
},
|
||||
failOnStatusCode: _failOnStatusCode,
|
||||
});
|
||||
});
|
||||
|
||||
if (url) {
|
||||
cy.visit(url);
|
||||
}
|
||||
}
|
||||
|
||||
function mapFeatureIdToId(id: string) {
|
||||
switch (id) {
|
||||
case 'mattermost.feature.custom_user_groups':
|
||||
return 'Custom User groups';
|
||||
case 'mattermost.feature.create_multiple_teams':
|
||||
return 'Create Multiple Teams';
|
||||
case 'mattermost.feature.unlimited_messages':
|
||||
return 'Unlimited Messages';
|
||||
case 'mattermost.feature.unlimited_file_storage':
|
||||
return 'Unlimited File Storage';
|
||||
case 'mattermost.feature.all_professional':
|
||||
return 'All Professional features';
|
||||
case 'mattermost.feature.all_enterprise':
|
||||
return 'All Enterprise features';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
function deletePost() {
|
||||
// # Delete system-bot message
|
||||
cy.get('@postId').then((postId) => {
|
||||
cy.externalRequest({user: admin, method: 'DELETE', path: `posts/${postId}`});
|
||||
});
|
||||
}
|
||||
function assertNotification(featureId, minimumPlan, totalRequests, requestsCount, teamName, trial = false) {
|
||||
// # Open system-bot and admin DM
|
||||
cy.visit(`/${teamName}/messages/@system-bot`);
|
||||
|
||||
// * Check for the post from the system-bot
|
||||
cy.getLastPostId().as('postId').then((postId) => {
|
||||
if (trial) {
|
||||
cy.get(`#${postId}_message`).then(() => {
|
||||
cy.get('a').contains('Enterprise trial');
|
||||
});
|
||||
} else {
|
||||
cy.get(`#${postId}_message`).contains(`${totalRequests} members of the workspace have requested a workspace upgrade for:`);
|
||||
}
|
||||
|
||||
cy.get(`#${featureId}-title`.replaceAll('.', '_')).contains(mapFeatureIdToId(featureId));
|
||||
|
||||
if (requestsCount >= 5) {
|
||||
cy.get(`#${featureId}-subtitle`.replaceAll('.', '_')).contains(`${requestsCount} members requested access to this feature`);
|
||||
cy.get(`#${postId}_at_sum_of_members_mention`).click().then(() => {
|
||||
cy.get('#notificationFromMembersModal');
|
||||
cy.get('#invitation_modal_title').contains(`Members that requested ${mapFeatureIdToId(featureId)}`).then(() => {
|
||||
cy.get('.close').click();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (minimumPlan === 'Professional plan') {
|
||||
cy.get(`#${featureId}-title`.replaceAll('.', '_')).within(() => {
|
||||
cy.get('#at_plan_mention').click();
|
||||
});
|
||||
|
||||
cy.get('.PricingModal__header').should('exist').then(() => {
|
||||
cy.get('#closeIcon').click();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function assertUpgradeMessageButton(onlyProfessionalFeatures?: boolean) {
|
||||
cy.get('#view_upgrade_options').contains('View upgrade options');
|
||||
cy.get('#view_upgrade_options').click();
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
if (onlyProfessionalFeatures) {
|
||||
cy.get('.close-x').click();
|
||||
cy.get('#upgrade_to_professional').contains('Upgrade to Professional');
|
||||
cy.get('.PurchaseModal').should('exist');
|
||||
}
|
||||
}
|
||||
|
||||
function assertTrialMessageButton() {
|
||||
cy.get('#learn_more_about_trial').contains('Learn more about trial');
|
||||
cy.get('#learn_more_about_trial').click();
|
||||
cy.get('.LearnMoreTrialModal').should('exist').then(() => {
|
||||
cy.get('.close').click();
|
||||
});
|
||||
|
||||
cy.findByText('View upgrade options').click();
|
||||
cy.get('#pricingModal').should('exist');
|
||||
}
|
||||
|
||||
function testTrialNotifications(subscription, limits) {
|
||||
let myTeam;
|
||||
let myChannel;
|
||||
let myUrl: string;
|
||||
let myAllProfessionalUsers = [];
|
||||
let myAllEnterpriseUsers = [];
|
||||
const ALL_PROFESSIONAL_FEATURES_REQUESTS = 5;
|
||||
const ALL_ENTERPRISE_FEATURES_REQUESTS = 3;
|
||||
const TOTAL = 8;
|
||||
|
||||
// # Login as an admin and create test users that will click the different notification ctas
|
||||
cy.apiInitSetup().then(({team, channel, offTopicUrl: url}) => {
|
||||
myTeam = team;
|
||||
myChannel = channel;
|
||||
myUrl = url;
|
||||
|
||||
// # Create non admin users
|
||||
myAllProfessionalUsers = createUsersProcess(myTeam, myChannel, ALL_PROFESSIONAL_FEATURES_REQUESTS);
|
||||
myAllEnterpriseUsers = createUsersProcess(myTeam, myChannel, ALL_ENTERPRISE_FEATURES_REQUESTS);
|
||||
});
|
||||
|
||||
// # Click notify admin to trial on pricing modal
|
||||
cy.then(() => {
|
||||
myAllProfessionalUsers.forEach((user) => {
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
cy.wait(['@subscription', '@products']);
|
||||
createTrialNotificationForProfessionalFeatures();
|
||||
});
|
||||
});
|
||||
|
||||
// # Click notify admin to trial on pricing modal
|
||||
cy.then(() => {
|
||||
myAllEnterpriseUsers.forEach((user) => {
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
cy.wait(['@subscription', '@products']);
|
||||
createTrialNotificationForEnterpriseFeatures();
|
||||
});
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
// # Manually trigger saved notifications
|
||||
triggerNotifications(myUrl, true);
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
assertNotification('mattermost.feature.all_professional', 'Professional plan', TOTAL, ALL_PROFESSIONAL_FEATURES_REQUESTS, myTeam.name, true);
|
||||
assertNotification('mattermost.feature.all_enterprise', 'Enterprise plan', TOTAL, ALL_ENTERPRISE_FEATURES_REQUESTS, myTeam.name, true);
|
||||
assertTrialMessageButton();
|
||||
});
|
||||
|
||||
deletePost();
|
||||
}
|
||||
|
||||
function testFilesNotifications(subscription: Subscription, limits: Limits) {
|
||||
let myTeam;
|
||||
let myChannel;
|
||||
let myUrl;
|
||||
let myAllProfessionalUsers = [];
|
||||
const ALL_PROFESSIONAL_FEATURES_REQUESTS = 5;
|
||||
const TOTAL = 5;
|
||||
|
||||
// # Login as an admin and create test users that will click the different notification ctas
|
||||
cy.apiInitSetup().then(({team, channel, offTopicUrl: url}) => {
|
||||
myTeam = team;
|
||||
myChannel = channel;
|
||||
myUrl = url;
|
||||
|
||||
// # Create non admin users
|
||||
myAllProfessionalUsers = createUsersProcess(myTeam, myChannel, ALL_PROFESSIONAL_FEATURES_REQUESTS);
|
||||
});
|
||||
|
||||
// # Click notify admin to trial on pricing modal
|
||||
cy.then(() => {
|
||||
myAllProfessionalUsers.forEach((user) => {
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
cy.wait(['@subscription', '@products']);
|
||||
createFilesNotificationForProfessionalFeatures();
|
||||
});
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
// # Manually trigger saved notifications
|
||||
triggerNotifications(myUrl, false);
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
assertNotification('mattermost.feature.unlimited_file_storage', 'Professional plan', TOTAL, ALL_PROFESSIONAL_FEATURES_REQUESTS, myTeam.name);
|
||||
assertUpgradeMessageButton();
|
||||
});
|
||||
deletePost();
|
||||
}
|
||||
|
||||
function testUpgradeNotifications(subscription, limits) {
|
||||
let myTeam;
|
||||
let myChannel;
|
||||
let myUrl: string;
|
||||
let myMessageLimitUsers = [];
|
||||
let myUnlimitedTeamsUsers = [];
|
||||
let myUserGroupsUsers = [];
|
||||
|
||||
const CREATE_MULTIPLE_TEAMS_USERS = 2;
|
||||
const UNLIMITED_MESSAGES_USERS = 3;
|
||||
const CUSTOM_USER_GROUPS = 5;
|
||||
|
||||
// # Login as an admin and create test users that will click the different notification ctas
|
||||
cy.apiInitSetup().then(({team, channel, offTopicUrl: url}) => {
|
||||
myTeam = team;
|
||||
myChannel = channel;
|
||||
myUrl = url;
|
||||
|
||||
// # Create non admin users
|
||||
myMessageLimitUsers = createUsersProcess(myTeam, myChannel, UNLIMITED_MESSAGES_USERS);
|
||||
myUnlimitedTeamsUsers = createUsersProcess(myTeam, myChannel, CREATE_MULTIPLE_TEAMS_USERS);
|
||||
myUserGroupsUsers = createUsersProcess(myTeam, myChannel, CUSTOM_USER_GROUPS);
|
||||
});
|
||||
|
||||
// # Click notify admin on message limit reached
|
||||
cy.then(() => {
|
||||
myMessageLimitUsers.forEach((user) => {
|
||||
cy.clearCookies();
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
cy.wait(['@subscription', '@products']);
|
||||
createMessageLimitNotification();
|
||||
});
|
||||
});
|
||||
|
||||
// # Click notify admin on team limit reached
|
||||
cy.then(() => {
|
||||
myUnlimitedTeamsUsers.forEach((user) => {
|
||||
cy.clearCookies();
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
cy.wait(['@subscription', '@products']);
|
||||
creatNewTeamNotification();
|
||||
});
|
||||
});
|
||||
|
||||
// # Click notify admin to allow user groups creation
|
||||
cy.then(() => {
|
||||
myUserGroupsUsers.forEach((user) => {
|
||||
cy.clearCookies();
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
userGroupsNotification();
|
||||
});
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
// # Manually trigger saved notifications
|
||||
triggerNotifications(myUrl, false);
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
assertNotification('mattermost.feature.custom_user_groups', 'Enterprise plan', 10, CUSTOM_USER_GROUPS, myTeam.name);
|
||||
assertNotification('mattermost.feature.create_multiple_teams', 'Professional plan', 10, CREATE_MULTIPLE_TEAMS_USERS, myTeam.name);
|
||||
assertNotification('mattermost.feature.unlimited_messages', 'Professional plan', 10, UNLIMITED_MESSAGES_USERS, myTeam.name);
|
||||
assertUpgradeMessageButton();
|
||||
});
|
||||
deletePost();
|
||||
}
|
||||
|
||||
describe('Notify Admin', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
cy.apiUpdateConfig({
|
||||
ServiceSettings: {
|
||||
EnableAPITriggerAdminNotifications: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
triggerNotifications('', false, false);
|
||||
});
|
||||
|
||||
it('should test trial notifications', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 0, // never trialed before
|
||||
};
|
||||
|
||||
cy.intercept('GET', '**/api/v4/usage/posts', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
count: 4500,
|
||||
},
|
||||
});
|
||||
const limits = {
|
||||
messages: {
|
||||
history: 8000,
|
||||
},
|
||||
teams: {
|
||||
active: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
};
|
||||
|
||||
testTrialNotifications(subscription, limits);
|
||||
});
|
||||
|
||||
it('should test files upgrade notifications', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 0, // never trialed before
|
||||
};
|
||||
|
||||
const fileStorageUsageBytes = 11000000000;
|
||||
|
||||
const limits = {
|
||||
messages: {
|
||||
history: 7000, // test server seeded with around 4k messages
|
||||
},
|
||||
teams: {
|
||||
active: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
files: {
|
||||
total_storage: fileStorageUsageBytes,
|
||||
},
|
||||
};
|
||||
|
||||
simulateFilesLimitReached(fileStorageUsageBytes);
|
||||
testFilesNotifications(subscription, limits);
|
||||
});
|
||||
|
||||
it('should test upgrade notifications', () => {
|
||||
cy.intercept('GET', '**/api/v4/usage/posts', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
count: 7000,
|
||||
},
|
||||
});
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
|
||||
const limits = {
|
||||
messages: {
|
||||
history: 7500,
|
||||
},
|
||||
teams: {
|
||||
active: 0, // no extra teams allowed to be created
|
||||
teamsLoaded: true,
|
||||
},
|
||||
};
|
||||
|
||||
testUpgradeNotifications(subscription, limits);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,120 @@
|
||||
// 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 @cloud_only @cloud_trial
|
||||
|
||||
function simulateSubscription() {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: 'sub_test1',
|
||||
is_free_trial: 'true',
|
||||
customer_id: '5zqhakmibpgyix9juiwwkpfnmr',
|
||||
product_id: 'prod_Jh6tBLcgWWOOog',
|
||||
seats: 25,
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body:
|
||||
[
|
||||
{
|
||||
id: 'prod_LSBESgGXq9KlLj',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
},
|
||||
{
|
||||
id: 'prod_K0AxuWCDoDD9Qq',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'prod_Jh6tBLcgWWOOog',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
describe('System Console - Payment Information section', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
simulateSubscription();
|
||||
|
||||
// # Visit Subscription page
|
||||
cy.visit('/admin_console/billing/subscription');
|
||||
|
||||
// * Check for Subscription header
|
||||
cy.contains('.admin-console__header', 'Subscription').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T4120 Validate non existence of Payment Information menu should during the trial period', () => {
|
||||
// * Check for visibility of payment information menu
|
||||
cy.get('#billing\\/payment_info', {timeout: 10000}).should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T5207 should validate admin user is able to submit alternative payment option', () => {
|
||||
cy.intercept('PUT', '/api/v4/cloud/customer', {
|
||||
body: {
|
||||
name: '',
|
||||
email: 'user123@example.mattermost.com',
|
||||
num_employees: 0,
|
||||
monthly_subscription_intent_wire_transfer: '',
|
||||
id: 'uniqueID',
|
||||
creator_id: '123randomId',
|
||||
create_at: 1665763513000,
|
||||
first_purchase_alt_payment_method: '{"ach":false,"wire":false,"other":true,"otherPaymentOption":"Test Payment Option"}',
|
||||
billing_address: {city: '',
|
||||
country: '',
|
||||
line1: '',
|
||||
line2: '',
|
||||
postal_code: '',
|
||||
state: ''},
|
||||
company_address: {city: '',
|
||||
country: '',
|
||||
line1: '',
|
||||
line2: '',
|
||||
postal_code: '',
|
||||
state: ''},
|
||||
payment_method: {type: '',
|
||||
last_four: '',
|
||||
exp_month: 0,
|
||||
exp_year: 0,
|
||||
card_brand: '',
|
||||
name: ''},
|
||||
}}).as('feedbackResponse');
|
||||
cy.get('.UpgradeMattermostCloud__upgradeButton').click();
|
||||
cy.get('button#monthlySubscription').as('paymentFeedbackLink').should('be.visible').should('have.text', 'Looking for other payment options?').click();
|
||||
cy.get('.Form-section-title').should('be.visible');
|
||||
cy.get('input#wire').should('be.not.checked');
|
||||
cy.get('input#ach').should('be.not.checked');
|
||||
cy.get('input#other').should('be.not.checked');
|
||||
cy.get('button#cancelFeedback').should('be.enabled').click();
|
||||
cy.get('@paymentFeedbackLink').click();
|
||||
cy.get('button#submitFeedback').should('be.disabled');
|
||||
|
||||
cy.get('input#wire').as('wireOption').check();
|
||||
cy.get('button#submitFeedback').as('savebutton').should('be.enabled');
|
||||
cy.get('@wireOption').check();
|
||||
|
||||
cy.get('@savebutton').should('be.enabled').click();
|
||||
cy.wait('@feedbackResponse');
|
||||
cy.get('span.savedFeedback__text').should('be.visible').should('have.text', 'Thanks for sharing feedback!');
|
||||
cy.get('button#feedbackSubmitedDone').should('be.enabled').click();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
// 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 @cloud_only @cloud_trial
|
||||
|
||||
import billing from '../../../../../fixtures/client_billing.json';
|
||||
|
||||
function simulateSubscription() {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: 'sub_test1',
|
||||
is_free_trial: 'true',
|
||||
customer_id: '5zqhakmibpgyix9juiwwkpfnmr',
|
||||
product_id: 'prod_Jh6tBLcgWWOOog',
|
||||
seats: 25,
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body:
|
||||
[
|
||||
{
|
||||
id: 'prod_LSBESgGXq9KlLj',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
},
|
||||
{
|
||||
id: 'prod_K0AxuWCDoDD9Qq',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'prod_Jh6tBLcgWWOOog',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/customer', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
name: 'Test environment ',
|
||||
email: 'test.mattermost.com@mattermost.com',
|
||||
num_employees: 12,
|
||||
monthly_subscription_alt_payment_method: '',
|
||||
id: 'oip7khhhkpbk7cjkrf7m66qyas',
|
||||
creator_id: 'iq9xcutqp7bpdramcij939yas',
|
||||
create_at: 1661456270000,
|
||||
billing_address: {
|
||||
city: 'Seattle',
|
||||
country: 'United States',
|
||||
line1: '123 Hello',
|
||||
line2: '',
|
||||
postal_code: '38383',
|
||||
state: 'AK',
|
||||
},
|
||||
company_address: {
|
||||
city: '',
|
||||
country: '',
|
||||
line1: '',
|
||||
line2: '',
|
||||
postal_code: '',
|
||||
state: '',
|
||||
},
|
||||
payment_method: {
|
||||
type: 'card',
|
||||
last_four: '4242',
|
||||
exp_month: 4,
|
||||
exp_year: 2028,
|
||||
card_brand: 'visa',
|
||||
name: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
describe('System Console - Subscriptions section', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
simulateSubscription();
|
||||
|
||||
// # Visit Subscription page
|
||||
cy.visit('/admin_console/billing/subscription');
|
||||
});
|
||||
|
||||
it('MM-T4118 Subscription page UI check', () => {
|
||||
// * Check for Subscription header
|
||||
cy.contains('.admin-console__header', 'Subscription').should('be.visible');
|
||||
|
||||
// * Check for visibility of Trial tag
|
||||
cy.contains('span', 'trial', {timeout: 10000}).should('be.visible');
|
||||
|
||||
// * Check for User count
|
||||
cy.request('/api/v4/analytics/old?name=standard&team_id=').then((response) => {
|
||||
cy.get('.PlanDetails__userCount > span').invoke('text').then((text) => {
|
||||
const userCount = response.body.find((obj) => obj.name === 'unique_user_count');
|
||||
expect(text).to.contain(userCount.value);
|
||||
});
|
||||
});
|
||||
|
||||
// * Check for See how billing works navigation
|
||||
cy.contains('span', 'See how billing works').parent().then((link) => {
|
||||
const getHref = () => link.prop('href');
|
||||
cy.wrap({href: getHref}).invoke('href').should('contains', '/cloud-billing.html');
|
||||
cy.wrap(link).should('have.attr', 'target', '_blank');
|
||||
cy.wrap(link).should('have.attr', 'rel', 'noopener noreferrer');
|
||||
cy.request(link.prop('href')).its('status').should('eq', 200);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4122 "Upgrade now" navigation and closing of Upgrade window', () => {
|
||||
// # Click on Upgrade Now button
|
||||
cy.contains('span', 'Upgrade Now').parent().click();
|
||||
cy.get('#professional_action').click();
|
||||
|
||||
// * Check for "Provide Your Payment Details" label
|
||||
cy.findByText('Provide your payment details').should('be.visible');
|
||||
|
||||
// # Click on close button of Upgrade window
|
||||
cy.get('#closeIcon').parent().should('exist').click();
|
||||
|
||||
// * Check for "Your trial has started!" label
|
||||
cy.contains('span', 'Your trial has started!').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T4124 Purchase modal UI check', () => {
|
||||
// # Click on Upgrade Now button
|
||||
cy.contains('span', 'Upgrade Now').parent().click();
|
||||
|
||||
cy.get('#professional_action').click();
|
||||
|
||||
// * Check for "Provide Your Payment Details" label
|
||||
cy.findByText('Provide your payment details').should('be.visible');
|
||||
|
||||
// * Check for Compare plans navigation
|
||||
cy.contains('span', 'Compare plans').click();
|
||||
|
||||
cy.findByRole('heading', {name: 'Select a plan'}).should('be.visible');
|
||||
cy.findByRole('button', {name: 'Close'}).click();
|
||||
|
||||
// * Check for See how billing works navigation
|
||||
cy.contains('span', 'See how billing works').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T4128 Enable/disable "Upgrade" button in Purchase modal', () => {
|
||||
// # Click on Upgrade Now button
|
||||
cy.contains('span', 'Upgrade Now').parent().click();
|
||||
|
||||
// # Click on Upgrade Now button on plans modal
|
||||
cy.get('#professional_action').click();
|
||||
|
||||
// * Check for "Provide your payment details" label
|
||||
cy.findByText('Provide your payment details').should('be.visible');
|
||||
|
||||
// # Enter card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.visa.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.visa.expDate);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(billing.visa.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test name');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('India{enter}', {force: true});
|
||||
cy.get('#input_address').type('test1');
|
||||
cy.get('#input_address2').type('test2');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('#input_state').type('test');
|
||||
cy.get('#input_postalCode').type('444');
|
||||
|
||||
// * Check for enable status of Upgrade button
|
||||
cy.get('.RHS').find('button').should('be.enabled');
|
||||
|
||||
// # Enter invalid csv
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cvc"]').clear().type(billing.invalidvisa.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test user');
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
|
||||
// # Enter billing details
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('India{enter}', {force: true});
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
cy.get('#input_address').type('test1');
|
||||
cy.get('#input_address2').type('test2');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
cy.get('#input_state').type('test');
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
cy.get('#input_postalCode').type('444');
|
||||
|
||||
// # Enter invalid card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.invalidvisa.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.visa.expDate);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(billing.visa.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test user');
|
||||
|
||||
// * Check for disabled Upgrade button for having wrong card details
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,167 @@
|
||||
// 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 @cloud_only @cloud_trial
|
||||
|
||||
import billing from '../../../../../fixtures/client_billing.json';
|
||||
|
||||
function simulateSubscription() {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: 'sub_test1',
|
||||
is_free_trial: 'true',
|
||||
customer_id: '5zqhakmibpgyix9juiwwkpfnmr',
|
||||
product_id: 'prod_LSBESgGXq9KlLj',
|
||||
seats: 25,
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body:
|
||||
[
|
||||
{
|
||||
id: 'prod_LSBESgGXq9KlLj',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
recurring_interval: 'month',
|
||||
cross_sells_to: '',
|
||||
},
|
||||
{
|
||||
id: 'prod_K0AxuWCDoDD9Qq',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
recurring_interval: 'month',
|
||||
cross_sells_to: 'prod_MYrZ0xObCXOyVr',
|
||||
},
|
||||
{
|
||||
id: 'prod_Jh6tBLcgWWOOog',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
recurring_interval: 'month',
|
||||
cross_sells_to: '',
|
||||
},
|
||||
{
|
||||
id: 'prod_MYrZ0xObCXOyVr',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 96,
|
||||
recurring_interval: 'year',
|
||||
name: 'Cloud Professional Yearly',
|
||||
cross_sells_to: 'prod_K0AxuWCDoDD9Qq',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
describe('System Console - Subscriptions section', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
simulateSubscription();
|
||||
|
||||
// # Visit Subscription page
|
||||
cy.visit('/admin_console/billing/subscription');
|
||||
});
|
||||
|
||||
it('MM-T5128 Updating the Usercount input field updates the prices accordingly in the Purchase modal', () => {
|
||||
const professionalYearlySubscription = {
|
||||
id: 'prod_MYrZ0xObCXOyVr',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 8,
|
||||
recurring_interval: 'year',
|
||||
name: 'Cloud Professional Yearly',
|
||||
cross_sells_to: 'prod_K0AxuWCDoDD9Qq',
|
||||
};
|
||||
|
||||
// * Check for User count
|
||||
cy.request('/api/v4/analytics/old?name=standard&team_id=').then((response) => {
|
||||
cy.get('.PlanDetails__userCount > span').invoke('text').then((text) => {
|
||||
const userCount = response.body.find((obj) => obj.name === 'unique_user_count');
|
||||
expect(text).to.contain(userCount.value);
|
||||
|
||||
const count = Number(userCount.value);
|
||||
|
||||
const numMonths = 12;
|
||||
|
||||
const checkValues = (currentCount) => {
|
||||
const totalVal = currentCount * professionalYearlySubscription.price_per_seat * numMonths;
|
||||
cy.get('.RHS').get('.SeatsCalculator__total-value').then((elem) => {
|
||||
const txt = elem.text();
|
||||
const totalValText = txt.replace('$', '').replaceAll(',', '');
|
||||
expect(totalVal.toString()).to.equal(totalValText);
|
||||
});
|
||||
};
|
||||
|
||||
// # Click on Upgrade Now button
|
||||
cy.contains('span', 'Upgrade Now').parent().click();
|
||||
|
||||
// # Click on Professional action button on pricing modal
|
||||
cy.get('#professional_action').click();
|
||||
|
||||
// * Check for "Provide Your Payment Details" label
|
||||
cy.findByText('Provide your payment details').should('be.visible');
|
||||
|
||||
// * check that the price matches the yearly product's price
|
||||
cy.get('.RHS').get('.plan_price_rate_section').contains(professionalYearlySubscription.price_per_seat);
|
||||
cy.get('.RHS').get('#input_UserSeats').should('have.value', count);
|
||||
|
||||
// * check that the prices are correct
|
||||
checkValues(count);
|
||||
|
||||
// # Enter card details and user details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.visa.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.visa.expDate);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(billing.visa.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test name');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('India{enter}', {force: true});
|
||||
cy.get('#input_address').type('test1');
|
||||
cy.get('#input_address2').type('test2');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('#input_state').type('test');
|
||||
cy.get('#input_postalCode').type('444');
|
||||
|
||||
// * Check for enable status of Upgrade button
|
||||
cy.get('.RHS').find('button').should('be.enabled');
|
||||
|
||||
// # Change the user seats field to a value smaller than the current number of users
|
||||
const lessThanUserCount = count - 5;
|
||||
cy.get('#input_UserSeats').clear().type(lessThanUserCount);
|
||||
|
||||
// * Ensure that the yearly, monthly, and yearly saving prices match the new user seats value entered
|
||||
checkValues(lessThanUserCount);
|
||||
cy.get('.RHS').get('.Input___customMessage').contains(`Your workspace currently has ${count} users`);
|
||||
|
||||
// * Check that Upgrade button is not enabled
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
|
||||
// # Change the user seats field to a value bigger than the current number of users
|
||||
const greaterThanUserCount = count + 5;
|
||||
cy.get('#input_UserSeats').clear().type(greaterThanUserCount);
|
||||
|
||||
// * Ensure that the yearly, monthly, and yearly saving prices match the new user seats value entered
|
||||
checkValues(greaterThanUserCount);
|
||||
|
||||
// * Check for enable status of Upgrade button
|
||||
cy.get('.RHS').find('button').should('be.enabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,123 @@
|
||||
// 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 @elasticsearch @autocomplete @not_cloud
|
||||
|
||||
import {getAdminAccount} from '../../../../support/env';
|
||||
|
||||
import {
|
||||
createPrivateChannel,
|
||||
createPublicChannel,
|
||||
enableElasticSearch,
|
||||
searchAndVerifyChannel,
|
||||
} from './helpers';
|
||||
|
||||
describe('Autocomplete with Elasticsearch - Channel', () => {
|
||||
let testTeam;
|
||||
let testUser;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// # Check if server has license for Elasticsearch
|
||||
cy.apiRequireLicenseForFeature('Elasticsearch');
|
||||
|
||||
// # Enable Elasticsearch
|
||||
enableElasticSearch();
|
||||
|
||||
// # Login as test user and go to town-square
|
||||
cy.apiInitSetup({loginAfter: true}).then(({team, user}) => {
|
||||
testUser = user;
|
||||
testTeam = team;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Visit town-square channel
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
});
|
||||
|
||||
it('MM-T2510_1 Private channel I do belong to appears', () => {
|
||||
// # Create private channel and add new user to it (sets @privateChannel alias)
|
||||
createPrivateChannel(testTeam.id, testUser).then((channel) => {
|
||||
// # Go to off-topic channel to partially reload the page
|
||||
cy.uiGetLhsSection('CHANNELS').findByText('Off-Topic').click();
|
||||
|
||||
// * Private channel in suggestion list should appear
|
||||
searchAndVerifyChannel(channel);
|
||||
});
|
||||
});
|
||||
|
||||
it("MM-T2510_2 Private channel I don't belong to does not appear", () => {
|
||||
// # Create private channel, do not add new user to it (sets @privateChannel alias)
|
||||
createPrivateChannel(testTeam.id).then((channel) => {
|
||||
// # Go to off-topic channel to partially reload the page
|
||||
cy.uiGetLhsSection('CHANNELS').findByText('Off-Topic').click();
|
||||
|
||||
// * Private channel should not appear on search
|
||||
searchAndVerifyChannel(channel, false);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2510_3 Private channel left does not appear', () => {
|
||||
// # Create private channel and add new user to it (sets @privateChannel alias)
|
||||
createPrivateChannel(testTeam.id, testUser).then((channel) => {
|
||||
// # Visit private channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Leave private channel
|
||||
cy.uiOpenChannelMenu('Leave Channel');
|
||||
cy.findByRoleExtended('button', {name: 'Yes, leave channel'}).should('be.visible').click();
|
||||
|
||||
// # Go to off-topic channel to partially reload the page
|
||||
cy.uiGetLhsSection('CHANNELS').findByText('Off-Topic').click();
|
||||
|
||||
// * Private channel should not appear on search
|
||||
searchAndVerifyChannel(channel, false);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2510_4 Channel outside of team does not appear', () => {
|
||||
const teamName = 'elastic-private-' + Date.now();
|
||||
|
||||
// # As admin, create a new team that the new user is not a member of
|
||||
cy.externalRequest({
|
||||
user: getAdminAccount(),
|
||||
path: 'teams',
|
||||
method: 'post',
|
||||
data: {
|
||||
name: teamName,
|
||||
display_name: teamName,
|
||||
type: 'O',
|
||||
},
|
||||
}).then(({data: team}) => {
|
||||
// # Create a private channel where the new user is not a member of
|
||||
createPrivateChannel(team.id).then((channel) => {
|
||||
// # Go to off-topic channel to partially reload the page
|
||||
cy.uiGetLhsSection('CHANNELS').findByText('Off-Topic').click();
|
||||
|
||||
// * Private channel should not appear on search
|
||||
searchAndVerifyChannel(channel, false);
|
||||
cy.uiClose();
|
||||
});
|
||||
|
||||
return cy.wrap({team});
|
||||
}).then(({team}) => {
|
||||
// # Create a private channel where the new user is not a member of
|
||||
createPublicChannel(team.id).then((publicChannel) => {
|
||||
// # Go to off-topic channel to partially reload the page
|
||||
cy.uiGetLhsSection('CHANNELS').findByText('Off-Topic').click();
|
||||
|
||||
// * Public channel should not appear on search
|
||||
searchAndVerifyChannel(publicChannel, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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 @elasticsearch @autocomplete @not_cloud
|
||||
|
||||
import {
|
||||
enableElasticSearch,
|
||||
searchAndVerifyChannel,
|
||||
} from './helpers';
|
||||
|
||||
describe('Autocomplete with Elasticsearch - Channel', () => {
|
||||
let testChannel;
|
||||
let teamName;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// * Check if server has license for Elasticsearch
|
||||
cy.apiRequireLicenseForFeature('Elasticsearch');
|
||||
|
||||
// # Enable Elasticsearch
|
||||
enableElasticSearch();
|
||||
|
||||
// # Login as test user
|
||||
cy.apiInitSetup({loginAfter: true}).then(({team}) => {
|
||||
teamName = team.name;
|
||||
const name = 'hellothere';
|
||||
|
||||
cy.apiCreateChannel(team.id, name, name).then(({channel}) => {
|
||||
testChannel = channel;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Visit off-topic channel
|
||||
cy.visit(`/${teamName}/channels/off-topic`);
|
||||
});
|
||||
|
||||
it('MM-T2517_1 Channels with dot returned in autocomplete suggestions', () => {
|
||||
const name = 'hello.there';
|
||||
|
||||
// # Change the name of channel
|
||||
cy.apiPatchChannel(testChannel.id, {display_name: name});
|
||||
|
||||
// * Search for channel should work
|
||||
searchAndVerifyChannel({...testChannel, display_name: name});
|
||||
});
|
||||
|
||||
it('MM-T2517_2 Channels with dash returned in autocomplete suggestions', () => {
|
||||
const name = 'hello-there';
|
||||
|
||||
// # Change the name of channel
|
||||
cy.apiPatchChannel(testChannel.id, {display_name: name});
|
||||
|
||||
// * Search for channel should work
|
||||
searchAndVerifyChannel({...testChannel, display_name: name});
|
||||
});
|
||||
|
||||
it('MM-T2517_3 Channels with underscore returned in autocomplete suggestions', () => {
|
||||
const name = 'hello_there';
|
||||
|
||||
// # Change the name of channel
|
||||
cy.apiPatchChannel(testChannel.id, {display_name: name});
|
||||
|
||||
// * Search for channel should work
|
||||
searchAndVerifyChannel({...testChannel, display_name: name});
|
||||
});
|
||||
|
||||
it('MM-T2517_4 Channels with dot, dash and underscore returned in autocomplete suggestions', () => {
|
||||
const name = 'he.llo-the_re';
|
||||
|
||||
// # Change the name of channel
|
||||
cy.apiPatchChannel(testChannel.id, {display_name: name});
|
||||
|
||||
// * Search for channel should work
|
||||
searchAndVerifyChannel({...testChannel, display_name: name});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,252 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
import {getAdminAccount} from '../../../../../support/env';
|
||||
|
||||
const admin = getAdminAccount();
|
||||
|
||||
function withTimestamp(string, timestamp) {
|
||||
return string + '-' + timestamp;
|
||||
}
|
||||
|
||||
function createEmail(name, timestamp) {
|
||||
return name + timestamp + '@sample.mattermost.com';
|
||||
}
|
||||
|
||||
// Helper function to start @mention
|
||||
function startAtMention(string) {
|
||||
// # Get the expected input
|
||||
cy.get('@input').clear().type(string);
|
||||
|
||||
// * Suggestion list should appear
|
||||
cy.get('#suggestionList').should('be.visible');
|
||||
}
|
||||
|
||||
function searchForChannel(name) {
|
||||
// # Open up channel switcher
|
||||
cy.typeCmdOrCtrl().type('k').wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// # Clear out and type in the name
|
||||
cy.findByRole('textbox', {name: 'quick switch input'}).
|
||||
should('be.visible').
|
||||
as('input').
|
||||
clear().
|
||||
type(name);
|
||||
}
|
||||
|
||||
function createChannel(channelType, teamId, userToAdd = null) {
|
||||
// # Create a channel as sysadmin
|
||||
return cy.externalRequest({
|
||||
user: admin,
|
||||
method: 'POST',
|
||||
path: 'channels',
|
||||
data: {
|
||||
team_id: teamId,
|
||||
name: 'test-channel' + Date.now(),
|
||||
display_name: 'Test Channel ' + Date.now(),
|
||||
type: channelType,
|
||||
header: '',
|
||||
purpose: '',
|
||||
},
|
||||
}).then(({data: channel}) => {
|
||||
if (userToAdd) {
|
||||
// # Get user profile by email
|
||||
return cy.apiGetUserByEmail(userToAdd.email).then(({user}) => {
|
||||
// # Add user to team
|
||||
cy.externalRequest({
|
||||
user: admin,
|
||||
method: 'post',
|
||||
path: `channels/${channel.id}/members`,
|
||||
data: {user_id: user.id},
|
||||
}).then(() => {
|
||||
// # Explicitly wait to give some time to index before searching
|
||||
cy.wait(TIMEOUTS.TWO_SEC);
|
||||
return cy.wrap(channel);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// # Explicitly wait to give some time to index before searching
|
||||
cy.wait(TIMEOUTS.TWO_SEC);
|
||||
return cy.wrap(channel);
|
||||
});
|
||||
}
|
||||
|
||||
export function createPrivateChannel(teamId, userToAdd = null) {
|
||||
// # Create a private channel as sysadmin
|
||||
return createChannel('P', teamId, userToAdd);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
withTimestamp,
|
||||
createEmail,
|
||||
startAtMention,
|
||||
searchForChannel,
|
||||
enableElasticSearch: () => {
|
||||
// # Enable elastic search via the API
|
||||
cy.apiUpdateConfig({
|
||||
ElasticsearchSettings: {
|
||||
EnableAutocomplete: true,
|
||||
EnableIndexing: true,
|
||||
EnableSearching: true,
|
||||
Sniff: false,
|
||||
},
|
||||
});
|
||||
|
||||
// # Navigate to the elastic search setting page
|
||||
cy.visit('/admin_console/environment/elasticsearch');
|
||||
|
||||
// * Test the connection and verify that we are successful
|
||||
cy.contains('button', 'Test Connection').click();
|
||||
cy.get('.alert-success').should('have.text', 'Test successful. Configuration saved.');
|
||||
|
||||
// # Index so we are up to date
|
||||
cy.contains('button', 'Index Now').click();
|
||||
|
||||
// # Small wait to ensure new row is added
|
||||
cy.wait(TIMEOUTS.ONE_SEC).get('.job-table__table').find('tbody > tr').eq(0).as('firstRow');
|
||||
|
||||
// * Newest row should eventually result in Success
|
||||
const checkFirstRow = () => {
|
||||
return cy.get('@firstRow').then((el) => {
|
||||
return el.find('.status-icon-success').length > 0;
|
||||
});
|
||||
};
|
||||
const options = {
|
||||
timeout: TIMEOUTS.TWO_MIN,
|
||||
interval: TIMEOUTS.TWO_SEC,
|
||||
errorMsg: 'Reindex did not succeed in time',
|
||||
};
|
||||
cy.waitUntil(checkFirstRow, options);
|
||||
},
|
||||
getTestUsers: () => {
|
||||
// Reverse the timestamp so that on search,
|
||||
// the newly created user will get on the list first.
|
||||
const reverseTimeStamp = (20 * Math.pow(10, 13)) - Date.now();
|
||||
return {
|
||||
ironman: {
|
||||
username: withTimestamp('ironman', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'Tony',
|
||||
last_name: 'Stark',
|
||||
email: createEmail('ironman', reverseTimeStamp),
|
||||
nickname: withTimestamp('protoncannon', reverseTimeStamp),
|
||||
},
|
||||
hulk: {
|
||||
username: withTimestamp('hulk', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'Bruce',
|
||||
last_name: 'Banner',
|
||||
email: createEmail('hulk', reverseTimeStamp),
|
||||
nickname: withTimestamp('gammaray', reverseTimeStamp),
|
||||
},
|
||||
hawkeye: {
|
||||
username: withTimestamp('hawkeye', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'Clint',
|
||||
last_name: 'Barton',
|
||||
email: createEmail('hawkeye', reverseTimeStamp),
|
||||
nickname: withTimestamp('ronin', reverseTimeStamp),
|
||||
},
|
||||
deadpool: {
|
||||
username: withTimestamp('deadpool', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'Wade',
|
||||
last_name: 'Wilson',
|
||||
email: createEmail('deadpool', reverseTimeStamp),
|
||||
nickname: withTimestamp('merc', reverseTimeStamp),
|
||||
},
|
||||
captainamerica: {
|
||||
username: withTimestamp('captainamerica', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'Steve',
|
||||
last_name: 'Rogers',
|
||||
email: createEmail('captainamerica', reverseTimeStamp),
|
||||
nickname: withTimestamp('professional', reverseTimeStamp),
|
||||
},
|
||||
doctorstrange: {
|
||||
username: withTimestamp('doctorstrange', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'Stephen',
|
||||
last_name: 'Strange',
|
||||
email: createEmail('doctorstrange', reverseTimeStamp),
|
||||
nickname: withTimestamp('sorcerersupreme', reverseTimeStamp),
|
||||
},
|
||||
thor: {
|
||||
username: withTimestamp('thor', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'Thor',
|
||||
last_name: 'Odinson',
|
||||
email: createEmail('thor', reverseTimeStamp),
|
||||
nickname: withTimestamp('mjolnir', reverseTimeStamp),
|
||||
},
|
||||
loki: {
|
||||
username: withTimestamp('loki', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'Loki',
|
||||
last_name: 'Odinson',
|
||||
email: createEmail('loki', reverseTimeStamp),
|
||||
nickname: withTimestamp('trickster', reverseTimeStamp),
|
||||
},
|
||||
dot: {
|
||||
username: withTimestamp('dot.dot', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'z1First',
|
||||
last_name: 'z1Last',
|
||||
email: createEmail('dot', reverseTimeStamp),
|
||||
nickname: 'z1Nick',
|
||||
},
|
||||
dash: {
|
||||
username: withTimestamp('dash-dash', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'z2First',
|
||||
last_name: 'z2Last',
|
||||
email: createEmail('dash', reverseTimeStamp),
|
||||
nickname: 'z2Nick',
|
||||
},
|
||||
underscore: {
|
||||
username: withTimestamp('under_score', reverseTimeStamp),
|
||||
password: 'passwd',
|
||||
first_name: 'z3First',
|
||||
last_name: 'z3Last',
|
||||
email: createEmail('underscore', reverseTimeStamp),
|
||||
nickname: 'z3Nick',
|
||||
},
|
||||
};
|
||||
},
|
||||
createPrivateChannel: (teamId, userToAdd = null) => {
|
||||
// # Create a private channel as sysadmin
|
||||
return createChannel('P', teamId, userToAdd);
|
||||
},
|
||||
createPublicChannel: (teamId, userToAdd = null) => {
|
||||
// # Create a public channel as sysadmin
|
||||
return createChannel('O', teamId, userToAdd);
|
||||
},
|
||||
searchAndVerifyChannel: (channel, shouldExist = true) => {
|
||||
const name = channel.display_name;
|
||||
searchForChannel(name);
|
||||
|
||||
if (shouldExist) {
|
||||
// * Channel should appear in suggestions list
|
||||
cy.get('#suggestionList').findByTestId(channel.name).should('be.visible');
|
||||
} else {
|
||||
// * Suggestion list and channel item should not appear
|
||||
cy.get('#suggestionList').should('not.exist');
|
||||
cy.findByTestId(channel.name).should('not.exist');
|
||||
}
|
||||
},
|
||||
searchAndVerifyUser: (user) => {
|
||||
// # Start @ mentions autocomplete with username
|
||||
cy.uiGetPostTextBox().
|
||||
as('input').
|
||||
clear().
|
||||
type(`@${user.username}`);
|
||||
|
||||
// * Suggestion list should appear
|
||||
cy.get('#suggestionList', {timeout: TIMEOUTS.FIVE_SEC}).should('be.visible');
|
||||
|
||||
// * Verify user appears in results post-change
|
||||
return cy.uiVerifyAtMentionSuggestion(user);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
// 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 @elasticsearch @autocomplete @not_cloud
|
||||
|
||||
import {getRandomId} from '../../../../utils';
|
||||
|
||||
import {
|
||||
enableElasticSearch,
|
||||
searchAndVerifyChannel,
|
||||
searchAndVerifyUser,
|
||||
} from './helpers';
|
||||
|
||||
describe('Autocomplete with Elasticsearch - Renaming', () => {
|
||||
let testUser;
|
||||
let testChannel;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// * Check if server has license for Elasticsearch
|
||||
cy.apiRequireLicenseForFeature('Elasticsearch');
|
||||
|
||||
cy.apiInitSetup().then(({team, channel, user}) => {
|
||||
testUser = user;
|
||||
testChannel = channel;
|
||||
|
||||
// # Enable Elasticsearch
|
||||
enableElasticSearch();
|
||||
|
||||
// # Visit town-square channel
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2512 Change is reflected in the search when renaming a user', () => {
|
||||
// # Verify user appears in search results before change
|
||||
searchAndVerifyUser(testUser);
|
||||
|
||||
// # Rename a user
|
||||
cy.apiPatchUser(testUser.id, {username: `newusername-${getRandomId()}`}).then(({user}) => {
|
||||
// # Verify user appears in search results post-change
|
||||
searchAndVerifyUser(user);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2513 Change is reflected in the search when renaming a channel', () => {
|
||||
// # Verify channel appears in search results before change
|
||||
searchAndVerifyChannel(testChannel);
|
||||
|
||||
// # Change the channels name
|
||||
cy.apiPatchChannel(testChannel.id, {name: `newname-${getRandomId()}`}).then(({channel}) => {
|
||||
cy.reload();
|
||||
|
||||
// # Search for channel and verify it appears
|
||||
searchAndVerifyChannel(channel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
// 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 @elasticsearch @autocomplete @not_cloud
|
||||
|
||||
import {getRandomId} from '../../../../utils';
|
||||
|
||||
import {
|
||||
enableElasticSearch,
|
||||
searchAndVerifyChannel,
|
||||
searchAndVerifyUser,
|
||||
} from './helpers';
|
||||
|
||||
describe('Autocomplete with Elasticsearch - Renaming Team', () => {
|
||||
const randomId = getRandomId();
|
||||
let testUser;
|
||||
let testChannel;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// * Check if server has license for Elasticsearch
|
||||
cy.apiRequireLicenseForFeature('Elasticsearch');
|
||||
|
||||
cy.apiInitSetup().then(({team, channel, user}) => {
|
||||
testUser = user;
|
||||
testChannel = channel;
|
||||
|
||||
// # Enable Elasticsearch
|
||||
enableElasticSearch();
|
||||
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
|
||||
// # Verify user and channel appears in search results before change
|
||||
searchAndVerifyUser(user);
|
||||
searchAndVerifyChannel(channel);
|
||||
|
||||
// # Rename the team
|
||||
cy.apiPatchTeam(team.id, {display_name: 'updatedteam' + randomId});
|
||||
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2514_1 Renaming a Team does not affect user autocomplete suggestions', () => {
|
||||
searchAndVerifyUser(testUser);
|
||||
});
|
||||
|
||||
it('MM-T2514_2 Renaming a Team does not affect channel autocomplete suggestions', () => {
|
||||
cy.get('body').type('{esc}');
|
||||
searchAndVerifyChannel(testChannel);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
// 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 @elasticsearch @autocomplete @not_cloud
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('Elasticsearch system console', () => {
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// # Check if server has license for Elasticsearch
|
||||
cy.apiRequireLicenseForFeature('Elasticsearch');
|
||||
|
||||
// # Enable Elasticsearch
|
||||
cy.apiUpdateConfig({
|
||||
ElasticsearchSettings: {
|
||||
EnableAutocomplete: true,
|
||||
EnableIndexing: true,
|
||||
EnableSearching: true,
|
||||
Sniff: false,
|
||||
},
|
||||
});
|
||||
|
||||
// # Visit the Elasticsearch settings page
|
||||
cy.visit('/admin_console/environment/elasticsearch');
|
||||
|
||||
// * Verify that we can connect to Elasticsearch
|
||||
cy.get('#testConfig').find('button').click();
|
||||
cy.get('.alert-success').should('have.text', 'Test successful. Configuration saved.');
|
||||
});
|
||||
|
||||
it('MM-T2519 can purge indexes', () => {
|
||||
cy.get('#purgeIndexesSection').within(() => {
|
||||
// # Click Purge Indexes button
|
||||
cy.contains('button', 'Purge Indexes').click();
|
||||
|
||||
// * We should see a message saying we are successful
|
||||
cy.get('.alert-success').should('have.text', 'Indexes purged successfully.');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2520 Can perform a bulk index', () => {
|
||||
// # Click the Index Now button to start the index
|
||||
cy.contains('button', 'Index Now').click();
|
||||
|
||||
// # Small wait to ensure new row is added
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// # Get the first row
|
||||
cy.get('.job-table__table').
|
||||
find('tbody > tr').
|
||||
eq(0).
|
||||
as('firstRow');
|
||||
|
||||
// * First row update to say Success
|
||||
cy.waitUntil(() => {
|
||||
return cy.get('@firstRow').then((el) => {
|
||||
return el.find('.status-icon-success').length > 0;
|
||||
});
|
||||
}
|
||||
, {
|
||||
timeout: TIMEOUTS.FIVE_MIN,
|
||||
interval: TIMEOUTS.TWO_SEC,
|
||||
errorMsg: 'Reindex did not succeed in time',
|
||||
});
|
||||
|
||||
cy.get('@firstRow').
|
||||
find('.status-icon-success').
|
||||
should('be.visible').
|
||||
and('have.text', 'Success');
|
||||
});
|
||||
|
||||
it('MM-T2521 Elasticsearch for autocomplete queries can be disabled', () => {
|
||||
// Check the false checkbox for enable autocomplete
|
||||
cy.get('#enableAutocompletefalse').check().should('be.checked');
|
||||
|
||||
// # Save the settings
|
||||
cy.get('#saveSetting').click().wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Get config from API and verify that EnableAutocomplete setting is false
|
||||
cy.apiGetConfig().then(({config}) => {
|
||||
expect(config.ElasticsearchSettings.EnableAutocomplete).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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 @elasticsearch @autocomplete @not_cloud
|
||||
|
||||
import {getRandomLetter} from '../../../../utils';
|
||||
import {doTestQuickChannelSwitcher} from '../../autocomplete/common_test';
|
||||
import {createSearchData, enableElasticSearch} from '../../autocomplete/helpers';
|
||||
|
||||
describe('Autocomplete with Elasticsearch - Users', () => {
|
||||
const prefix = getRandomLetter(3);
|
||||
let testUsers;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// * Check if server has license for Elasticsearch
|
||||
cy.apiRequireLicenseForFeature('Elasticsearch');
|
||||
|
||||
// # Enable Elasticsearch
|
||||
enableElasticSearch();
|
||||
|
||||
createSearchData(prefix).then((searchData) => {
|
||||
testUsers = searchData.users;
|
||||
|
||||
cy.apiLogin(searchData.sysadmin);
|
||||
|
||||
// # Navigate to the new teams town square
|
||||
cy.visit(`/${searchData.team.name}/channels/town-square`);
|
||||
|
||||
// # Open quick channel switcher
|
||||
cy.typeCmdOrCtrl().type('k');
|
||||
cy.findByRole('textbox', {name: 'quick switch input'}).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
describe('search for user in channel switcher', () => {
|
||||
describe('by @username', () => {
|
||||
it('MM-T2506_1 Full username returns single user', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}ironman`, testUsers.ironman);
|
||||
});
|
||||
|
||||
it('MM-T2506_2 Unique partial username returns single user', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}doc`, testUsers.doctorstrange);
|
||||
});
|
||||
|
||||
it('MM-T2506_3 Partial username returns all users that match', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}i`, testUsers.ironman);
|
||||
});
|
||||
});
|
||||
|
||||
describe('by @firstname', () => {
|
||||
it('MM-T3860_1 Full first name returns single user', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}tony`, testUsers.ironman);
|
||||
});
|
||||
|
||||
it('MM-T3860_2 Unique partial first name returns single user', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}wa`, testUsers.deadpool);
|
||||
});
|
||||
|
||||
it('MM-T3860_3 Partial first name returns all users that match', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}ste`, testUsers.captainamerica, testUsers.doctorstrange);
|
||||
});
|
||||
});
|
||||
|
||||
describe('by @lastname', () => {
|
||||
it('MM-T3861_1 Full last name returns single user', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}stark`, testUsers.ironman);
|
||||
});
|
||||
|
||||
it('MM-T3861_2 Unique partial last name returns single user', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}ban`, testUsers.hulk);
|
||||
});
|
||||
|
||||
it('MM-T3861_3 Partial last name returns all users that match', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}ba`, testUsers.hawkeye, testUsers.hulk);
|
||||
});
|
||||
});
|
||||
|
||||
describe('by @nickname', () => {
|
||||
it('MM-T3862_1 Full nickname returns single user', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}ronin`, testUsers.hawkeye);
|
||||
});
|
||||
|
||||
it('MM-T3862_2 Unique partial nickname returns single user', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}gam`, testUsers.hulk);
|
||||
});
|
||||
|
||||
it('MM-T3862_3 Partial nickname returns all users that match', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}pro`, testUsers.captainamerica, testUsers.ironman);
|
||||
});
|
||||
});
|
||||
|
||||
describe('special characters in usernames are returned', () => {
|
||||
it('MM-T3856_1 Username with dot', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}dot.dot`, testUsers.dot);
|
||||
});
|
||||
|
||||
it('MM-T3856_2 Username dash', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}dash-dash`, testUsers.dash);
|
||||
});
|
||||
|
||||
it('MM-T3856_3 Username underscore', () => {
|
||||
doTestQuickChannelSwitcher(`@${prefix}under_score`, testUsers.underscore);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @enterprise @elasticsearch @autocomplete @not_cloud
|
||||
|
||||
import {getRandomLetter} from '../../../../utils';
|
||||
import {doTestPostextbox} from '../../autocomplete/common_test';
|
||||
import {createSearchData, enableElasticSearch} from '../../autocomplete/helpers';
|
||||
|
||||
describe('Autocomplete with Elasticsearch - Users', () => {
|
||||
const prefix = getRandomLetter(3);
|
||||
let testUsers;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// * Check if server has license for Elasticsearch
|
||||
cy.apiRequireLicenseForFeature('Elasticsearch');
|
||||
|
||||
// # Enable Elasticsearch
|
||||
enableElasticSearch();
|
||||
|
||||
createSearchData(prefix).then((searchData) => {
|
||||
testUsers = searchData.users;
|
||||
|
||||
cy.apiLogin(searchData.sysadmin);
|
||||
|
||||
// # Navigate to the new teams town square
|
||||
cy.visit(`/${searchData.team.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('search for user in message input box', () => {
|
||||
describe('by @username', () => {
|
||||
it('MM-T2505_1 Full username returns single user', () => {
|
||||
doTestPostextbox(`@${prefix}ironman`, testUsers.ironman);
|
||||
});
|
||||
|
||||
it('MM-T2505_2 Unique partial username returns single user', () => {
|
||||
doTestPostextbox(`@${prefix}doc`, testUsers.doctorstrange);
|
||||
});
|
||||
|
||||
it('MM-T2505_3 Partial username returns all users that match', () => {
|
||||
doTestPostextbox(`@${prefix}i`, testUsers.ironman);
|
||||
});
|
||||
});
|
||||
|
||||
describe('by @firstname', () => {
|
||||
it('MM-T3857_1 Full first name returns single user', () => {
|
||||
doTestPostextbox(`@${prefix}tony`, testUsers.ironman);
|
||||
});
|
||||
|
||||
it('MM-T3857_2 Unique partial first name returns single user', () => {
|
||||
doTestPostextbox(`@${prefix}wa`, testUsers.deadpool);
|
||||
});
|
||||
|
||||
it('MM-T3857_3 Partial first name returns all users that match', () => {
|
||||
doTestPostextbox(`@${prefix}ste`, testUsers.captainamerica, testUsers.doctorstrange);
|
||||
});
|
||||
});
|
||||
|
||||
describe('by @lastname', () => {
|
||||
it('MM-T3858_1 Full last name returns single user', () => {
|
||||
doTestPostextbox(`@${prefix}stark`, testUsers.ironman);
|
||||
});
|
||||
|
||||
it('MM-T3858_2 Unique partial last name returns single user', () => {
|
||||
doTestPostextbox(`@${prefix}ban`, testUsers.hulk);
|
||||
});
|
||||
|
||||
it('MM-T3858_3 Partial last name returns all users that match', () => {
|
||||
doTestPostextbox(`@${prefix}ba`, testUsers.hawkeye, testUsers.hulk);
|
||||
});
|
||||
});
|
||||
|
||||
describe('by @nickname', () => {
|
||||
it('MM-T3859_1 Full nickname returns single user', () => {
|
||||
doTestPostextbox(`@${prefix}ronin`, testUsers.hawkeye);
|
||||
});
|
||||
|
||||
it('MM-T3859_2 Unique partial nickname returns single user', () => {
|
||||
doTestPostextbox(`@${prefix}gam`, testUsers.hulk);
|
||||
});
|
||||
|
||||
it('MM-T3859_3 Partial nickname returns all users that match', () => {
|
||||
doTestPostextbox(`@${prefix}pro`, testUsers.captainamerica, testUsers.ironman);
|
||||
});
|
||||
});
|
||||
|
||||
describe('special characters in usernames are returned', () => {
|
||||
it('MM-T2515_1 Username with dot', () => {
|
||||
doTestPostextbox(`@${prefix}dot.dot`, testUsers.dot);
|
||||
});
|
||||
|
||||
it('MM-T2515_2 Username with dash', () => {
|
||||
doTestPostextbox(`@${prefix}dash-dash`, testUsers.dash);
|
||||
});
|
||||
|
||||
it('MM-T2515_3 Username with underscore', () => {
|
||||
doTestPostextbox(`@${prefix}under_score`, testUsers.underscore);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
// 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 @elasticsearch @autocomplete @not_cloud
|
||||
|
||||
import {getRandomLetter} from '../../../../utils';
|
||||
import {doTestDMChannelSidebar, doTestUserChannelSection} from '../../autocomplete/common_test';
|
||||
import {createSearchData, enableElasticSearch} from '../../autocomplete/helpers';
|
||||
|
||||
describe('Autocomplete with Elasticsearch - Users', () => {
|
||||
const prefix = getRandomLetter(3);
|
||||
let testUsers;
|
||||
let testTeam;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// * Check if server has license for Elasticsearch
|
||||
cy.apiRequireLicenseForFeature('Elasticsearch');
|
||||
|
||||
// # Enable Elasticsearch
|
||||
enableElasticSearch();
|
||||
|
||||
createSearchData(prefix).then((searchData) => {
|
||||
testUsers = searchData.users;
|
||||
testTeam = searchData.team;
|
||||
|
||||
cy.apiLogin(searchData.sysadmin);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3863 Users in correct in/out of channel sections', () => {
|
||||
doTestUserChannelSection(prefix, testTeam, testUsers);
|
||||
});
|
||||
|
||||
it('MM-T2518 DM can be opened with a user not on your team or in your DM channel sidebar', () => {
|
||||
doTestDMChannelSidebar(testUsers);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,234 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {getAdminAccount} from '../../../../support/env';
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] 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 @extend_session
|
||||
|
||||
describe('MM-T2575 Extend Session - Email Login', () => {
|
||||
let offTopicUrl;
|
||||
const oneDay = 24 * 60 * 60 * 1000;
|
||||
const admin = getAdminAccount();
|
||||
let testUser;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// * Verify that the server has license and its database matches with the DB client and config at "cypress.json"
|
||||
cy.apiRequireLicense();
|
||||
cy.apiRequireServerDBToMatch();
|
||||
|
||||
cy.apiInitSetup().then(({user, offTopicUrl: url}) => {
|
||||
testUser = user;
|
||||
offTopicUrl = url;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Login as sysadmin and revoke sessions of the test user
|
||||
cy.apiAdminLogin();
|
||||
cy.apiRevokeUserSessions(testUser.id);
|
||||
});
|
||||
|
||||
it('should redirect to login page when session expired', () => {
|
||||
// # Update system config
|
||||
const setting = {
|
||||
ServiceSettings: {
|
||||
ExtendSessionLengthWithActivity: true,
|
||||
SessionLengthWebInHours: 1,
|
||||
},
|
||||
} as Cypress.AdminConfig;
|
||||
|
||||
cy.apiUpdateConfig(setting);
|
||||
|
||||
// # Login as test user and go to town-square channel
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
// # Get active user sessions as baseline reference
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: initialSessions}) => {
|
||||
// Post a message to a channel
|
||||
cy.postMessage(`${Date.now()}`);
|
||||
|
||||
const expiredSession = parseDateTime(initialSessions[0].createat) + 1;
|
||||
|
||||
// # Update user with expired session
|
||||
cy.dbUpdateUserSession({
|
||||
userId: initialSessions[0].userid,
|
||||
sessionId: initialSessions[0].id,
|
||||
fieldsToUpdate: {expiresat: expiredSession},
|
||||
}).then(({session: updatedSession}) => {
|
||||
// * Verify that the session is updated
|
||||
expect(parseDateTime(updatedSession.expiresat)).to.equal(expiredSession);
|
||||
|
||||
// # Invalidate cache and reload to take effect the expired session
|
||||
cy.externalRequest({user: admin, method: 'POST', path: 'caches/invalidate'});
|
||||
cy.reload();
|
||||
|
||||
// # Try to visit town-square channel
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
// * Verify that it redirects to login page due to expired session
|
||||
cy.url().should('include', `/login?redirect_to=${offTopicUrl.replace(/\//g, '%2F')}`);
|
||||
|
||||
// * Get user's active session of test user and verify that it remained as expired and is not extended
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: activeSessions}) => {
|
||||
expect(activeSessions.length).to.equal(0);
|
||||
|
||||
cy.dbGetUserSession({sessionId: initialSessions[0].id}).then(({session: unExtendedSession}) => {
|
||||
expect(parseDateTime(unExtendedSession.expiresat)).to.equal(expiredSession);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const visitAChannel = () => {
|
||||
cy.visit(offTopicUrl);
|
||||
cy.url().should('not.include', '/login?redirect_to');
|
||||
cy.url().should('include', offTopicUrl);
|
||||
};
|
||||
|
||||
const postAMessage = (now) => {
|
||||
cy.postMessage(now);
|
||||
cy.getLastPost().should('contain', now);
|
||||
};
|
||||
|
||||
const testCases = [{
|
||||
name: 'on visit to a channel',
|
||||
fn: visitAChannel,
|
||||
sessionLengthInHours: 24,
|
||||
}, {
|
||||
name: 'on posting a message',
|
||||
fn: postAMessage,
|
||||
sessionLengthInHours: 48,
|
||||
}, {
|
||||
name: 'on visit to a channel',
|
||||
fn: visitAChannel,
|
||||
sessionLengthInHours: 74,
|
||||
}, {
|
||||
name: 'on posting a message',
|
||||
fn: postAMessage,
|
||||
sessionLengthInHours: 96,
|
||||
}];
|
||||
|
||||
testCases.forEach((testCase) => {
|
||||
it(`with SessionLengthWebInHours ${testCase.sessionLengthInHours} and threshold not met, should not extend session ${testCase.name}`, () => {
|
||||
// # Update system config
|
||||
const setting = {
|
||||
ServiceSettings: {
|
||||
ExtendSessionLengthWithActivity: true,
|
||||
SessionLengthWebInHours: testCase.sessionLengthInHours,
|
||||
},
|
||||
} as Cypress.AdminConfig;
|
||||
cy.apiUpdateConfig(setting);
|
||||
|
||||
// # Login as test user and go to town-square channel
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
// # Get active user sessions as baseline reference
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: initialSessions}) => {
|
||||
const initialSession = initialSessions[0];
|
||||
|
||||
// Post a message to a channel
|
||||
cy.postMessage(`${Date.now()}`);
|
||||
|
||||
// Elapsed time of 0.9% or a bit below 1.00%
|
||||
const elapsedBelowThreshold = parseDateTime(initialSession.expiresat) - (testCase.sessionLengthInHours * oneDay * 0.0004);
|
||||
|
||||
// # Update the user session with new expiration to simulate that
|
||||
// # the session has elapsed just below 1% of session length.
|
||||
cy.dbUpdateUserSession({
|
||||
userId: initialSession.userid,
|
||||
sessionId: initialSession.id,
|
||||
fieldsToUpdate: {expiresat: elapsedBelowThreshold},
|
||||
}).then(({session: updatedSession}) => {
|
||||
// * Verify that the session is updated
|
||||
expect(parseDateTime(updatedSession.expiresat)).to.equal(elapsedBelowThreshold);
|
||||
|
||||
// # Invalidate cache and reload to take effect the new session
|
||||
cy.externalRequest({user: admin, method: 'POST', path: 'caches/invalidate'});
|
||||
cy.reload();
|
||||
|
||||
// # Visit a channel or post a message
|
||||
const now = Date.now();
|
||||
testCase.fn(now);
|
||||
|
||||
// * Get active session of test user and verify that the session has remained the same and has not extended
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: unExtendedSessions}) => {
|
||||
const unExtendedSession = unExtendedSessions[0];
|
||||
expect(initialSession.id).to.equal(unExtendedSession.id);
|
||||
expect(elapsedBelowThreshold).to.equal(parseDateTime(unExtendedSession.expiresat));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
testCases.forEach((testCase) => {
|
||||
it(`with SessionLengthWebInHours ${testCase.sessionLengthInHours} and threshold met, should extend session ${testCase.name}`, () => {
|
||||
// # Update system config
|
||||
const setting = {
|
||||
ServiceSettings: {
|
||||
ExtendSessionLengthWithActivity: true,
|
||||
SessionLengthWebInHours: testCase.sessionLengthInHours,
|
||||
},
|
||||
} as Cypress.AdminConfig;
|
||||
cy.apiUpdateConfig(setting);
|
||||
|
||||
// # Login as test user and go to town-square channel
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
// # Get active user sessions as baseline reference
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: initialSessions}) => {
|
||||
const initialSession = initialSessions[0];
|
||||
|
||||
// Post a message to a channel
|
||||
cy.postMessage(`${Date.now()}`);
|
||||
|
||||
// Elapsed time of 1.1% or a bit above 1.00%
|
||||
const elapsedAboveThreshold = parseDateTime(initialSession.expiresat) - (testCase.sessionLengthInHours * oneDay * 0.011);
|
||||
|
||||
// # Update the user session with new expiration to simulate that
|
||||
// # the session has elapsed just above 1% of session length.
|
||||
cy.dbUpdateUserSession({
|
||||
userId: initialSession.userid,
|
||||
sessionId: initialSession.id,
|
||||
fieldsToUpdate: {expiresat: elapsedAboveThreshold},
|
||||
}).then(({session: updatedSession}) => {
|
||||
// * Verify that the session is updated
|
||||
expect(parseDateTime(updatedSession.expiresat)).to.equal(elapsedAboveThreshold);
|
||||
|
||||
// # Invalidate cache and reload to take effect the new session
|
||||
cy.externalRequest({user: admin, method: 'POST', path: 'caches/invalidate'});
|
||||
cy.reload();
|
||||
|
||||
// # Visit a channel or post a message
|
||||
const now = Date.now();
|
||||
testCase.fn(now);
|
||||
|
||||
// * Get active session of test user and verify that the session has been extended depending on SessionLengthWebInHours setting
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: extendedSessions}) => {
|
||||
expect(extendedSessions[0].id).to.equal(updatedSession.id);
|
||||
expect(parseDateTime(extendedSessions[0].expiresat)).to.be.greaterThan(parseDateTime(updatedSession.expiresat));
|
||||
const twentySeconds = 20000;
|
||||
expect(parseDateTime(extendedSessions[0].expiresat)).to.be.closeTo(new Date().setHours(new Date().getHours() + testCase.sessionLengthInHours), twentySeconds);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function parseDateTime(value: string) {
|
||||
return parseInt(value, 10);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {getAdminAccount} from '../../../../../support/env';
|
||||
import * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
|
||||
const admin = getAdminAccount();
|
||||
const oneDay = 24 * 60 * 60 * 1000;
|
||||
const thirtySeconds = 30 * 1000;
|
||||
|
||||
export function verifyExtendedSession(testUser, sessionLengthInDays, channelUrl) {
|
||||
// # Login as test user and visit default channel
|
||||
cy.visit(channelUrl);
|
||||
|
||||
// # Get active user sessions as baseline reference
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: initialSessions}) => {
|
||||
expect(initialSessions.length).to.equal(1);
|
||||
const initialSession = initialSessions[0];
|
||||
|
||||
// # Post a message to a channel
|
||||
const now = Date.now();
|
||||
cy.postMessage(now);
|
||||
|
||||
// # Update user session which is to expire 20 sec from now
|
||||
const soonToExpire = getExpirationFromNow(thirtySeconds);
|
||||
cy.dbUpdateUserSession({
|
||||
userId: initialSession.userid,
|
||||
sessionId: initialSession.id,
|
||||
fieldsToUpdate: {expiresat: soonToExpire},
|
||||
}).then(({session: updatedSession}) => {
|
||||
// * Verify that the session is updated
|
||||
expect(parseInt(updatedSession.expiresat, 10)).to.equal(soonToExpire);
|
||||
|
||||
// # Invalidate cache and reload to take effect the soon to expire session
|
||||
cy.externalRequest({user: admin, method: 'POST', path: 'caches/invalidate'});
|
||||
cy.reload();
|
||||
|
||||
// # Visit default channel
|
||||
cy.visit(channelUrl);
|
||||
|
||||
// # Get active session of test user
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: extendedSessions}) => {
|
||||
expect(extendedSessions.length).to.equal(1);
|
||||
const extendedSession = extendedSessions[0];
|
||||
|
||||
// * Verify that the session has been extended depending on session length (in days) setting
|
||||
expect(extendedSession.id).to.equal(updatedSession.id);
|
||||
expect(parseInt(extendedSession.expiresat, 10)).to.be.greaterThan(parseInt(updatedSession.expiresat, 10));
|
||||
expect(parseInt(extendedSession.expiresat, 10)).to.be.greaterThan(parseInt(initialSession.expiresat, 10));
|
||||
|
||||
expect(parseInt(extendedSession.expiresat, 10)).to.be.closeTo(now + (sessionLengthInDays * oneDay * 0.042), thirtySeconds);
|
||||
});
|
||||
|
||||
// # Post multiple times to check that the session continues and doesn't redirect to login page
|
||||
Cypress._.times(20, (i) => {
|
||||
cy.postMessage(i);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function verifyNotExtendedSession(testUser, channelUrl) {
|
||||
// # Login as test user and visit default channel
|
||||
cy.visit(channelUrl);
|
||||
|
||||
// # Get active user sessions as baseline reference
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: initialSessions}) => {
|
||||
expect(initialSessions.length).to.equal(1);
|
||||
const initialSession = initialSessions[0];
|
||||
expect(parseInt(initialSession.expiresat, 10)).to.be.greaterThan(0);
|
||||
|
||||
// # Post a message to a channel
|
||||
const now = Date.now();
|
||||
cy.postMessage(`now: ${now}`);
|
||||
|
||||
// # Update user session which is to expire 20 sec from now
|
||||
const soonToExpire = getExpirationFromNow(thirtySeconds);
|
||||
cy.dbUpdateUserSession({
|
||||
userId: initialSession.userid,
|
||||
sessionId: initialSession.id,
|
||||
fieldsToUpdate: {expiresat: soonToExpire},
|
||||
}).then(({session: updatedSession}) => {
|
||||
// * Verify that the session is updated
|
||||
expect(parseInt(updatedSession.expiresat, 10)).to.equal(soonToExpire);
|
||||
|
||||
// # Invalidate cache and reload to take effect the soon to expire session
|
||||
cy.externalRequest({user: admin, method: 'POST', path: 'caches/invalidate'});
|
||||
cy.reload();
|
||||
|
||||
// # Visit default channel
|
||||
cy.visit(channelUrl);
|
||||
|
||||
// # Get active session of test user
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: soonToExpireSessions}) => {
|
||||
// * Verify that the session was not extended
|
||||
expect(soonToExpireSessions.length).to.equal(1);
|
||||
expect(soonToExpireSessions[0].id).to.equal(updatedSession.id);
|
||||
expect(parseInt(soonToExpireSessions[0].expiresat, 10)).to.equal(parseInt(updatedSession.expiresat, 10));
|
||||
|
||||
// * Verify that it redirects to login page due to expired session
|
||||
cy.waitUntil(() => {
|
||||
return cy.url().then((url) => {
|
||||
return url.includes('/login');
|
||||
});
|
||||
}, {
|
||||
timeout: TIMEOUTS.TWO_MIN,
|
||||
interval: TIMEOUTS.TWO_SEC,
|
||||
});
|
||||
|
||||
// * Verify that user has no active session
|
||||
cy.dbGetActiveUserSessions({username: testUser.username}).then(({sessions: activeSessions}) => {
|
||||
expect(activeSessions.length).to.equal(0);
|
||||
});
|
||||
|
||||
// * Verify that the session has not been extended
|
||||
cy.dbGetUserSession({sessionId: initialSession.id}).then(({session: unExtendedSession}) => {
|
||||
expect(parseInt(unExtendedSession.expiresat, 10)).to.equal(soonToExpire);
|
||||
expect(parseInt(unExtendedSession.expiresat, 10)).to.be.lessThan(Date.now());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getExpirationFromNow(duration = 0) {
|
||||
return Date.now() + duration;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// 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 @extend_session
|
||||
|
||||
import {verifyExtendedSession, verifyNotExtendedSession} from './helpers';
|
||||
|
||||
describe('Extended Session Length', () => {
|
||||
const sessionLengthInHours = 1;
|
||||
const setting = {
|
||||
ServiceSettings: {
|
||||
SessionLengthWebInHours: sessionLengthInHours,
|
||||
},
|
||||
};
|
||||
let emailUser;
|
||||
let offTopicUrl;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
cy.apiRequireLicense();
|
||||
|
||||
// * Server database should match with the DB client and config at "cypress.json"
|
||||
cy.apiRequireServerDBToMatch();
|
||||
|
||||
cy.apiInitSetup().then(({user, offTopicUrl: url}) => {
|
||||
emailUser = user;
|
||||
offTopicUrl = url;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
cy.apiRevokeUserSessions(emailUser.id);
|
||||
});
|
||||
|
||||
it('MM-T4045_1 Email user session should have extended due to user activity when enabled', () => {
|
||||
// # Enable ExtendSessionLengthWithActivity
|
||||
setting.ServiceSettings.ExtendSessionLengthWithActivity = true;
|
||||
cy.apiUpdateConfig(setting);
|
||||
|
||||
cy.apiLogin(emailUser);
|
||||
verifyExtendedSession(emailUser, sessionLengthInHours, offTopicUrl);
|
||||
});
|
||||
|
||||
it('MM-T4045_2 Email user session should not extend even with user activity when disabled', () => {
|
||||
// # Disable ExtendSessionLengthWithActivity
|
||||
setting.ServiceSettings.ExtendSessionLengthWithActivity = false;
|
||||
cy.apiUpdateConfig(setting);
|
||||
|
||||
cy.apiLogin(emailUser);
|
||||
verifyNotExtendedSession(emailUser, offTopicUrl);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
// 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 @extend_session @ldap
|
||||
|
||||
import ldapUsers from '../../../../../fixtures/ldap_users.json';
|
||||
|
||||
import {verifyExtendedSession, verifyNotExtendedSession} from './helpers';
|
||||
|
||||
describe('Extended Session Length', () => {
|
||||
const sessionLengthInHours = 1;
|
||||
const setting = {
|
||||
ServiceSettings: {
|
||||
SessionLengthWebInHours: sessionLengthInHours,
|
||||
},
|
||||
};
|
||||
let testLdapUser;
|
||||
let offTopicUrl;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
cy.apiRequireLicense();
|
||||
|
||||
// * Server database should match with the DB client and config at "cypress.json"
|
||||
cy.apiRequireServerDBToMatch();
|
||||
|
||||
const ldapUser = ldapUsers['test-1'];
|
||||
cy.apiSyncLDAPUser({ldapUser}).then((user) => {
|
||||
testLdapUser = user;
|
||||
});
|
||||
|
||||
cy.apiInitSetup().then(({team, offTopicUrl: url}) => {
|
||||
offTopicUrl = url;
|
||||
cy.apiAddUserToTeam(team.id, testLdapUser.id);
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
cy.apiRevokeUserSessions(testLdapUser.id);
|
||||
});
|
||||
|
||||
it('MM-T4046_1 LDAP user session should have extended due to user activity when enabled', () => {
|
||||
// # Enable ExtendSessionLengthWithActivity
|
||||
setting.ServiceSettings.ExtendSessionLengthWithActivity = true;
|
||||
cy.apiUpdateConfig(setting);
|
||||
|
||||
cy.apiLogin(testLdapUser);
|
||||
verifyExtendedSession(testLdapUser, sessionLengthInHours, offTopicUrl);
|
||||
});
|
||||
|
||||
it('MM-T4046_2 LDAP user session should not extend even with user activity when disabled', () => {
|
||||
// # Disable ExtendSessionLengthWithActivity
|
||||
setting.ServiceSettings.ExtendSessionLengthWithActivity = false;
|
||||
cy.apiUpdateConfig(setting);
|
||||
|
||||
cy.apiLogin(testLdapUser);
|
||||
verifyNotExtendedSession(testLdapUser, offTopicUrl);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
// 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.
|
||||
// ***************************************************************
|
||||
|
||||
// - Requires openldap and keycloak running
|
||||
// - Requires keycloak certificate at fixtures folder
|
||||
// -> copy ./mattermost-server/build/docker/keycloak/keycloak.crt to ./mattermost-webapp/e2e/cypress/tests/fixtures/keycloak.crt
|
||||
// - Requires Cypress' chromeWebSecurity to be false
|
||||
|
||||
// Group: @channels @enterprise @not_cloud @extend_session @ldap @saml @keycloak
|
||||
|
||||
import {getKeycloakServerSettings} from '../../../../../utils/config';
|
||||
|
||||
import {verifyExtendedSession, verifyNotExtendedSession} from './helpers';
|
||||
|
||||
describe('Extended Session Length', () => {
|
||||
const sessionLengthInDays = 1;
|
||||
const samlConfig = getKeycloakServerSettings();
|
||||
const sessionConfig = {
|
||||
ServiceSettings: {
|
||||
SessionLengthSSOInDays: sessionLengthInDays,
|
||||
},
|
||||
};
|
||||
|
||||
let testTeamId;
|
||||
let testSamlUser;
|
||||
let offTopicUrl;
|
||||
let samlLdapUser;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
cy.apiRequireLicenseForFeature('LDAP', 'SAML');
|
||||
|
||||
// * Server database should match with the DB client and config at "cypress.json"
|
||||
cy.apiRequireServerDBToMatch();
|
||||
|
||||
// # Create new LDAP user
|
||||
cy.createLDAPUser().then((user) => {
|
||||
samlLdapUser = user;
|
||||
});
|
||||
|
||||
// # Create new team
|
||||
cy.apiCreateTeam('saml-team', 'SAML Team').then(({team}) => {
|
||||
testTeamId = team.id;
|
||||
offTopicUrl = `/${team.name}/channels/off-topic`;
|
||||
});
|
||||
|
||||
cy.apiUpdateConfig(samlConfig).then(() => {
|
||||
// # Require keycloak with realm setup
|
||||
cy.apiRequireKeycloak();
|
||||
|
||||
// # Upload certificate, overwrite existing
|
||||
cy.apiUploadSAMLIDPCert('keycloak.crt');
|
||||
|
||||
// # Create Keycloak user and login for the first time
|
||||
cy.keycloakCreateUsers([samlLdapUser]);
|
||||
cy.doKeycloakLogin(samlLdapUser);
|
||||
|
||||
// # Wait for the UI to be ready which indicates SAML registration is complete
|
||||
cy.findByText('Logout').click();
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
cy.apiGetUserByEmail(samlLdapUser.email).then(({user}) => {
|
||||
testSamlUser = user;
|
||||
cy.apiAddUserToTeam(testTeamId, user.id);
|
||||
cy.apiRevokeUserSessions(user.id);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4047_1 SAML/SSO user session should have extended due to user activity when enabled', () => {
|
||||
// # Enable ExtendSessionLengthWithActivity
|
||||
sessionConfig.ServiceSettings.ExtendSessionLengthWithActivity = true;
|
||||
cy.apiUpdateConfig({...samlConfig, ...sessionConfig});
|
||||
|
||||
// # Login via Keycloak
|
||||
cy.doKeycloakLogin(samlLdapUser);
|
||||
cy.postMessage('hello');
|
||||
|
||||
// # Verify session is extended
|
||||
verifyExtendedSession(testSamlUser, sessionLengthInDays, offTopicUrl);
|
||||
});
|
||||
|
||||
it('MM-T4047_2 SAML/SSO user session should not extend even with user activity when disabled', () => {
|
||||
// # Disable ExtendSessionLengthWithActivity
|
||||
sessionConfig.ServiceSettings.ExtendSessionLengthWithActivity = false;
|
||||
cy.apiUpdateConfig({...samlConfig, ...sessionConfig});
|
||||
|
||||
// # Login via Keycloak
|
||||
cy.doKeycloakLogin(samlLdapUser);
|
||||
cy.postMessage('hello');
|
||||
|
||||
// # Verify session is not extended
|
||||
verifyNotExtendedSession(testSamlUser, offTopicUrl);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,128 @@
|
||||
// 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
|
||||
|
||||
// # Goes to the System Scheme page as System Admin
|
||||
const goToSessionLengths = () => {
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/environment/session_lengths');
|
||||
};
|
||||
|
||||
// # 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
|
||||
const saveConfig = (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();
|
||||
}
|
||||
};
|
||||
|
||||
describe('MM-T2574 Session Lengths', () => {
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
cy.apiRequireLicense();
|
||||
goToSessionLengths();
|
||||
});
|
||||
|
||||
describe('"Extend session length with activity" defaults to true', () => {
|
||||
it('"Extend session length with activity" radio is checked', () => {
|
||||
cy.get('#extendSessionLengthWithActivitytrue').check().should('be.checked');
|
||||
});
|
||||
it('"Session idle timeout" setting should not exist', () => {
|
||||
cy.get('#sessionIdleTimeoutInMinutes').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Setting "Extend session length with activity" to false alters subsequent settings', () => {
|
||||
before(() => cy.get('#extendSessionLengthWithActivityfalse').check());
|
||||
it('In enterprise edition, "Session idle timeout" setting should exist on page', () => {
|
||||
cy.get('#sessionIdleTimeoutInMinutes').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Session Lengths settings should save successfully', () => {
|
||||
before(() => cy.get('#extendSessionLengthWithActivityfalse').check());
|
||||
it('Setting "Session Idle Timeout (minutes)" should save in UI', () => {
|
||||
cy.get('#sessionIdleTimeoutInMinutes').
|
||||
should('have.value', '43200').
|
||||
clear().type('43201');
|
||||
saveConfig();
|
||||
cy.get('#sessionIdleTimeoutInMinutes').should('have.value', '43201');
|
||||
});
|
||||
it('Setting "Session Cache (minutes)" should be saved in the server configuration', () => {
|
||||
cy.apiGetConfig().then(({config}) => {
|
||||
const setting = config.ServiceSettings.SessionIdleTimeoutInMinutes;
|
||||
expect(setting).to.equal(43201);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should match help text', () => {
|
||||
const helpText = {
|
||||
extendSessionLengthWithActivity: {
|
||||
false: 'When true, sessions will be automatically extended when the user is active in their Mattermost client. Users sessions will only expire if they are not active in their Mattermost client for the entire duration of the session lengths defined in the fields below. When false, sessions will not extend with activity in Mattermost. User sessions will immediately expire at the end of the session length or idle timeouts defined below. ',
|
||||
true: 'When true, sessions will be automatically extended when the user is active in their Mattermost client. Users sessions will only expire if they are not active in their Mattermost client for the entire duration of the session lengths defined in the fields below. When false, sessions will not extend with activity in Mattermost. User sessions will immediately expire at the end of the session length or idle timeouts defined below. ',
|
||||
},
|
||||
sessionLengthWebInHours: {
|
||||
false: 'The number of hours from the last time a user entered their credentials to the expiry of the user\'s session. After changing this setting, the new session length will take effect after the next time the user enters their credentials.',
|
||||
true: 'Set the number of hours from the last activity in Mattermost to the expiry of the user’s session when using email and AD/LDAP authentication. After changing this setting, the new session length will take effect after the next time the user enters their credentials.',
|
||||
},
|
||||
sessionLengthMobileInHours: {
|
||||
false: 'The number of hours from the last time a user entered their credentials to the expiry of the user\'s session. After changing this setting, the new session length will take effect after the next time the user enters their credentials.',
|
||||
true: 'Set the number of hours from the last activity in Mattermost to the expiry of the user’s session on mobile. After changing this setting, the new session length will take effect after the next time the user enters their credentials.',
|
||||
},
|
||||
sessionLengthSSOInHours: {
|
||||
false: 'The number of hours from the last time a user entered their credentials to the expiry of the user\'s session. If the authentication method is SAML or GitLab, the user may automatically be logged back in to Mattermost if they are already logged in to SAML or GitLab. After changing this setting, the setting will take effect after the next time the user enters their credentials.',
|
||||
true: 'Set the number of hours from the last activity in Mattermost to the expiry of the user’s session for SSO authentication, such as SAML, GitLab and OAuth 2.0. If the authentication method is SAML or GitLab, the user may automatically be logged back in to Mattermost if they are already logged in to SAML or GitLab. After changing this setting, the setting will take effect after the next time the user enters their credentials.',
|
||||
},
|
||||
sessionCacheInMinutes: {
|
||||
false: 'The number of minutes to cache a session in memory.',
|
||||
true: 'The number of minutes to cache a session in memory.',
|
||||
},
|
||||
sessionIdleTimeoutInMinutes: {
|
||||
false: 'The number of minutes from the last time a user was active on the system to the expiry of the user\'s session. Once expired, the user will need to log in to continue. Minimum is 5 minutes, and 0 is unlimited.Applies to the desktop app and browsers. For mobile apps, use an EMM provider to lock the app when not in use. In High Availability mode, enable IP hash load balancing for reliable timeout measurement.',
|
||||
true: false,
|
||||
},
|
||||
};
|
||||
|
||||
cy.get('#extendSessionLengthWithActivityfalse').check();
|
||||
Object.entries(helpText).forEach(([key, value]) => {
|
||||
cy.findByTestId(key).should('exist');
|
||||
cy.findByTestId(`${key}help-text`).should('have.text', value.false);
|
||||
});
|
||||
|
||||
cy.get('#extendSessionLengthWithActivitytrue').check();
|
||||
Object.entries(helpText).forEach(([key, value]) => {
|
||||
if (value.true) {
|
||||
cy.findByTestId(key).should('exist');
|
||||
cy.findByTestId(`${key}help-text`).should('have.text', value.true);
|
||||
} else {
|
||||
cy.findByTestId(key).should('not.exist');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,345 @@
|
||||
// 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 @group_mentions
|
||||
|
||||
import ldapUsers from '../../../../fixtures/ldap_users.json';
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
import {
|
||||
disablePermission,
|
||||
enablePermission,
|
||||
} from '../system_console/channel_moderation/helpers';
|
||||
|
||||
import {enableGroupMention} from './helpers';
|
||||
|
||||
describe('Group Mentions', () => {
|
||||
let groupID;
|
||||
let boardUser;
|
||||
let regularUser;
|
||||
let testTeam;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP Groups
|
||||
cy.apiRequireLicenseForFeature('LDAPGroups');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
regularUser = user;
|
||||
testTeam = team;
|
||||
});
|
||||
|
||||
// # Test LDAP configuration and server connection
|
||||
// # Synchronize user attributes
|
||||
cy.apiLDAPTest();
|
||||
cy.apiLDAPSync();
|
||||
|
||||
// # Link the LDAP Group - board
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#board_group', {timeout: TIMEOUTS.ONE_MIN}).then((el) => {
|
||||
if (!el.text().includes('Edit')) {
|
||||
// # Link the Group if its not linked before
|
||||
if (el.find('.icon.fa-unlink').length > 0) {
|
||||
el.find('.icon.fa-unlink').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// # Get board group id
|
||||
cy.apiGetGroups().then((res) => {
|
||||
res.body.forEach((group) => {
|
||||
if (group.display_name === 'board') {
|
||||
// # Set groupID to navigate to group page directly
|
||||
groupID = group.id;
|
||||
|
||||
// # Set allow reference false to ensure correct data for test cases
|
||||
cy.apiPatchGroup(groupID, {allow_reference: false});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// # Login once as board user to ensure the user is created in the system
|
||||
boardUser = ldapUsers['board-1'];
|
||||
cy.apiLogin(boardUser);
|
||||
|
||||
// # Login as sysadmin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Add board user to test team to ensure that it exists in the team and set its preferences to skip tutorial step
|
||||
cy.apiGetUserByEmail(boardUser.email).then(({user}) => {
|
||||
cy.apiGetChannelByName(testTeam.name, 'town-square').then(({channel}) => {
|
||||
cy.apiAddUserToTeam(testTeam.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiSaveTutorialStep(user.id, '999');
|
||||
});
|
||||
});
|
||||
|
||||
after(() => {
|
||||
// # Login as sysadmin and navigate to system scheme page
|
||||
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');
|
||||
|
||||
// # Click reset to defaults and confirm
|
||||
cy.findByTestId('resetPermissionsToDefault').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
|
||||
// # Save
|
||||
cy.uiSaveConfig();
|
||||
});
|
||||
|
||||
it('MM-T2450 - Group Mentions when user is a Channel Admin', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID, boardUser.email);
|
||||
|
||||
// # Disable Group Mentions for All Users & Channel Admins
|
||||
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');
|
||||
disablePermission('all_users-posts-use_group_mentions-checkbox');
|
||||
disablePermission('channel_admin-posts-use_group_mentions-checkbox');
|
||||
cy.uiSaveConfig();
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(regularUser);
|
||||
|
||||
// # Create a new channel so that regular user can be channel admin
|
||||
cy.apiCreateChannel(testTeam.id, 'group-mention', 'Group Mentions').then(({channel}) => {
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Type the Group Name
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}`).wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify if autocomplete dropdown is not displayed
|
||||
cy.get('#suggestionList').should('not.exist');
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} hello`);
|
||||
|
||||
// * Verify if a system message is not displayed
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${groupName}`);
|
||||
|
||||
// * Verify that the group mention is not highlighted
|
||||
cy.get(`#postMessageText_${postId}`).find('.mention--highlight').should('not.exist');
|
||||
|
||||
// * Verify that the group mention does not has blue colored text
|
||||
cy.get(`#postMessageText_${postId}`).find('.group-mention-link').should('not.exist');
|
||||
});
|
||||
|
||||
// # Enable Group Mentions for Channel Admins
|
||||
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');
|
||||
enablePermission('channel_admin-posts-use_group_mentions-checkbox');
|
||||
cy.uiSaveConfig();
|
||||
|
||||
// # Login as a regular user and visit the channel
|
||||
cy.apiLogin(regularUser);
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Type the Group Name
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}`).wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify if autocomplete dropdown is displayed
|
||||
cy.get('#suggestionList').should('be.visible').children().within((el) => {
|
||||
cy.wrap(el).eq(0).should('contain', 'Group Mentions');
|
||||
cy.wrap(el).eq(1).should('contain', groupName);
|
||||
});
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} hello`);
|
||||
|
||||
// * Verify if a system message is displayed
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${boardUser.username} did not get notified by this mention because they are not in the channel. Would you like to add them to the channel? They will have access to all message history.`);
|
||||
|
||||
// * Verify if an option should be given to add them to channel
|
||||
cy.get('a.PostBody_addChannelMemberLink').should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2451 - Group Mentions when user is a Team Admin', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID, boardUser.email);
|
||||
|
||||
// # Disable Group Mentions for All Users & Channel Admins & Team Admins
|
||||
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');
|
||||
disablePermission('all_users-posts-use_group_mentions-checkbox');
|
||||
disablePermission('channel_admin-posts-use_group_mentions-checkbox');
|
||||
disablePermission('team_admin-posts-use_group_mentions-checkbox');
|
||||
cy.uiSaveConfig();
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(regularUser);
|
||||
|
||||
// # Create a new team and channel so that regular user can be team admin
|
||||
cy.apiCreateTeam('team', 'Test NoMember').then(({team}) => {
|
||||
cy.apiCreateChannel(team.id, 'group-mention', 'Group Mentions').then(({channel}) => {
|
||||
// # Visit the channel
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # Type the Group Name
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}`).wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify if autocomplete dropdown is not displayed
|
||||
cy.get('#suggestionList').should('not.exist');
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} hello`);
|
||||
|
||||
// * Verify if a system message is not displayed
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${groupName}`);
|
||||
|
||||
// * Verify that the group mention is not highlighted
|
||||
cy.get(`#postMessageText_${postId}`).find('.mention--highlight').should('not.exist');
|
||||
|
||||
// * Verify that the group mention does not has blue colored text
|
||||
cy.get(`#postMessageText_${postId}`).find('.group-mention-link').should('not.exist');
|
||||
});
|
||||
|
||||
// # Enable Group Mentions for Team Admins
|
||||
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');
|
||||
enablePermission('team_admin-posts-use_group_mentions-checkbox');
|
||||
cy.uiSaveConfig();
|
||||
|
||||
// # Login as a regular user and visit the channel
|
||||
cy.apiLogin(regularUser);
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # Type the Group Name
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}`).wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify if autocomplete dropdown is displayed
|
||||
cy.get('#suggestionList').should('be.visible').children().within((el) => {
|
||||
cy.wrap(el).eq(0).should('contain', 'Group Mentions');
|
||||
cy.wrap(el).eq(1).should('contain', groupName);
|
||||
});
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} hello`);
|
||||
|
||||
// * Verify if a system message is displayed
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${groupName} has no members on this team`);
|
||||
|
||||
// * Verify that the group mention is not highlighted
|
||||
cy.get(`#postMessageText_${postId}`).find('.mention--highlight').should('not.exist');
|
||||
|
||||
// * Verify that the group mention has blue colored text
|
||||
cy.get(`#postMessageText_${postId}`).find('.group-mention-link').should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2452 - Group Mentions when user is a Guest User', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID, boardUser.email);
|
||||
|
||||
// # Verify that group mentions for all users & guests are disabled
|
||||
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');
|
||||
cy.findByTestId('all_users-posts-use_group_mentions-checkbox').should('not.have.class', 'checked');
|
||||
cy.findByTestId('guests-guest_use_group_mentions-checkbox').should('not.have.class', 'checked');
|
||||
|
||||
// # Create a new channel as a sysadmin
|
||||
cy.apiCreateChannel(testTeam.id, 'group-mention', 'Group Mentions').then(({channel}) => {
|
||||
cy.apiCreateUser().then(({user}) => { // eslint-disable-line
|
||||
// # Add user to the team and channel
|
||||
cy.apiAddUserToTeam(testTeam.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
|
||||
// # Demote the user as a guest user
|
||||
cy.apiDemoteUserToGuest(user.id);
|
||||
|
||||
// # Login as a guest user
|
||||
cy.apiLogin(user);
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Type the Group Name
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}`).wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify if autocomplete dropdown is not displayed
|
||||
cy.get('#suggestionList').should('not.exist');
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} hello`);
|
||||
|
||||
// * Verify if a system message is not displayed
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${groupName}`);
|
||||
|
||||
// * Verify that the group mention is not highlighted
|
||||
cy.get(`#postMessageText_${postId}`).find('.mention--highlight').should('not.exist');
|
||||
|
||||
// * Verify that the group mention does not has blue colored text
|
||||
cy.get(`#postMessageText_${postId}`).find('.group-mention-link').should('not.exist');
|
||||
});
|
||||
|
||||
// # Login as sysadmin and enable group mentions permission for guests
|
||||
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');
|
||||
enablePermission('guests-guest_use_group_mentions-checkbox');
|
||||
cy.uiSaveConfig();
|
||||
|
||||
// # Login as guest user again and visit the channel
|
||||
cy.apiLogin(user);
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Type the Group Name
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}`).wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify if autocomplete dropdown is displayed
|
||||
cy.get('#suggestionList').should('be.visible').children().within((el) => {
|
||||
cy.wrap(el).eq(0).should('contain', 'Group Mentions');
|
||||
cy.wrap(el).eq(1).should('contain', groupName);
|
||||
});
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} hello`);
|
||||
|
||||
// * Verify if a system message is displayed
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${boardUser.username} did not get notified by this mention because they are not in the channel.`);
|
||||
|
||||
// * Verify that the option to add them to channel is not given
|
||||
cy.get('a.PostBody_addChannelMemberLink').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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.
|
||||
// ***************************************************************
|
||||
|
||||
// Group: @channels @enterprise @system_console @group_mentions
|
||||
|
||||
import ldapUsers from '../../../../fixtures/ldap_users.json';
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
import {enableGroupMention} from './helpers';
|
||||
|
||||
describe('Group Mentions', () => {
|
||||
let groupID1;
|
||||
let groupID2;
|
||||
let boardUser;
|
||||
let regularUser;
|
||||
let testTeam;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP Groups
|
||||
cy.apiRequireLicenseForFeature('LDAPGroups');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
regularUser = user;
|
||||
testTeam = team;
|
||||
});
|
||||
|
||||
// # Test LDAP configuration and server connection
|
||||
// # Synchronize user attributes
|
||||
cy.apiLDAPTest();
|
||||
cy.apiLDAPSync();
|
||||
|
||||
// # Link the LDAP Group - board
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#board_group', {timeout: TIMEOUTS.ONE_MIN}).then((el) => {
|
||||
if (!el.text().includes('Edit')) {
|
||||
// # Link the Group if its not linked before
|
||||
if (el.find('.icon.fa-unlink').length > 0) {
|
||||
el.find('.icon.fa-unlink').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// # Link the LDAP Group - developers
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#developers_group', {timeout: TIMEOUTS.ONE_MIN}).then((el) => {
|
||||
if (!el.text().includes('Edit')) {
|
||||
// # Link the Group if its not linked before
|
||||
if (el.find('.icon.fa-unlink').length > 0) {
|
||||
el.find('.icon.fa-unlink').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// # Get board group id
|
||||
cy.apiGetGroups().then((res) => {
|
||||
res.body.forEach((group) => {
|
||||
if (group.display_name === 'board') {
|
||||
// # Set groupID1 to navigate to group page directly
|
||||
groupID1 = group.id;
|
||||
|
||||
// # Set allow reference false to ensure correct data for test cases
|
||||
cy.apiPatchGroup(group.id, {allow_reference: false});
|
||||
}
|
||||
|
||||
if (group.display_name === 'developers') {
|
||||
// # Set groupID1 to navigate to group page directly
|
||||
groupID2 = group.id;
|
||||
|
||||
// # Set allow reference false to ensure correct data for test cases
|
||||
cy.apiPatchGroup(group.id, {allow_reference: false});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// # Login once as board user to ensure the user is created in the system
|
||||
boardUser = ldapUsers['board-1'];
|
||||
cy.apiLogin(boardUser);
|
||||
|
||||
// # Login as sysadmin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Add board user to test team to ensure that it exists in the team and set its preferences to skip tutorial step
|
||||
cy.apiGetUserByEmail(boardUser.email).then(({user}) => {
|
||||
cy.apiGetChannelByName(testTeam.name, 'town-square').then(({channel}) => {
|
||||
cy.apiAddUserToTeam(testTeam.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiSaveTutorialStep(user.id, '999');
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Login as sysadmin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Enable Group Mention for the group - board
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#board_group', {timeout: TIMEOUTS.ONE_MIN}).then((el) => {
|
||||
if (!el.text().includes('Edit')) {
|
||||
// # Link the Group if its not linked before
|
||||
if (el.find('.icon.fa-unlink').length > 0) {
|
||||
el.find('.icon.fa-unlink').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2447 - Group Mentions when group was unlinked', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID1);
|
||||
|
||||
// # Unlink the group
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#board_group', {timeout: TIMEOUTS.ONE_MIN}).then((el) => {
|
||||
el.find('.icon.fa-link').click();
|
||||
});
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(regularUser);
|
||||
|
||||
// # Create a new channel as a regular user
|
||||
cy.apiCreateChannel(testTeam.id, 'group-mention', 'Group Mentions').then(({channel}) => {
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
cy.uiGetPostTextBox();
|
||||
|
||||
// # Type the Group Name to check if Autocomplete dropdown is not displayed
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}`).wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify if autocomplete dropdown is not displayed
|
||||
cy.get('#suggestionList').should('not.exist');
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} `);
|
||||
|
||||
// * Verify if a system message is not displayed
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${groupName}`);
|
||||
|
||||
// * Verify that the group mention is not highlighted
|
||||
cy.get(`#postMessageText_${postId}`).find('.mention--highlight').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2460 - Group Mentions when used in Direct Message', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID1);
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(regularUser);
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
cy.uiGetPostTextBox();
|
||||
|
||||
// # Trigger DM with a user
|
||||
cy.uiAddDirectMessage().click();
|
||||
cy.get('.more-modal__row.clickable').first().click();
|
||||
cy.uiGetButton('Go').click();
|
||||
|
||||
// # Type the Group Name to check if Autocomplete dropdown is displayed
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}`).wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify if autocomplete dropdown is displayed
|
||||
cy.get('#suggestionList').should('be.visible').children().within((el) => {
|
||||
cy.wrap(el).eq(0).should('contain', 'Group Mentions');
|
||||
cy.wrap(el).eq(1).should('contain', groupName);
|
||||
});
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} `);
|
||||
|
||||
// * Verify if a system message is not displayed
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${groupName}`);
|
||||
|
||||
// * Verify that the group mention is not highlighted
|
||||
cy.get(`#postMessageText_${postId}`).find('.mention--highlight').should('not.exist');
|
||||
|
||||
// * Verify that the group mention has blue colored text
|
||||
cy.get(`#postMessageText_${postId}`).find('.group-mention-link').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2461 - Group Mentions when used in Group Message', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID1);
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(regularUser);
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
cy.uiGetPostTextBox();
|
||||
|
||||
// # Trigger DM with couple of users
|
||||
cy.uiAddDirectMessage().click();
|
||||
cy.get('.more-modal__row.clickable').first().click();
|
||||
cy.uiGetButton('Go').click();
|
||||
|
||||
// # Type the Group Name to check if Autocomplete dropdown is displayed
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}`).wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify if autocomplete dropdown is displayed
|
||||
cy.get('#suggestionList').should('be.visible').children().within((el) => {
|
||||
cy.wrap(el).eq(0).should('contain', 'Group Mentions');
|
||||
cy.wrap(el).eq(1).should('contain', groupName);
|
||||
});
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} `);
|
||||
|
||||
// * Verify if a system message is not displayed
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${groupName}`);
|
||||
|
||||
// * Verify that the group mention is not highlighted
|
||||
cy.get(`#postMessageText_${postId}`).find('.mention--highlight').should('not.exist');
|
||||
|
||||
// * Verify that the group mention has blue colored text
|
||||
cy.get(`#postMessageText_${postId}`).find('.group-mention-link').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2443 - Group Mentions when Channel is Group Synced', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
const groupName2 = `developers_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID1);
|
||||
enableGroupMention(groupName2, groupID2);
|
||||
|
||||
// # Create a new channel as a regular user
|
||||
cy.apiCreateChannel(testTeam.id, 'group-mention-2', 'Group Mentions 2').then(({channel}) => {
|
||||
// # Link the group and the channel.
|
||||
cy.apiLinkGroupChannel(groupID1, channel.id);
|
||||
|
||||
cy.apiLogin({username: 'board.one', password: 'Password1'}).then(({user: boardOne}) => {
|
||||
cy.apiAddUserToChannel(channel.id, boardOne.id);
|
||||
|
||||
// # Make the channel private and group-synced.
|
||||
cy.apiPatchChannel(channel.id, {group_constrained: true, type: 'P'});
|
||||
|
||||
// # Login to create the dev user
|
||||
cy.apiLogin({username: 'dev.one', password: 'Password1'}).then(({user: devOne}) => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
cy.apiAddUserToTeam(testTeam.id, devOne.id);
|
||||
|
||||
cy.apiLogin({username: 'board.one', password: 'Password1'});
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
cy.uiGetPostTextBox();
|
||||
|
||||
cy.postMessage(`@${groupName2} `);
|
||||
|
||||
// * Verify if a system message is not displayed
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${groupName2}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,246 @@
|
||||
// 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 @group_mentions
|
||||
|
||||
import ldapUsers from '../../../../fixtures/ldap_users.json';
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
import {
|
||||
disablePermission,
|
||||
enablePermission,
|
||||
saveConfigForChannel,
|
||||
visitChannelConfigPage,
|
||||
} from '../system_console/channel_moderation/helpers';
|
||||
import {checkboxesTitleToIdMap} from '../system_console/channel_moderation/constants';
|
||||
|
||||
import {enableGroupMention} from './helpers';
|
||||
|
||||
describe('Group Mentions', () => {
|
||||
let groupID;
|
||||
let boardUser;
|
||||
let regularUser;
|
||||
let testTeam;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP Groups
|
||||
cy.apiRequireLicenseForFeature('LDAPGroups');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
regularUser = user;
|
||||
testTeam = team;
|
||||
});
|
||||
|
||||
// # Test LDAP configuration and server connection
|
||||
// # Synchronize user attributes
|
||||
cy.apiLDAPTest();
|
||||
cy.apiLDAPSync();
|
||||
|
||||
// # Link the group - board
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#board_group', {timeout: TIMEOUTS.ONE_MIN}).then((el) => {
|
||||
if (!el.text().includes('Edit')) {
|
||||
// # Link the Group if its not linked before
|
||||
if (el.find('.icon.fa-unlink').length > 0) {
|
||||
el.find('.icon.fa-unlink').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// # Get board group id
|
||||
cy.apiGetGroups().then((res) => {
|
||||
res.body.forEach((group) => {
|
||||
if (group.display_name === 'board') {
|
||||
// # Set groupID to navigate to group page directly
|
||||
groupID = group.id;
|
||||
|
||||
// # Set allow reference false to ensure correct data for test cases
|
||||
cy.apiPatchGroup(groupID, {allow_reference: false});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// # Login once as board user to ensure the user is created in the system
|
||||
boardUser = ldapUsers['board-1'];
|
||||
cy.apiLogin(boardUser);
|
||||
|
||||
// # Login as sysadmin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Add board user to test team to ensure that it exists in the team and set its preferences to skip tutorial step
|
||||
cy.apiGetUserByEmail(boardUser.email).then(({user}) => {
|
||||
cy.apiGetChannelByName(testTeam.name, 'town-square').then(({channel}) => {
|
||||
cy.apiAddUserToTeam(testTeam.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiSaveTutorialStep(user.id, '999');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2456 - Group Mentions when group members are in the team but not in the channel', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID, boardUser.email);
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(regularUser);
|
||||
|
||||
// # Create a new channel as a regular user
|
||||
cy.apiCreateChannel(testTeam.id, 'group-mention', 'Group Mentions').then(({channel}) => {
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
cy.uiGetPostTextBox();
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} `);
|
||||
|
||||
// * Verify if a system message is displayed indicating that list of members were not notified
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${boardUser.username} did not get notified by this mention because they are not in the channel. Would you like to add them to the channel? They will have access to all message history.`);
|
||||
|
||||
// * Verify if an option should be given to add them to channel
|
||||
cy.get('a.PostBody_addChannelMemberLink').should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2457 - Group Mentions when group members are not in the team and the channel', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID, boardUser.email);
|
||||
|
||||
// # Create a new team and channel as a sysadmin
|
||||
cy.apiCreateTeam('team', 'Test NoMember').then(({team}) => {
|
||||
cy.apiCreateChannel(team.id, 'group-mention', 'Group Mentions').then(({channel}) => {
|
||||
cy.apiCreateUser().then(({user}) => { // eslint-disable-line
|
||||
// # Add user to the team and channel
|
||||
cy.apiAddUserToTeam(team.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(user);
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
cy.uiGetPostTextBox();
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} `);
|
||||
|
||||
// * Verify if a system message is displayed indicating that there are no members in this team
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).
|
||||
should('include.text', `@${groupName} has no members on this team`);
|
||||
|
||||
// * Verify that the group mention is not highlighted
|
||||
cy.get(`#postMessageText_${postId}`).find('.mention--highlight').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2458 - Group Mentions when group members are not in the channel as a Guest User', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID, boardUser.email);
|
||||
|
||||
// # Enable Group Mentions for Guest Users
|
||||
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');
|
||||
enablePermission('guests-guest_use_group_mentions-checkbox');
|
||||
cy.uiSaveConfig();
|
||||
|
||||
// # Create a new channel as a sysadmin
|
||||
cy.apiCreateChannel(testTeam.id, 'group-mention', 'Group Mentions').then(({channel}) => {
|
||||
cy.apiCreateUser().then(({user}) => { // eslint-disable-line
|
||||
// # Add user to the team and channel
|
||||
cy.apiAddUserToTeam(testTeam.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
|
||||
// # Demote the user as a guest user
|
||||
cy.apiDemoteUserToGuest(user.id);
|
||||
|
||||
// # Login as a guest user
|
||||
cy.apiLogin(user);
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
cy.uiGetPostTextBox();
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} `);
|
||||
|
||||
// * Verify if a system message is displayed indicating that list of members were not notified
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).
|
||||
should('include.text', `@${boardUser.username} did not get notified by this mention because they are not in the channel.`);
|
||||
|
||||
// * Verify that the option to add them to channel is not given
|
||||
cy.get('a.PostBody_addChannelMemberLink').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2459 - Group Mentions when group members are not in the channel when Manage Members is disabled', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and enable group mention with the group name
|
||||
cy.apiAdminLogin();
|
||||
enableGroupMention(groupName, groupID, boardUser.email);
|
||||
|
||||
// # Create a new channel as a sysadmin
|
||||
cy.apiCreateChannel(testTeam.id, 'group-mention', 'Group Mentions').then(({channel}) => {
|
||||
// # Disable Manage Members permission for the channel
|
||||
visitChannelConfigPage(channel);
|
||||
disablePermission(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS);
|
||||
saveConfigForChannel();
|
||||
|
||||
// # Add regular user to the channel
|
||||
cy.apiAddUserToChannel(channel.id, regularUser.id);
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(regularUser);
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
cy.uiGetPostTextBox();
|
||||
|
||||
// # Submit a post containing the group mention
|
||||
cy.postMessage(`@${groupName} `);
|
||||
|
||||
// * Verify if a system message is displayed indicating that list of members were not notified
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).
|
||||
should('include.text', `@${boardUser.username} did not get notified by this mention because they are not in the channel.`);
|
||||
|
||||
// * Verify that the option to add them to channel is not given
|
||||
cy.get('a.PostBody_addChannelMemberLink').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
export function enableGroupMention(groupName, groupID, userEmail) {
|
||||
// # Visit Group Configurations page
|
||||
cy.visit(`/admin_console/user_management/groups/${groupID}`);
|
||||
|
||||
// # Scroll users list into view and then make sure it has loaded before scrolling back to the top
|
||||
cy.get('#group_users', {timeout: TIMEOUTS.ONE_MIN}).scrollIntoView();
|
||||
if (userEmail) {
|
||||
cy.findByText(userEmail).should('be.visible');
|
||||
}
|
||||
cy.get('#group_profile').scrollIntoView().wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// # Click the allow reference button
|
||||
cy.findByTestId('allowReferenceSwitch').then((el) => {
|
||||
const button = el.find('button');
|
||||
const classAttribute = button[0].getAttribute('class');
|
||||
if (!classAttribute.includes('active')) {
|
||||
button[0].click();
|
||||
}
|
||||
});
|
||||
|
||||
// # Give the group a custom name different from its DisplayName attribute
|
||||
cy.get('#groupMention').find('input').clear().type(groupName);
|
||||
|
||||
// # Click save button
|
||||
cy.uiSaveConfig();
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// 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 @guest_account
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
import {createPrivateChannel} from '../elasticsearch_autocomplete/helpers';
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('Guest Account - Guest User Experience', () => {
|
||||
let guestUser: Cypress.UserProfile;
|
||||
let privateChannel: Cypress.Channel;
|
||||
let testTeam: Cypress.Team;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
ServiceSettings: {
|
||||
EnableEmailInvitations: true,
|
||||
},
|
||||
});
|
||||
|
||||
// # Create User and Team
|
||||
cy.apiInitSetup({userPrefix: 'guest'}).then(({user, team}) => {
|
||||
guestUser = user;
|
||||
testTeam = team;
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1369 System message when user is added specifies the guest status', () => {
|
||||
// # Demote Guest user if applicable
|
||||
demoteGuestUser(guestUser);
|
||||
|
||||
// # Ceate a new team
|
||||
cy.apiCreateTeam('test-team2', 'Test Team2').then(({team: teamTwo}) => {
|
||||
// # Add the guest user to this team
|
||||
cy.apiAddUserToTeam(teamTwo.id, guestUser.id).then(() => {
|
||||
// # Login as guest user
|
||||
cy.apiLogin(guestUser);
|
||||
cy.reload();
|
||||
});
|
||||
});
|
||||
|
||||
// # Create Private Channel
|
||||
createPrivateChannel(testTeam.id, guestUser).then((channel) => {
|
||||
privateChannel = channel;
|
||||
|
||||
cy.visit(`/${testTeam.name}/channels/${privateChannel.name}`);
|
||||
});
|
||||
|
||||
// * The system message should contain 'added to the channel as a guest'
|
||||
cy.getLastPostId().then((id) => {
|
||||
cy.get(`#postMessageText_${id}`).should('contain', `@${guestUser.username} added to the channel as a guest`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1397 Guest tag in search in:', () => {
|
||||
demoteGuestUser(guestUser);
|
||||
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
cy.sendDirectMessageToUser(guestUser, 'hello');
|
||||
|
||||
// # Search for the Guest User
|
||||
cy.get('#searchBox').wait(TIMEOUTS.FIVE_SEC).type(`in:${guestUser.username}`);
|
||||
|
||||
// * Verify Guest Badge is not displayed at Search auto-complete
|
||||
cy.get('#search-autocomplete__popover').should('be.visible');
|
||||
cy.contains('.suggestion-list__item', guestUser.username).should('be.visible').within(($el) => {
|
||||
cy.wrap($el).find('.Tag').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function demoteGuestUser(guestUser) {
|
||||
// # Demote user as guest user before each test
|
||||
cy.apiAdminLogin();
|
||||
cy.apiGetUserByEmail(guestUser.email).then(({user}) => {
|
||||
if (user.roles !== 'system_guest') {
|
||||
cy.apiDemoteUserToGuest(guestUser.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
// 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 @guest_account
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
function demoteGuestUser(guestUser) {
|
||||
// # Demote user as guest user before each test
|
||||
cy.apiAdminLogin();
|
||||
cy.apiGetUserByEmail(guestUser.email).then(({user}) => {
|
||||
if (user.roles !== 'system_guest') {
|
||||
cy.apiDemoteUserToGuest(guestUser.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Guest Account - Guest User Experience', () => {
|
||||
let guestUser: Cypress.UserProfile;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
ServiceSettings: {
|
||||
EnableEmailInvitations: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.apiInitSetup({userPrefix: 'guest'}).then(({user, team, channel}) => {
|
||||
guestUser = user;
|
||||
|
||||
// # Create new team and visit its URL
|
||||
cy.apiDemoteUserToGuest(user.id).then(() => {
|
||||
cy.apiAddUserToTeam(team.id, guestUser.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, guestUser.id).then(() => {
|
||||
cy.apiLogin(guestUser);
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1354 Verify Guest User Restrictions', () => {
|
||||
// # Open team menu
|
||||
cy.uiOpenTeamMenu();
|
||||
|
||||
// * Verify reduced options in Team Menu
|
||||
const missingMainOptions = [
|
||||
'Invite People',
|
||||
'Team Settings',
|
||||
'Manage Members',
|
||||
'Join Another Team',
|
||||
'Create a Team',
|
||||
];
|
||||
missingMainOptions.forEach((missingOption) => {
|
||||
cy.uiGetLHSTeamMenu().should('not.contain', missingOption);
|
||||
});
|
||||
|
||||
const includeMainOptions = [
|
||||
'View Members',
|
||||
'Leave Team',
|
||||
];
|
||||
includeMainOptions.forEach((includeOption) => {
|
||||
cy.uiGetLHSTeamMenu().findByText(includeOption);
|
||||
});
|
||||
|
||||
// * Verify Reduced Options in LHS
|
||||
cy.uiGetLHSAddChannelButton().should('not.exist');
|
||||
|
||||
// * Verify Guest Badge in Channel Header
|
||||
cy.get('#channelHeaderDescription').within(($el) => {
|
||||
cy.wrap($el).find('.has-guest-header').should('be.visible').and('have.text', 'This channel has guests');
|
||||
});
|
||||
|
||||
// * Verify list of Users in Direct Messages Dialog
|
||||
cy.uiAddDirectMessage().click().wait(TIMEOUTS.FIVE_SEC);
|
||||
cy.get('#multiSelectList').should('be.visible').within(($el) => {
|
||||
// * Verify only 2 users - Guest and sysadmin are listed
|
||||
cy.wrap($el).children().should('have.length', 2);
|
||||
});
|
||||
cy.uiClose();
|
||||
|
||||
// * Verify Guest Badge when guest user posts a message
|
||||
cy.postMessage('testing');
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#post_${postId}`).within(($el) => {
|
||||
cy.wrap($el).find('.post__header .Tag').should('be.visible');
|
||||
cy.wrap($el).find('.post__header .user-popover').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
|
||||
});
|
||||
});
|
||||
|
||||
// * Verify Guest Badge in Guest User's Profile Popover
|
||||
cy.get('#user-profile-popover').should('be.visible').within(($el) => {
|
||||
cy.wrap($el).find('.GuestTag').should('be.visible').and('have.text', 'GUEST');
|
||||
});
|
||||
|
||||
// # Close the profile popover
|
||||
cy.get('#channel-header').click();
|
||||
|
||||
// * Verify Guest User can see only 1 additional channel in LHS plus off-topic and off-topic
|
||||
cy.uiGetLhsSection('CHANNELS').find('.SidebarChannel').should('have.length', 3);
|
||||
|
||||
// * Verify list of Users a Guest User can see in Team Members dialog
|
||||
cy.uiOpenTeamMenu('View Members');
|
||||
cy.get('#searchableUserListTotal').should('be.visible').and('have.text', '1 - 2 members of 2 total');
|
||||
});
|
||||
|
||||
it('MM-18049 Verify Guest User Restrictions is removed when promoted', () => {
|
||||
// # Promote a Guest user to a member and reload
|
||||
cy.apiAdminLogin();
|
||||
cy.apiPromoteGuestToUser(guestUser.id);
|
||||
|
||||
// # Login as guest user
|
||||
cy.apiLogin(guestUser);
|
||||
cy.reload();
|
||||
|
||||
// * Verify options in team menu are changed
|
||||
cy.uiOpenTeamMenu();
|
||||
const includeOptions = [
|
||||
'Invite People',
|
||||
'View Members',
|
||||
'Leave Team',
|
||||
'Create a Team',
|
||||
];
|
||||
includeOptions.forEach((option) => {
|
||||
cy.uiGetLHSTeamMenu().findByText(option);
|
||||
});
|
||||
|
||||
// # Close the main menu
|
||||
cy.uiGetLHSHeader().click();
|
||||
|
||||
// * Verify Options in LHS are changed
|
||||
cy.uiGetLHSAddChannelButton();
|
||||
|
||||
// * Verify Guest Badge in Channel Header is removed
|
||||
cy.get('#sidebarItem_off-topic').click();
|
||||
cy.get('#channelIntro').should('be.visible');
|
||||
cy.get('#channelHeaderDescription').within(($el) => {
|
||||
cy.wrap($el).find('.has-guest-header').should('not.exist');
|
||||
});
|
||||
|
||||
// * Verify Guest Badge is removed when user posts a message
|
||||
cy.get('#sidebarItem_off-topic').click({force: true});
|
||||
cy.postMessage('testing');
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#post_${postId}`).within(($el) => {
|
||||
cy.wrap($el).find('.post__header .Tag').should('not.exist');
|
||||
cy.wrap($el).find('.post__header .user-popover').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
|
||||
});
|
||||
});
|
||||
|
||||
// * Verify Guest Badge is not displayed in User's Profile Popover
|
||||
cy.get('#user-profile-popover').should('be.visible').within(($el) => {
|
||||
cy.wrap($el).find('.user-popover__role').should('not.exist');
|
||||
});
|
||||
|
||||
// # Close the profile popover
|
||||
cy.get('#channel-header').click();
|
||||
});
|
||||
|
||||
it('MM-T1417 Add Guest User to New Team from System Console', () => {
|
||||
// # Demote Guest user if applicable
|
||||
demoteGuestUser(guestUser);
|
||||
|
||||
// # Create a new team
|
||||
cy.apiCreateTeam('test-team2', 'Test Team2').then(({team: teamTwo}) => {
|
||||
// # Add the guest user to this team
|
||||
cy.apiAddUserToTeam(teamTwo.id, guestUser.id).then(() => {
|
||||
// # Login as guest user
|
||||
cy.apiLogin(guestUser);
|
||||
cy.reload();
|
||||
|
||||
// # Click team button
|
||||
cy.get(`#${teamTwo.name}TeamButton`, {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').click();
|
||||
|
||||
// * Verify if Channel Not found is displayed
|
||||
cy.findByText('Channel Not Found').should('be.visible');
|
||||
cy.findByText('Your guest account has no channels assigned. Please contact an administrator.').should('be.visible');
|
||||
cy.findByText('Back').should('be.visible').click();
|
||||
|
||||
// * Verify if user is redirected to a valid channel
|
||||
cy.findByTestId('post_textbox').should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1412 Revoke Guest User Sessions when Guest feature is disabled', () => {
|
||||
// # Demote Guest user if applicable
|
||||
demoteGuestUser(guestUser);
|
||||
|
||||
// # Disable Guest Access
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: false,
|
||||
},
|
||||
});
|
||||
|
||||
// # Wait for page to load and then logout
|
||||
cy.uiGetPostTextBox().wait(TIMEOUTS.TWO_SEC);
|
||||
cy.apiLogout();
|
||||
cy.visit('/');
|
||||
|
||||
// # Login with guest user credentials and check the error message
|
||||
cy.get('#input_loginId').type(guestUser.username);
|
||||
cy.get('#input_password-input').type('passwd');
|
||||
cy.get('#saveSetting').should('not.be.disabled').click();
|
||||
|
||||
// * Verify if guest account is deactivated
|
||||
cy.findByText('Login failed because your account has been deactivated. Please contact an administrator.').should('be.visible');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,91 @@
|
||||
// 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 @guest_account
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
describe('Guest Accounts', () => {
|
||||
let guestUser: Cypress.UserProfile;
|
||||
|
||||
before(() => {
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
cy.apiCreateGuestUser({}).then(({guest}) => {
|
||||
guestUser = guest;
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1411 Update Guest Users in User Management when Guest feature is disabled', () => {
|
||||
// # Navigate to Guest Access page.
|
||||
cy.visit('/admin_console/authentication/guest_access');
|
||||
|
||||
// # Enable guest accounts.
|
||||
cy.findByTestId('GuestAccountsSettings.Enabletrue').check();
|
||||
|
||||
// # Click "Save".
|
||||
cy.get('#saveSetting').then((btn) => {
|
||||
if (btn.is(':enabled')) {
|
||||
btn.on('click', () => {});
|
||||
|
||||
cy.waitUntil(() => cy.get('#saveSetting').then((el) => {
|
||||
return el[0].innerText === 'Save';
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
// # Ensure there are active Guest users.
|
||||
checkUserListStatus(guestUser, 'Guest');
|
||||
|
||||
// # Navigate to System Console ➜ Guest Access.
|
||||
cy.visit('/admin_console/authentication/guest_access');
|
||||
|
||||
// # Set Enable Guest Access to false.
|
||||
cy.findByTestId('GuestAccountsSettings.Enablefalse').check();
|
||||
|
||||
// # Click "Save".
|
||||
cy.get('#saveSetting').scrollIntoView().click();
|
||||
cy.get('#confirmModal').should('be.visible').within(() => {
|
||||
cy.get('#confirmModalButton').should('have.text', 'Save and Disable Guest Access').click();
|
||||
});
|
||||
|
||||
// * Guest users are shown as "Inactive".
|
||||
checkUserListStatus(guestUser, 'Inactive');
|
||||
|
||||
// # Navigate to Guest Access page.
|
||||
cy.visit('/admin_console/authentication/guest_access');
|
||||
|
||||
// # Enable guest accounts.
|
||||
cy.findByTestId('GuestAccountsSettings.Enabletrue').check();
|
||||
|
||||
// # Click "Save".
|
||||
cy.get('#saveSetting').scrollIntoView().click();
|
||||
|
||||
// * Guest users are shown as "Inactive".
|
||||
checkUserListStatus(guestUser, 'Inactive');
|
||||
});
|
||||
|
||||
function getInnerText(el) {
|
||||
return el[0].innerText.replace(/\n/g, '').replace(/\s/g, ' ');
|
||||
}
|
||||
|
||||
function checkUserListStatus(user, status) {
|
||||
// # Go to System Console ➜ Users.
|
||||
cy.visit('/admin_console/user_management/users');
|
||||
|
||||
cy.get('#searchUsers').should('be.visible').type(user.username);
|
||||
cy.get('#selectUserStatus').select(status);
|
||||
cy.get('.more-modal__details > .more-modal__name').should('be.visible').then((el) => {
|
||||
expect(getInnerText(el)).contains(`@${user.username}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,163 @@
|
||||
// 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 @not_cloud @enterprise @guest_account @mfa
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
import authenticator from 'authenticator';
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
import {
|
||||
getJoinEmailTemplate,
|
||||
getRandomId,
|
||||
reUrl,
|
||||
verifyEmailBody,
|
||||
} from '../../../../utils';
|
||||
|
||||
describe('Guest Accounts', () => {
|
||||
let sysadmin: Cypress.UserProfile;
|
||||
let testTeam: Cypress.Team;
|
||||
let testChannel: Cypress.Channel;
|
||||
let adminMFASecret: string;
|
||||
const username = 'g' + getRandomId(); // username has to start with a letter.
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
cy.apiInitSetup().then(({team, channel}) => {
|
||||
testTeam = team;
|
||||
testChannel = channel;
|
||||
});
|
||||
|
||||
// # Log in as a team admin.
|
||||
cy.apiAdminLogin().then((user) => {
|
||||
sysadmin = user;
|
||||
});
|
||||
});
|
||||
|
||||
after(() => {
|
||||
// # Login back as admin.
|
||||
// cy.log("############################" + adminMFASecret)
|
||||
const token = authenticator.generateToken(adminMFASecret);
|
||||
cy.apiAdminLoginWithMFA(token);
|
||||
|
||||
// # Update Configs.
|
||||
cy.apiUpdateConfig({
|
||||
ServiceSettings: {
|
||||
EnableMultifactorAuthentication: false,
|
||||
EnforceMultifactorAuthentication: false,
|
||||
},
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
EnforceMultifactorAuthentication: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1390 Enforce Guest MFA when MFA is enabled and enforced', () => {
|
||||
// # Navigate to System Console -> Authentication -> MFA Page.
|
||||
cy.visit('/admin_console/authentication/mfa');
|
||||
|
||||
// # Ensure the setting 'Enable Multi factor authentication' is set to true in the MFA page.
|
||||
cy.findByTestId('ServiceSettings.EnableMultifactorAuthenticationtrue').check();
|
||||
|
||||
// # Also ensure that this MFA setting is enforced.
|
||||
cy.findByTestId('ServiceSettings.EnforceMultifactorAuthenticationtrue').check();
|
||||
|
||||
// # Click "Save".
|
||||
cy.findByText('Save').click().wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// # Get MFA secret
|
||||
cy.uiGetMFASecret(sysadmin.id).then((secret) => {
|
||||
adminMFASecret = secret;
|
||||
});
|
||||
|
||||
// # Navigate to Guest Access page.
|
||||
cy.visit('/admin_console/authentication/guest_access');
|
||||
|
||||
// # Enable guest accounts.
|
||||
cy.findByTestId('GuestAccountsSettings.Enabletrue').check();
|
||||
|
||||
// # Check if user is allowed to enforce MFA for Guest accounts.
|
||||
cy.findByTestId('GuestAccountsSettings.EnforceMultifactorAuthenticationtrue').check();
|
||||
|
||||
// # Click "Save".
|
||||
cy.get('#saveSetting').scrollIntoView().click();
|
||||
|
||||
const email = `${username}@sample.mattermost.com`;
|
||||
|
||||
// # From the main page, invite a Guest user and click on the Join Team in the email sent to the guest user.
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
|
||||
// # Open team menu, click Invite People, then invite guest
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
cy.findByTestId('inviteGuestLink').click();
|
||||
|
||||
// # Type guest user e-mail address.
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').typeWithForce(email + '{enter}');
|
||||
});
|
||||
cy.get('.users-emails-input__menu').
|
||||
children().should('have.length', 1).
|
||||
eq(0).should('contain', `Invite ${email} as a guest`).click();
|
||||
|
||||
// # Search and add to a Channel.
|
||||
cy.get('.channels-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').typeWithForce(testChannel.name);
|
||||
});
|
||||
cy.get('.channels-input__menu').
|
||||
children().should('have.length', 1).
|
||||
eq(0).should('contain', testChannel.name).click();
|
||||
|
||||
cy.get('#inviteGuestButton').scrollIntoView().click();
|
||||
cy.findByTestId('confirm-done').should('be.visible').click();
|
||||
|
||||
// # Get invitation link.
|
||||
cy.getRecentEmail({username, email}).then((data) => {
|
||||
const {body: actualEmailBody, subject} = data;
|
||||
|
||||
// # Verify that the email subject is about joining.
|
||||
expect(subject).to.contain(`${sysadmin.username} invited you to join the team ${testTeam.display_name} as a guest`);
|
||||
|
||||
const expectedEmailBody = getJoinEmailTemplate(sysadmin.username, email, testTeam, true);
|
||||
verifyEmailBody(expectedEmailBody, actualEmailBody);
|
||||
|
||||
// # Extract invitation link from the invitation e-mail.
|
||||
const invitationLink = actualEmailBody[3].match(reUrl)[0];
|
||||
|
||||
// # Logout sysadmin.
|
||||
cy.apiLogout();
|
||||
cy.visit(invitationLink);
|
||||
});
|
||||
|
||||
// # Create an account with Email and Password.
|
||||
cy.get('#input_name').type(username);
|
||||
cy.get('#input_password-input').type(username);
|
||||
cy.findByText('Create Account').click();
|
||||
|
||||
// * When MFA is enforced for Guest Access, guest user should be forced to configure MFA while creating an account.
|
||||
cy.url().should('include', 'mfa/setup');
|
||||
cy.get('#mfa').wait(TIMEOUTS.HALF_SEC).find('.col-sm-12').then((p) => {
|
||||
const secretp = p.text();
|
||||
const secret = secretp.split(' ')[1];
|
||||
|
||||
const token = authenticator.generateToken(secret);
|
||||
cy.get('#mfa').find('.form-control').type(token);
|
||||
cy.get('#mfa').find('.btn.btn-primary').click();
|
||||
|
||||
cy.wait(TIMEOUTS.ONE_SEC);
|
||||
cy.get('#mfa').find('.btn.btn-primary').click();
|
||||
});
|
||||
cy.apiLogout();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
// 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 @guest_account @not_cloud
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('Verify Guest User Identification in different screens', () => {
|
||||
let guestUser: Cypress.UserProfile;
|
||||
let testChannel: Cypress.Channel;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
ServiceSettings: {
|
||||
EnableEmailInvitations: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.apiInitSetup().then(({team, channel, user}) => {
|
||||
testChannel = channel;
|
||||
|
||||
cy.apiCreateGuestUser({}).then(({guest}) => {
|
||||
guestUser = guest;
|
||||
cy.apiAddUserToTeam(team.id, guest.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, guest.id);
|
||||
});
|
||||
});
|
||||
|
||||
// # Login as regular user and visit the channel with guest
|
||||
cy.apiLogin(user);
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1419 Deactivating a Guest removes "This channel has guests" message from channel header', () => {
|
||||
// * Verify the text 'This channel has guests' is displayed in the header
|
||||
cy.get('#channelHeaderDescription').within(($el) => {
|
||||
cy.wrap($el).find('.has-guest-header').should('be.visible').and('have.text', 'This channel has guests');
|
||||
});
|
||||
|
||||
// # Deactivate Guest user
|
||||
cy.externalActivateUser(guestUser.id, false).wait(TIMEOUTS.FIVE_SEC);
|
||||
|
||||
// # Switch channels away and back to reload the header
|
||||
cy.get('.SidebarChannel:contains(Town Square)').click();
|
||||
cy.get(`.SidebarChannel:contains(${testChannel.display_name})`).click();
|
||||
|
||||
// * Verify the text 'This channel has guests' is removed from the header
|
||||
cy.get('#channelHeaderDescription').within(($el) => {
|
||||
cy.wrap($el).find('.has-guest-header').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,225 @@
|
||||
// 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 @guest_account
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
import {getAdminAccount} from '../../../../support/env';
|
||||
|
||||
describe('Verify Guest User Identification in different screens', () => {
|
||||
const admin = getAdminAccount();
|
||||
let regularUser: Cypress.UserProfile;
|
||||
let guestUser: Cypress.UserProfile;
|
||||
let testTeam: Cypress.Team;
|
||||
let testChannel: Cypress.Channel;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
ServiceSettings: {
|
||||
EnableEmailInvitations: true,
|
||||
},
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
// # Login as regular user and visit test channel
|
||||
cy.apiLogin(regularUser);
|
||||
cy.visit(`/${team.name}/channels/${testChannel.name}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1370 Verify Guest Badge in Channel Members dropdown and dialog', () => {
|
||||
// # Open Channel Members RHS
|
||||
cy.get('#channelHeaderDropdownIcon').click();
|
||||
cy.get('#channelManageMembers').click().wait(TIMEOUTS.HALF_SEC);
|
||||
cy.uiGetRHS().findByTestId(`memberline-${guestUser.id}`).within(($el) => {
|
||||
cy.wrap($el).get('.Tag').should('be.visible').should('have.text', 'GUEST');
|
||||
});
|
||||
});
|
||||
|
||||
it('Verify Guest Badge in Team Members dialog', () => {
|
||||
// # Open team menu and click 'View Members'
|
||||
cy.uiOpenTeamMenu('View Members');
|
||||
|
||||
cy.get('#teamMembersModal').should('be.visible').within(($el) => {
|
||||
cy.wrap($el).findAllByTestId('userListItemDetails').each(($elChild) => {
|
||||
cy.wrap($elChild).invoke('text').then((username) => {
|
||||
// * Verify Guest Badge in Channel Members List
|
||||
if (username === guestUser.username) {
|
||||
cy.wrap($elChild).find('.Tag').should('be.visible').and('have.text', 'GUEST');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// #Close Channel Members Dialog
|
||||
cy.wrap($el).find('.close').click();
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1372 Verify Guest Badge in Posts in Center Channel, RHS and User Profile Popovers', () => {
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// # Get yesterdays date in UTC
|
||||
const yesterdaysDate = dayjs().subtract(1, 'days').valueOf();
|
||||
|
||||
// # Post a day old message
|
||||
cy.postMessageAs({sender: guestUser, message: 'Hello from yesterday', channelId: testChannel.id, createAt: yesterdaysDate}).
|
||||
its('id').
|
||||
should('exist').
|
||||
as('yesterdaysPost');
|
||||
|
||||
// * Verify Guest Badge when guest user posts a message in Center Channel
|
||||
cy.get('@yesterdaysPost').then((postId) => {
|
||||
cy.get(`#post_${postId}`).within(($el) => {
|
||||
cy.wrap($el).find('.post__header .Tag').should('be.visible');
|
||||
cy.wrap($el).find('.post__header .user-popover').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
|
||||
});
|
||||
});
|
||||
|
||||
// * Verify Guest Badge in Guest User's Profile Popover
|
||||
cy.get('#user-profile-popover').should('be.visible').within(($el) => {
|
||||
cy.wrap($el).find('.GuestTag').should('be.visible').and('have.text', 'GUEST');
|
||||
});
|
||||
|
||||
// # Close the profile popover
|
||||
cy.get('#channel-header').click();
|
||||
|
||||
// # Open RHS comment menu
|
||||
cy.get('@yesterdaysPost').then((postId) => {
|
||||
cy.clickPostCommentIcon(postId.toString());
|
||||
|
||||
// * Verify Guest Badge in RHS
|
||||
cy.get(`#rhsPost_${postId}`).within(($el) => {
|
||||
cy.wrap($el).find('.post__header .Tag').should('be.visible');
|
||||
});
|
||||
|
||||
// # Close RHS
|
||||
cy.uiCloseRHS();
|
||||
});
|
||||
});
|
||||
|
||||
it('Verify Guest Badge in Switch Channel Dialog', () => {
|
||||
// # Open Find Channels
|
||||
cy.uiOpenFindChannels();
|
||||
|
||||
// # Type the guest user name on Channel switcher input
|
||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(guestUser.username).wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify if Guest badge is displayed for the guest user in the Switch Channel Dialog
|
||||
cy.get('#suggestionList').should('be.visible');
|
||||
cy.findByTestId(guestUser.username).within(($el) => {
|
||||
cy.wrap($el).find('.Tag').should('be.visible').and('have.text', 'GUEST');
|
||||
});
|
||||
|
||||
// # Close Dialog
|
||||
cy.get('#quickSwitchModalLabel > .close').click();
|
||||
});
|
||||
|
||||
it('MM-T1377 Verify Guest Badge in DM Search dialog', () => {
|
||||
// #Click on plus icon of Direct Messages
|
||||
cy.uiAddDirectMessage().click().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// # Search for the Guest User
|
||||
cy.focused().type(guestUser.username, {force: true}).wait(TIMEOUTS.HALF_SEC);
|
||||
cy.get('#multiSelectList').should('be.visible').within(($el) => {
|
||||
// * Verify if Guest badge is displayed in the DM Search
|
||||
cy.wrap($el).find('.Tag').should('be.visible').and('have.text', 'GUEST');
|
||||
});
|
||||
|
||||
// # Close the Direct Messages dialog
|
||||
cy.get('#moreDmModal .close').click();
|
||||
});
|
||||
|
||||
it('Verify Guest Badge in DM header and GM header', () => {
|
||||
// # Open a DM with Guest User
|
||||
cy.uiAddDirectMessage().click();
|
||||
cy.findByRole('dialog', {name: 'Direct Messages'}).should('be.visible').wait(TIMEOUTS.ONE_SEC);
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
should('have.focused').
|
||||
typeWithForce(guestUser.username).
|
||||
wait(TIMEOUTS.ONE_SEC).
|
||||
typeWithForce('{enter}');
|
||||
cy.uiGetButton('Go').click().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify Guest Badge in DM header
|
||||
cy.get('#channelHeaderTitle').should('be.visible').find('.Tag').should('be.visible').and('have.text', 'GUEST');
|
||||
cy.get('#channelHeaderDescription').within(($el) => {
|
||||
cy.wrap($el).find('.has-guest-header').should('be.visible').and('have.text', 'This channel has guests');
|
||||
});
|
||||
|
||||
// # Open a GM with Guest User and Sysadmin
|
||||
cy.uiAddDirectMessage().click();
|
||||
cy.findByRole('dialog', {name: 'Direct Messages'}).should('be.visible').wait(TIMEOUTS.ONE_SEC);
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
should('have.focused').
|
||||
typeWithForce(guestUser.username).
|
||||
wait(TIMEOUTS.ONE_SEC).
|
||||
typeWithForce('{enter}');
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
should('have.focused').
|
||||
typeWithForce(admin.username).
|
||||
wait(TIMEOUTS.ONE_SEC).
|
||||
typeWithForce('{enter}');
|
||||
cy.uiGetButton('Go').click().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify Guest Badge in GM header
|
||||
cy.get('#channelHeaderTitle').should('be.visible').find('.Tag').should('be.visible').and('have.text', 'GUEST');
|
||||
cy.get('#channelHeaderDescription').within(($el) => {
|
||||
cy.wrap($el).find('.has-guest-header').should('be.visible').and('have.text', 'This group message has guests');
|
||||
});
|
||||
});
|
||||
|
||||
it('Verify Guest Badge in @mentions Autocomplete', () => {
|
||||
// # Start a draft in Channel containing "@user"
|
||||
cy.uiGetPostTextBox().type(`@${guestUser.username}`);
|
||||
|
||||
// * Verify Guest Badge is displayed at mention auto-complete
|
||||
cy.get('#suggestionList').should('be.visible');
|
||||
cy.findByTestId(`mentionSuggestion_${guestUser.username}`).within(($el) => {
|
||||
cy.wrap($el).find('.Tag').should('be.visible').and('have.text', 'GUEST');
|
||||
});
|
||||
});
|
||||
|
||||
it('Verify Guest Badge not displayed in Search Autocomplete', () => {
|
||||
// # Search for the Guest User
|
||||
cy.get('#searchBox').type('from:');
|
||||
|
||||
// * Verify Guest Badge is not displayed at Search auto-complete
|
||||
cy.get('#search-autocomplete__popover').should('be.visible');
|
||||
cy.contains('.suggestion-list__item', guestUser.username).scrollIntoView().should('be.visible').within(($el) => {
|
||||
cy.wrap($el).find('.Tag').should('not.exist');
|
||||
});
|
||||
|
||||
// # Close and Clear the Search Autocomplete
|
||||
cy.get('#searchFormContainer').find('.input-clear-x').click({force: true});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,146 @@
|
||||
// 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 @guest_account
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
import {getRandomId} from '../../../../utils';
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
import {
|
||||
changeGuestFeatureSettings,
|
||||
invitePeople,
|
||||
verifyInvitationError,
|
||||
verifyInvitationSuccess,
|
||||
} from './helpers';
|
||||
|
||||
describe('Guest Account - Guest User Invitation Flow', () => {
|
||||
let testTeam: Cypress.Team;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Login as sysadmin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Reset Guest Feature settings
|
||||
changeGuestFeatureSettings();
|
||||
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
testTeam = team;
|
||||
|
||||
// # Go to town square
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1336 Invite Guests - Existing Team Member', () => {
|
||||
cy.apiCreateUser().then(({user: newUser}) => {
|
||||
cy.apiAddUserToTeam(testTeam.id, newUser.id).then(() => {
|
||||
// # Search and add an existing member by username who is part of the team
|
||||
invitePeople(newUser.username, 1, newUser.username);
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
verifyInvitationError(newUser.username, testTeam, 'This person is already a member.');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1337 Invite Guests - Existing Team Guest', () => {
|
||||
cy.apiCreateGuestUser({}).then(({guest}) => {
|
||||
cy.apiAddUserToTeam(testTeam.id, guest.id).then(() => {
|
||||
// # Search and add an existing guest by first name, who is part of the team but not channel
|
||||
invitePeople(guest.first_name, 1, guest.username, 'Off-Topic');
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
verifyInvitationSuccess(guest.username, testTeam, 'This guest has been added to the team and channel.');
|
||||
|
||||
// # Search and add an existing guest by last name, who is part of the team and channel
|
||||
invitePeople(guest.last_name, 1, guest.username, 'Off-Topic');
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
verifyInvitationError(guest.username, testTeam, 'This person is already a member of all the channels.', true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1338 Invite Guests - Existing Member not on the team', () => {
|
||||
cy.apiCreateUser().then(({user: regularUser}) => {
|
||||
// # Search and add an existing member by email who is not part of the team
|
||||
invitePeople(regularUser.email, 1, regularUser.username);
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
verifyInvitationError(regularUser.username, testTeam, 'This person is already a member.');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1339 Invite Guests - Existing Guest not on the team', () => {
|
||||
// # Search and add an existing guest by email, who is not part of the team
|
||||
cy.apiCreateGuestUser({}).then(({guest}) => {
|
||||
invitePeople(guest.email, 1, guest.username);
|
||||
|
||||
verifyInvitationSuccess(guest.username, testTeam, 'This guest has been added to the team and channel.', true);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1340 Invite Guests - New User not in the system', () => {
|
||||
// # Search and add a new guest by email, who is not part of the team
|
||||
const email = `temp-${getRandomId()}@mattermost.com`;
|
||||
invitePeople(email, 1, email);
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
verifyInvitationSuccess(email, testTeam, 'An invitation email has been sent.');
|
||||
});
|
||||
|
||||
it('MM-T1394 Change Email not whitelisted for Guest user', () => {
|
||||
// # Configure a whitelisted domain
|
||||
changeGuestFeatureSettings(true, true, 'example.com');
|
||||
|
||||
// # Visit to newly created team
|
||||
cy.reload();
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
|
||||
// # Invite a Guest by email
|
||||
const email = `temp-${getRandomId()}@mattermost.com`;
|
||||
invitePeople(email, 1, email);
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
const expectedError = `The following email addresses do not belong to an accepted domain: ${email}. Please contact your System Administrator for details.`;
|
||||
verifyInvitationError(email, testTeam, expectedError);
|
||||
|
||||
// # From System Console try to update email of guest user
|
||||
cy.apiCreateGuestUser({}).then(({guest}) => {
|
||||
// # Navigate to System Console Users listing page
|
||||
cy.visit('/admin_console/user_management/users');
|
||||
|
||||
// # Search for User by username and select the option to update email
|
||||
cy.get('#searchUsers').should('be.visible').type(guest.username);
|
||||
|
||||
// # Click on the option to update email
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
cy.findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').click();
|
||||
cy.findByText('Update Email').should('be.visible').click();
|
||||
|
||||
// * Update email outside whitelisted domain and verify error message
|
||||
cy.findByTestId('resetEmailModal').should('be.visible').within(() => {
|
||||
cy.findByTestId('resetEmailForm').should('be.visible').get('input').type(email);
|
||||
cy.findByTestId('resetEmailButton').click();
|
||||
cy.get('.error').should('be.visible').and('have.text', 'The email you provided does not belong to an accepted domain for guest accounts. Please contact your administrator or sign up with a different email.');
|
||||
cy.get('.close').click();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,226 @@
|
||||
// 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 @guest_account
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
import {getRandomId} from '../../../../utils';
|
||||
|
||||
import {
|
||||
changeGuestFeatureSettings,
|
||||
invitePeople,
|
||||
verifyInvitationSuccess,
|
||||
} from './helpers';
|
||||
|
||||
describe('Guest Account - Guest User Invitation Flow', () => {
|
||||
let testTeam: Cypress.Team;
|
||||
let newUser: Cypress.UserProfile;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Login as sysadmin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Reset Guest Feature settings
|
||||
changeGuestFeatureSettings();
|
||||
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
testTeam = team;
|
||||
|
||||
cy.apiCreateUser().then(({user}) => {
|
||||
newUser = user;
|
||||
cy.apiAddUserToTeam(testTeam.id, newUser.id);
|
||||
});
|
||||
|
||||
// # Go to town square
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4451 Verify UI Elements of Guest User Invitation Flow', () => {
|
||||
// # Open team menu and click 'Invite People'
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
// * Verify Invite Guest link
|
||||
cy.findByTestId('inviteGuestLink').should('be.visible').click();
|
||||
cy.findByText('Add to channels').should('be.visible');
|
||||
|
||||
// * Verify the header has changed in the modal
|
||||
cy.findByTestId('invitationModal').within(() => {
|
||||
cy.get('h1').should('have.text', `Invite guests to ${testTeam.display_name}`);
|
||||
});
|
||||
|
||||
// * Verify Invite Guests button is disabled by default
|
||||
cy.get('#inviteGuestButton').scrollIntoView().should('be.visible').and('be.disabled');
|
||||
|
||||
// * Verify Invite People field
|
||||
const email = `temp-${getRandomId()}@mattermost.com`;
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
// * Verify the input placeholder text
|
||||
cy.get('.users-emails-input__placeholder').should('have.text', 'Enter a name or email address');
|
||||
|
||||
// # Type the email of the new user
|
||||
cy.get('input').typeWithForce(email);
|
||||
});
|
||||
cy.get('.users-emails-input__menu').
|
||||
children().should('have.length', 1).
|
||||
eq(0).should('contain', `Invite ${email} as a guest`).click();
|
||||
|
||||
cy.get('.channels-input__control').should('be.visible').within(() => {
|
||||
// * Verify the input placeholder text
|
||||
cy.get('.channels-input__placeholder').should('have.text', 'e.g. Town Square');
|
||||
|
||||
// # Type the channel name
|
||||
cy.get('input').typeWithForce('town sq');
|
||||
});
|
||||
|
||||
cy.get('.channels-input__menu').
|
||||
children().should('have.length', 1).
|
||||
eq(0).should('contain', 'Town Square').click();
|
||||
|
||||
// * Verify Set Custom Message before clicking on the link
|
||||
cy.get('.AddToChannels').should('be.visible').within(() => {
|
||||
cy.get('textarea').should('not.exist');
|
||||
|
||||
// #Verify link text and click on it
|
||||
cy.get('a').should('have.text', 'Set a custom message').click();
|
||||
});
|
||||
|
||||
// * Verify Set Custom Message after clicking on the link
|
||||
cy.get('.AddToChannels').should('be.visible').within(() => {
|
||||
cy.get('a').should('not.exist');
|
||||
cy.get('.AddToChannels__customMessageTitle').findByText('Custom message');
|
||||
cy.get('textarea').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1386 Verify when different feature settings are disabled', () => {
|
||||
// # Disable Guest Accounts
|
||||
// # Enable Email Invitations
|
||||
changeGuestFeatureSettings(false, true);
|
||||
|
||||
// # reload current page
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
|
||||
// # Open team menu and click 'Invite People'
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
// * Verify if Invite Members modal is displayed when guest account feature is disabled
|
||||
cy.findByTestId('invitationModal').find('h1').should('have.text', `Invite people to ${testTeam.display_name}`);
|
||||
|
||||
// * Verify Share Link Header and helper text
|
||||
cy.findByTestId('InviteView__copyInviteLink').should('be.visible').within(() => {
|
||||
cy.findByText('Copy invite link').should('be.visible');
|
||||
});
|
||||
|
||||
// # Close the Modal
|
||||
cy.get('#closeIcon').should('be.visible').click();
|
||||
|
||||
// # Enable Guest Accounts
|
||||
// # Disable Email Invitations
|
||||
changeGuestFeatureSettings(true, false);
|
||||
|
||||
// # Reload the current page
|
||||
cy.reload();
|
||||
|
||||
const email = `temp-${getRandomId()}@mattermost.com`;
|
||||
invitePeople(email, 1, email, 'Town Square', false);
|
||||
|
||||
// * Verify Invite Guests button is disabled
|
||||
cy.get('#inviteGuestButton').should('be.disabled');
|
||||
});
|
||||
|
||||
it('MM-T4449 Invite Guest via Email containing upper case letters', () => {
|
||||
// # Reset Guest Feature settings
|
||||
changeGuestFeatureSettings();
|
||||
|
||||
// # Visit Team page
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
|
||||
// # Invite a email containing uppercase letters
|
||||
const email = `tEMp-${getRandomId()}@mattermost.com`;
|
||||
invitePeople(email, 1, email);
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
verifyInvitationSuccess(email.toLowerCase(), testTeam, 'An invitation email has been sent.');
|
||||
});
|
||||
|
||||
it('MM-T1414 Add Guest from Add New Members dialog', () => {
|
||||
// # Demote the user from member to guest
|
||||
cy.apiDemoteUserToGuest(newUser.id);
|
||||
|
||||
// # Open team menu and click 'Invite People'
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
// # Click invite members if needed
|
||||
cy.get('.InviteAs').findByTestId('inviteMembersLink').click();
|
||||
|
||||
// # Search and add a member
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').typeWithForce(newUser.username);
|
||||
});
|
||||
cy.get('.users-emails-input__menu').
|
||||
children().should('have.length', 1).eq(0).should('contain', newUser.username).click();
|
||||
|
||||
// # Click Invite Members
|
||||
cy.get('#inviteMembersButton').scrollIntoView().click();
|
||||
|
||||
// * Verify the content and error message in the Invitation Modal
|
||||
cy.findByTestId('invitationModal').within(() => {
|
||||
cy.get('div.invitation-modal-confirm--sent').should('not.exist');
|
||||
cy.get('div.invitation-modal-confirm--not-sent').should('be.visible').within(() => {
|
||||
cy.get('h2 > span').should('have.text', 'Invitations Not Sent');
|
||||
cy.get('.people-header').should('have.text', 'People');
|
||||
cy.get('.details-header').should('have.text', 'Details');
|
||||
cy.get('.username-or-icon').should('contain', newUser.username);
|
||||
cy.get('.reason').should('have.text', 'Contact your admin to make this guest a full member.');
|
||||
cy.get('.username-or-icon .Tag').should('be.visible').and('have.text', 'GUEST');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1415 Check invite more button available on both successful and failed invites', () => {
|
||||
// # Search and add an existing member by username who is part of the team
|
||||
invitePeople(newUser.username, 1, newUser.username);
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
cy.findByText('This person is already a member.').should('be.visible');
|
||||
|
||||
// # Click on invite more button
|
||||
cy.findByTestId('invite-more').click();
|
||||
|
||||
// * Verify the channel is preselected
|
||||
cy.get('.channels-input__control').should('be.visible').within(() => {
|
||||
cy.get('.public-channel-icon').should('be.visible');
|
||||
cy.findByText('Town Square').should('be.visible');
|
||||
});
|
||||
|
||||
// * Verify the email field is empty
|
||||
const email = `temp-${getRandomId()}@mattermost.com`;
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
cy.get('.users-emails-input__multi-value').should('not.exist');
|
||||
cy.get('input').typeWithForce(email);
|
||||
});
|
||||
cy.get('.users-emails-input__menu').children().should('have.length', 1).eq(0).should('contain', email).click();
|
||||
|
||||
// # Click Invite Guests Button
|
||||
cy.get('#inviteGuestButton').scrollIntoView().click();
|
||||
|
||||
// * Verify invite more button is present
|
||||
cy.findByTestId('invite-more').should('be.visible');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
// 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 @guest_account
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('Guest Account - Guest User Badge and Popover', () => {
|
||||
let regularUser: Cypress.UserProfile;
|
||||
let guestUser: Cypress.UserProfile;
|
||||
let testTeam: Cypress.Team;
|
||||
let testChannel: Cypress.Channel;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
ServiceSettings: {
|
||||
EnableEmailInvitations: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.apiInitSetup().then(({team, channel, user}) => {
|
||||
regularUser = user;
|
||||
testTeam = team;
|
||||
testChannel = channel;
|
||||
|
||||
cy.apiCreateGuestUser({}).then(({guest}) => {
|
||||
guestUser = guest;
|
||||
cy.log(`Guest Id: ${guestUser.id}`);
|
||||
cy.log(`Guest Username ${guestUser.username}`);
|
||||
cy.apiAddUserToTeam(testTeam.id, guestUser.id).then(() => {
|
||||
cy.apiAddUserToChannel(testChannel.id, guestUser.id);
|
||||
});
|
||||
});
|
||||
|
||||
// # Login as regular user and go to town square
|
||||
cy.apiLogin(regularUser);
|
||||
cy.visit(`/${team.name}/channels/${testChannel.name}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1371 User profile popover shows guest badge', () => {
|
||||
// # Post a day old message
|
||||
cy.postMessageAs({sender: guestUser, message: 'Hello from yesterday', channelId: testChannel.id}).
|
||||
its('id').
|
||||
should('exist').
|
||||
as('yesterdaysPost');
|
||||
|
||||
// * Verify Guest Badge when guest user posts a message in Center Channel
|
||||
cy.get('@yesterdaysPost').then((postId) => {
|
||||
cy.get(`#post_${postId}`).within(($el) => {
|
||||
cy.wrap($el).find('.post__header .Tag').should('be.visible');
|
||||
cy.wrap($el).find('.post__header .user-popover').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,106 @@
|
||||
// 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 @guest_account
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
function removeUserFromAllChannels(verifyAlert, user) {
|
||||
// # Remove the Guest user from all channels of a team as a sysadmin
|
||||
const channels = ['Town Square', 'Off-Topic'];
|
||||
|
||||
// # Always click on the Town Square channel first
|
||||
cy.get('#sidebarItem_town-square').click({force: true});
|
||||
|
||||
channels.forEach((channel) => {
|
||||
// # Remove the Guest User from channel
|
||||
cy.getCurrentChannelId().then((channelId) => {
|
||||
cy.removeUserFromChannel(channelId, user.id);
|
||||
});
|
||||
|
||||
// * Verify if guest user gets a message when the channel is removed. Does not appears when removed from last channel of the last team
|
||||
if (channel === 'Town Square' || verifyAlert) {
|
||||
cy.get('#removeFromChannelModalLabel').should('be.visible').and('have.text', `Removed from ${channel}`);
|
||||
cy.get('.modal-body').should('be.visible').contains(`removed you from ${channel}`);
|
||||
cy.get('#removedChannelBtn').should('be.visible').and('have.text', 'Okay').click().wait(TIMEOUTS.HALF_SEC);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Guest Account - Guest User Removal Experience', () => {
|
||||
let team1: Cypress.Team;
|
||||
let team2: Cypress.Team;
|
||||
let guest: Cypress.UserProfile;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
team1 = team;
|
||||
|
||||
// # Create new team and visit its URL
|
||||
cy.apiCreateTeam('test-team2', 'Test Team2').then(({team}) => {
|
||||
team2 = team;
|
||||
cy.apiCreateUser().then(({user}) => {
|
||||
guest = user;
|
||||
cy.apiAddUserToTeam(team1.id, guest.id);
|
||||
cy.apiAddUserToTeam(team2.id, guest.id).then(() => {
|
||||
cy.apiLogin(guest);
|
||||
cy.visit(`/${team2.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1360 Taken to login screen when removed from last channel', () => {
|
||||
// # Demote the current member to a guest user
|
||||
cy.apiAdminLogin();
|
||||
cy.apiDemoteUserToGuest(guest.id);
|
||||
|
||||
// # Login as guest user
|
||||
cy.apiLogin(guest);
|
||||
cy.reload();
|
||||
|
||||
// * Verify team Sidebar is visible
|
||||
cy.get('#teamSidebarWrapper').should('be.visible');
|
||||
|
||||
// # Remove User from all the channels of the team as a sysadmin
|
||||
removeUserFromAllChannels(true, guest);
|
||||
|
||||
// * Verify if user is automatically redirected to the other team
|
||||
cy.url().should('include', team1.name);
|
||||
|
||||
// * Verify team Sidebar is not present
|
||||
cy.get('#teamSidebarWrapper').should('not.exist');
|
||||
|
||||
// // # Remove User from all the channels of the team as a sysadmin
|
||||
removeUserFromAllChannels(false, guest);
|
||||
|
||||
// * Verify if the user is redirected to the Select Team page
|
||||
cy.url().should('include', '/select_team');
|
||||
cy.get('.signup__content').should('be.visible').and('have.text', 'Your guest account has no channels assigned. Please contact an administrator.');
|
||||
|
||||
// Login as sysadmin and verify test team 2
|
||||
cy.apiAdminLogin();
|
||||
cy.reload().visit(`/${team2.name}/channels/town-square`);
|
||||
|
||||
// * Verify if status is displayed indicating guest user is removed from the channel
|
||||
cy.getLastPost().
|
||||
should('contain', 'System').
|
||||
and('contain', `You and @${guest.username} joined the team.`).
|
||||
and('contain', `@${guest.username} was removed from the channel.`);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
export function changeGuestFeatureSettings(featureFlag = true, emailInvitation = true, whitelistedDomains = '') {
|
||||
// # Update Guest Accounts, Email Invitations, and Whitelisted Domains
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: featureFlag,
|
||||
RestrictCreationToDomains: whitelistedDomains,
|
||||
},
|
||||
ServiceSettings: {
|
||||
EnableEmailInvitations: emailInvitation,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function invitePeople(typeText: string, resultsCount: number, verifyText: string, channelName = 'Town Square', clickInvite = true) {
|
||||
// # Open team menu and click 'Invite People'
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
// # Click on the next icon to invite guest
|
||||
cy.findByTestId('inviteGuestLink').click();
|
||||
|
||||
// # Search and add a user
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').typeWithForce(typeText);
|
||||
});
|
||||
cy.get('.users-emails-input__menu').
|
||||
children().should('have.length', resultsCount).eq(0).should('contain', verifyText).click();
|
||||
|
||||
// # Search and add a Channel
|
||||
cy.get('.channels-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').typeWithForce(channelName);
|
||||
});
|
||||
cy.get('.channels-input__menu').
|
||||
children().should('have.length', 1).
|
||||
eq(0).should('contain', channelName).click();
|
||||
|
||||
if (clickInvite) {
|
||||
// # Click Invite Guests Button
|
||||
cy.get('#inviteGuestButton').scrollIntoView().click();
|
||||
}
|
||||
}
|
||||
|
||||
export function verifyInvitationError(user: string, team: Cypress.Team, errorText: string, verifyGuestBadge = false) {
|
||||
// * Verify the content and error message in the Invitation Modal
|
||||
cy.findByTestId('invitationModal').within(() => {
|
||||
cy.get('h1').should('have.text', `Guests invited to ${team.display_name}`);
|
||||
cy.get('div.invitation-modal-confirm--sent').should('not.exist');
|
||||
cy.get('div.invitation-modal-confirm--not-sent').should('be.visible').within(() => {
|
||||
cy.get('h2 > span').should('have.text', 'Invitations Not Sent');
|
||||
cy.get('.people-header').should('have.text', 'People');
|
||||
cy.get('.details-header').should('have.text', 'Details');
|
||||
cy.get('.username-or-icon').should('contain', user);
|
||||
cy.get('.reason').should('have.text', errorText);
|
||||
if (verifyGuestBadge) {
|
||||
cy.get('.username-or-icon .Tag').should('be.visible').and('have.text', 'GUEST');
|
||||
}
|
||||
});
|
||||
cy.findByTestId('confirm-done').should('be.visible').and('not.be.disabled').click();
|
||||
});
|
||||
|
||||
// * Verify if Invitation Modal was closed
|
||||
cy.get('.InvitationModal').should('not.exist');
|
||||
}
|
||||
|
||||
export function verifyInvitationSuccess(user: string, team: Cypress.Team, successText: string, verifyGuestBadge = false) {
|
||||
// * Verify the content and success message in the Invitation Modal
|
||||
cy.findByTestId('invitationModal').within(() => {
|
||||
cy.get('h1').should('have.text', `Guests invited to ${team.display_name}`);
|
||||
cy.get('div.invitation-modal-confirm--not-sent').should('not.exist');
|
||||
cy.get('div.invitation-modal-confirm--sent').should('be.visible').within(() => {
|
||||
cy.get('h2 > span').should('have.text', 'Successful Invites');
|
||||
cy.get('.people-header').should('have.text', 'People');
|
||||
cy.get('.details-header').should('have.text', 'Details');
|
||||
cy.get('.username-or-icon').should('contain', user);
|
||||
cy.get('.reason').should('have.text', successText);
|
||||
if (verifyGuestBadge) {
|
||||
cy.get('.username-or-icon .Tag').should('be.visible').and('have.text', 'GUEST');
|
||||
}
|
||||
});
|
||||
cy.findByTestId('confirm-done').should('be.visible').and('not.be.disabled').click();
|
||||
});
|
||||
|
||||
// * Verify if Invitation Modal was closed
|
||||
cy.get('.InvitationModal').should('not.exist');
|
||||
}
|
||||
|
||||
export function verifyGuest(userStatus = 'Guest ') {
|
||||
// * Verify if Guest User is displayed
|
||||
cy.findAllByTestId('userListRow').should('have.length', 1);
|
||||
cy.findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').and('have.text', userStatus);
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
// 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 @guest_account
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
import {getRandomId, stubClipboard} from '../../../../utils';
|
||||
import {getAdminAccount} from '../../../../support/env';
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('Guest Account - Member Invitation Flow', () => {
|
||||
const sysadmin = getAdminAccount();
|
||||
let testTeam: Cypress.Team;
|
||||
let testUser: Cypress.UserProfile;
|
||||
|
||||
beforeEach(() => {
|
||||
// # Login as sysadmin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
ServiceSettings: {
|
||||
EnableEmailInvitations: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testUser = user;
|
||||
testTeam = team;
|
||||
|
||||
// # Go to town square
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1323 Verify UI Elements of Members Invitation Flow - Accessing Invite People', () => {
|
||||
const email = `temp-${getRandomId()}@mattermost.com`;
|
||||
|
||||
// # Open team menu and click 'Invite People'
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
// * Verify UI Elements in initial step
|
||||
cy.findByTestId('invitationModal').within(() => {
|
||||
cy.get('h1').should('have.text', `Invite people to ${testTeam.display_name}`);
|
||||
});
|
||||
|
||||
stubClipboard().as('clipboard');
|
||||
|
||||
// * Verify share link button
|
||||
cy.findByTestId('InviteView__copyInviteLink').should('be.visible').should('have.text', 'Copy invite link').click();
|
||||
|
||||
// * Verify share link url
|
||||
const baseUrl = Cypress.config('baseUrl');
|
||||
|
||||
cy.get('@clipboard').its('contents').should('eq', `${baseUrl}/signup_user_complete/?id=${testTeam.invite_id}`);
|
||||
|
||||
cy.get('#inviteMembersButton').scrollIntoView().should('be.visible').and('be.disabled');
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
// * Verify the input placeholder text
|
||||
cy.get('.users-emails-input__placeholder').should('have.text', 'Enter a name or email address');
|
||||
|
||||
// # Type the email of the new user
|
||||
cy.get('input').typeWithForce(email);
|
||||
});
|
||||
cy.get('.users-emails-input__menu').
|
||||
children().should('have.length', 1).
|
||||
eq(0).should('contain', `Invite ${email} as a team member`).click();
|
||||
|
||||
// * Verify the clicking the close icon closes the modal
|
||||
cy.get('#closeIcon').should('be.visible').click();
|
||||
cy.get('.InvitationModal').should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T1324 Invite Members - Team Link - New User', () => {
|
||||
// # Wait for page to load and then logout. Else invite members link will be redirected to login page
|
||||
cy.uiGetPostTextBox().wait(TIMEOUTS.TWO_SEC);
|
||||
const inviteMembersLink = `/signup_user_complete/?id=${testTeam.invite_id}`;
|
||||
cy.apiLogout();
|
||||
|
||||
// # Visit the Invite Members link
|
||||
cy.visit(inviteMembersLink);
|
||||
|
||||
// * Verify the sign up options
|
||||
cy.findByText('AD/LDAP Credentials').scrollIntoView().should('be.visible');
|
||||
cy.findByText('Email address').should('be.visible');
|
||||
cy.findByPlaceholderText('Choose a Password').should('be.visible');
|
||||
|
||||
// # Sign up via email
|
||||
const username = `temp-${getRandomId()}`;
|
||||
const email = `${username}@mattermost.com`;
|
||||
cy.get('#input_email').type(email);
|
||||
cy.get('#input_name').type(username);
|
||||
cy.get('#input_password-input').type('Testing123');
|
||||
cy.findByText('Create Account').click();
|
||||
|
||||
// * Verify if user is added to the invited team
|
||||
cy.uiGetLHSHeader().findByText(testTeam.display_name);
|
||||
|
||||
// * Verify if user has access to the default channels
|
||||
cy.uiGetLhsSection('CHANNELS').within(() => {
|
||||
cy.findByText('Off-Topic').should('be.visible');
|
||||
cy.findByText('Town Square').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1325 Invite Members - Team Link - Existing User', () => {
|
||||
// # Login as sysadmin and create a new team
|
||||
cy.apiAdminLogin();
|
||||
cy.apiCreateTeam('team', 'Team').then(({team}) => {
|
||||
// # Visit the team and wait for page to load and then logout.
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
cy.uiGetPostTextBox().wait(TIMEOUTS.TWO_SEC);
|
||||
const inviteMembersLink = `/signup_user_complete/?id=${team.invite_id}`;
|
||||
cy.apiLogout();
|
||||
|
||||
// # Visit the Invite Members link
|
||||
cy.visit(inviteMembersLink);
|
||||
|
||||
// # Click on the login option
|
||||
cy.findByText('Log in').should('be.visible').click();
|
||||
|
||||
// # Login as user
|
||||
cy.get('#input_loginId').type(testUser.username);
|
||||
cy.get('#input_password-input').type('passwd');
|
||||
cy.get('#saveSetting').should('not.be.disabled').click();
|
||||
|
||||
// * Verify if user is added to the invited team
|
||||
cy.get(`#${testTeam.name}TeamButton`).as('teamButton').should('be.visible').within(() => {
|
||||
cy.get('.badge').should('be.visible').and('have.text', 1);
|
||||
});
|
||||
|
||||
cy.get('@teamButton').click().wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Verify if user has access to the default channels in the invited teams
|
||||
cy.uiGetLhsSection('CHANNELS').within(() => {
|
||||
cy.findByText('Off-Topic').should('be.visible');
|
||||
cy.findByText('Town Square').should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1326 Verify Invite Members - Existing Team Member', () => {
|
||||
cy.apiCreateTeam('team', 'Team').then(({team}) => {
|
||||
// # Login as new user
|
||||
loginAsNewUser(team);
|
||||
|
||||
// # Search and add an existing member by username who is part of the team
|
||||
invitePeople(sysadmin.username, 1, sysadmin.username);
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
verifyInvitationError(sysadmin.username, team, 'This person is already a team member.');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1328 Invite Members - Existing Member not on the team', () => {
|
||||
cy.apiCreateTeam('team', 'Team').then(({team}) => {
|
||||
// # Login as new user
|
||||
loginAsNewUser(team);
|
||||
|
||||
// # Search and add an existing member by email who is not part of the team
|
||||
invitePeople(testUser.email, 1, testUser.username);
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
verifyInvitationSuccess(testUser.username, team, 'This member has been added to the team.');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1329 Invite Members - Invite People - Existing Guest not on the team', () => {
|
||||
cy.apiCreateTeam('team', 'Team').then(({team}) => {
|
||||
// # Login as new user
|
||||
loginAsNewUser(team);
|
||||
|
||||
// # Search and add a new member by email who is not part of the team
|
||||
const email = `temp-${getRandomId()}@mattermost.com`;
|
||||
invitePeople(email, 1, email);
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
verifyInvitationSuccess(email, team, 'An invitation email has been sent.');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4450 Invite Member via Email containing upper case letters', () => {
|
||||
// # Login as new user
|
||||
loginAsNewUser(testTeam);
|
||||
|
||||
// # Invite a email containing uppercase letters
|
||||
const email = `tEMp-${getRandomId()}@mattermost.com`;
|
||||
invitePeople(email, 1, email);
|
||||
|
||||
// * Verify the content and message in next screen
|
||||
verifyInvitationSuccess(email, testTeam, 'An invitation email has been sent.');
|
||||
});
|
||||
|
||||
it('MM-T1330 Invite Members - New User not in the system', () => {
|
||||
// # Login as sysadmin and create a new team
|
||||
cy.apiAdminLogin();
|
||||
|
||||
cy.apiCreateTeam('team', 'Team').then(({team}) => {
|
||||
// # Login as new user
|
||||
loginAsNewUser(team);
|
||||
|
||||
// # Search and add an existing member by username who is part of the team
|
||||
invitePeople(testUser.email, 1, testUser.username, false);
|
||||
|
||||
// # Add a random username without proper email address format
|
||||
const username = `temp-${getRandomId()}`;
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').typeWithForce(username).tab();
|
||||
});
|
||||
|
||||
// # Click Invite Members
|
||||
cy.get('#inviteMembersButton').scrollIntoView().click();
|
||||
|
||||
// * Verify the content and message in the Invitation Modal
|
||||
cy.findByTestId('invitationModal').within(() => {
|
||||
cy.get('h1').should('have.text', `Members invited to ${team.display_name}`);
|
||||
cy.get('div.invitation-modal-confirm--not-sent').should('be.visible').within(() => {
|
||||
cy.get('h2 > span').should('have.text', 'Invitations Not Sent');
|
||||
cy.get('.people-header').should('have.text', 'People');
|
||||
cy.get('.details-header').should('have.text', 'Details');
|
||||
cy.get('.username-or-icon').should('contain', username);
|
||||
cy.get('.reason').should('have.text', 'Does not match a valid user or email.');
|
||||
});
|
||||
|
||||
cy.get('div.invitation-modal-confirm--sent').should('be.visible').within(() => {
|
||||
cy.get('h2 > span').should('have.text', 'Successful Invites');
|
||||
cy.get('.people-header').should('have.text', 'People');
|
||||
cy.get('.details-header').should('have.text', 'Details');
|
||||
cy.get('.username-or-icon').should('contain', testUser.username);
|
||||
cy.get('.reason').should('have.text', 'This member has been added to the team.');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function invitePeople(typeText, resultsCount, verifyText, clickInvite = true) {
|
||||
// # Open team menu and click 'Invite People'
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
// # Search and add a member
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').typeWithForce(typeText);
|
||||
});
|
||||
|
||||
cy.get('.users-emails-input__menu').
|
||||
children().should('have.length', resultsCount).eq(0).should('contain', verifyText).click();
|
||||
|
||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||
cy.get('input').tab();
|
||||
});
|
||||
|
||||
// # Click Invite Members
|
||||
if (clickInvite) {
|
||||
cy.get('#inviteMembersButton').scrollIntoView().click();
|
||||
}
|
||||
}
|
||||
|
||||
function verifyInvitationError(user, team, errorText) {
|
||||
// * Verify the content and error message in the Invitation Modal
|
||||
cy.findByTestId('invitationModal').within(() => {
|
||||
cy.get('h1').should('have.text', `Members invited to ${team.display_name}`);
|
||||
cy.get('div.invitation-modal-confirm--sent').should('not.exist');
|
||||
cy.get('div.invitation-modal-confirm--not-sent').should('be.visible').within(() => {
|
||||
cy.get('h2 > span').should('have.text', 'Invitations Not Sent');
|
||||
cy.get('.people-header').should('have.text', 'People');
|
||||
cy.get('.details-header').should('have.text', 'Details');
|
||||
cy.get('.username-or-icon').should('contain', user);
|
||||
cy.get('.reason').should('have.text', errorText);
|
||||
});
|
||||
cy.findByTestId('confirm-done').should('be.visible').and('not.be.disabled').click();
|
||||
});
|
||||
|
||||
// * Verify if Invitation Modal was closed
|
||||
cy.get('.InvitationModal').should('not.exist');
|
||||
}
|
||||
|
||||
function verifyInvitationSuccess(user, team, successText) {
|
||||
// * Verify the content and success message in the Invitation Modal
|
||||
cy.findByTestId('invitationModal').within(() => {
|
||||
cy.get('h1').should('have.text', `Members invited to ${team.display_name}`);
|
||||
cy.get('div.invitation-modal-confirm--not-sent').should('not.exist');
|
||||
cy.get('div.invitation-modal-confirm--sent').should('be.visible').within(() => {
|
||||
cy.get('h2 > span').should('have.text', 'Successful Invites');
|
||||
cy.get('.people-header').should('have.text', 'People');
|
||||
cy.get('.details-header').should('have.text', 'Details');
|
||||
cy.get('.username-or-icon').should('contain', user);
|
||||
cy.get('.reason').should('have.text', successText);
|
||||
});
|
||||
cy.findByTestId('confirm-done').should('be.visible').and('not.be.disabled').click();
|
||||
});
|
||||
|
||||
// * Verify if Invitation Modal was closed
|
||||
cy.get('.InvitationModal').should('not.exist');
|
||||
}
|
||||
|
||||
function loginAsNewUser(team) {
|
||||
// # Login as new user and get the user id
|
||||
cy.apiCreateUser().then(({user}) => {
|
||||
cy.apiAddUserToTeam(team.id, user.id);
|
||||
|
||||
cy.apiLogin(user);
|
||||
cy.visit(`/${team.name}`);
|
||||
});
|
||||
}
|
||||
@@ -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 @guest_account @mfa
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
describe('Guest Account - Verify Guest Access UI', () => {
|
||||
beforeEach(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
ServiceSettings: {
|
||||
EnableMultifactorAuthentication: false,
|
||||
},
|
||||
});
|
||||
|
||||
// # Visit System Console Users page
|
||||
cy.visit('/admin_console/authentication/guest_access');
|
||||
});
|
||||
|
||||
it('MM-18046 Verify Guest Access Screen', () => {
|
||||
// * Verify Enable Guest Access field
|
||||
cy.findByTestId('GuestAccountsSettings.Enable').should('be.visible').within(() => {
|
||||
cy.get('.control-label').should('be.visible').and('have.text', 'Enable Guest Access: ');
|
||||
});
|
||||
cy.findByTestId('GuestAccountsSettings.Enablehelp-text').should('be.visible').and('have.text', 'When true, external guest can be invited to channels within teams. Please see Permissions Schemes for which roles can invite guests.');
|
||||
|
||||
// * Verify Whitelisted Guest Domains field
|
||||
cy.findByTestId('GuestAccountsSettings.RestrictCreationToDomains').should('be.visible').within(() => {
|
||||
cy.get('.control-label').should('be.visible').and('have.text', 'Whitelisted Guest Domains:');
|
||||
});
|
||||
cy.findByTestId('GuestAccountsSettings.RestrictCreationToDomainshelp-text').should('be.visible').and('have.text', '(Optional) Guest accounts can be created at the system level from this list of allowed guest domains.');
|
||||
|
||||
// * Verify Guest MFA field when System MFA is not enabled
|
||||
cy.findByTestId('GuestAccountsSettings.EnforceMultifactorAuthentication').should('be.visible').within(() => {
|
||||
cy.get('.control-label').should('be.visible').and('have.text', 'Enforce Multi-factor Authentication: ');
|
||||
});
|
||||
cy.findByTestId('GuestAccountsSettings.EnforceMultifactorAuthenticationhelp-text').should('be.visible').and('have.text', 'Multi-factor authentication is currently not enabled.');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
ServiceSettings: {
|
||||
EnableMultifactorAuthentication: true,
|
||||
},
|
||||
});
|
||||
|
||||
// # Visit System Console Users page
|
||||
cy.visit('/admin_console/authentication/guest_access');
|
||||
|
||||
// * Verify Guest MFA field when System MFA is enabled
|
||||
cy.findByTestId('GuestAccountsSettings.EnforceMultifactorAuthenticationhelp-text').should('be.visible').and('have.text', 'Multi-factor authentication is currently not enforced.');
|
||||
});
|
||||
|
||||
it('MM-T1410 Confirmation Modal when Guest Access is disabled', () => {
|
||||
// # Disable Guest Access and save
|
||||
cy.findByTestId('GuestAccountsSettings.Enablefalse').click();
|
||||
|
||||
// * Verify the warning message
|
||||
cy.get('.error-message').should('be.visible').within(() => {
|
||||
cy.findByText('All current guest account sessions will be revoked, and marked as inactive').should('be.visible');
|
||||
});
|
||||
|
||||
// # Click on the Save Settings
|
||||
cy.get('#saveSetting').should('be.visible').click();
|
||||
|
||||
// * Verify the confirmation message displayed
|
||||
cy.get('#confirmModal').should('be.visible').within(() => {
|
||||
cy.get('#confirmModalLabel').should('be.visible').and('have.text', 'Save and Disable Guest Access?');
|
||||
cy.get('.modal-body').should('be.visible').and('have.text', 'Disabling guest access will revoke all current Guest Account sessions. Guests will no longer be able to login and new guests cannot be invited into Mattermost. Guest users will be marked as inactive in user lists. Enabling this feature will not reinstate previous guest accounts. Are you sure you wish to remove these users?');
|
||||
cy.get('#confirmModalButton').should('have.text', 'Save and Disable Guest Access');
|
||||
});
|
||||
|
||||
// * Verify the behavior when Cancel button in the confirmation message is clicked
|
||||
cy.get('#cancelModalButton').click();
|
||||
cy.get('#confirmModal').should('not.exist');
|
||||
cy.get('.error-message').should('be.visible');
|
||||
|
||||
// # Click on the Save Settings, confirm and wait for some time to complete successful save
|
||||
cy.get('#saveSetting').should('be.visible').click();
|
||||
cy.get('#confirmModalButton').should('be.visible').click().wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// # Visit the chat facing application
|
||||
cy.get('.header__info').should('be.visible').click();
|
||||
cy.findByLabelText('Admin Console Menu').should('exist').within(() => {
|
||||
cy.findByText('Switch to eligendi').click();
|
||||
});
|
||||
|
||||
// # Open team menu and click 'Invite People'
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
// * Verify that an option to Invite via Guest should not be available
|
||||
cy.findByTestId('inviteGuestLink').should('not.exist');
|
||||
cy.get('.users-emails-input__control').should('be.visible');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
// 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 @guest_account @not_cloud
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
import {verifyGuest} from './helpers';
|
||||
|
||||
describe('Guest Account - Verify Manage Guest Users', () => {
|
||||
let guestUser: Cypress.UserProfile;
|
||||
let testTeam: Cypress.Team;
|
||||
let testChannel: Cypress.Channel;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
});
|
||||
|
||||
// # Create team and guest user account
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// # Visit System Console Users page
|
||||
cy.visit('/admin_console/user_management/users');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Reload current page before each test
|
||||
cy.reload();
|
||||
|
||||
// # Search for Guest User by username
|
||||
cy.get('#searchUsers', {timeout: TIMEOUTS.HALF_MIN}).should('be.visible').type(guestUser.username);
|
||||
});
|
||||
|
||||
it('MM-18048 Deactivate Guest User and Verify', () => {
|
||||
// # Click on the Deactivate option
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').click();
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByText('Deactivate').click();
|
||||
|
||||
// * Verify the confirmation message displayed
|
||||
cy.get('#confirmModal').should('be.visible').within(() => {
|
||||
cy.get('#confirmModalLabel').should('be.visible').and('have.text', `Deactivate ${guestUser.username}`);
|
||||
cy.get('.modal-body').should('be.visible').and('have.text', `This action deactivates ${guestUser.username}. They will be logged out and not have access to any teams or channels on this system. Are you sure you want to deactivate ${guestUser.username}?`);
|
||||
});
|
||||
|
||||
// * Verify the behavior when Cancel button in the confirmation message is clicked
|
||||
cy.get('#cancelModalButton').click();
|
||||
cy.get('#confirmModal').should('not.exist');
|
||||
verifyGuest();
|
||||
|
||||
// * Verify the behavior when Deactivate button in the confirmation message is clicked
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').click();
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByText('Deactivate').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
cy.get('#confirmModal').should('not.exist');
|
||||
verifyGuest('Inactive ');
|
||||
|
||||
// # Reload and verify if behavior is same
|
||||
cy.reload();
|
||||
cy.get('#searchUsers').should('be.visible').type(guestUser.username);
|
||||
verifyGuest('Inactive ');
|
||||
});
|
||||
|
||||
it('MM-18048 Activate Guest User and Verify', () => {
|
||||
// # Click on the Activate option
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').click();
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByText('Activate').click();
|
||||
|
||||
// * Verify if User's status is activated again
|
||||
verifyGuest();
|
||||
|
||||
// # Reload and verify if behavior is same
|
||||
cy.reload();
|
||||
cy.get('#searchUsers').should('be.visible').type(guestUser.username);
|
||||
verifyGuest();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
// 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 @guest_account
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
import {getRandomId} from '../../../../utils';
|
||||
import {getAdminAccount} from '../../../../support/env';
|
||||
|
||||
import {verifyGuest} from './helpers';
|
||||
|
||||
describe('Guest Account - Verify Manage Guest Users', () => {
|
||||
const admin = getAdminAccount();
|
||||
let guestUser: Cypress.UserProfile;
|
||||
let testTeam: Cypress.Team;
|
||||
let testChannel: Cypress.Channel;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for Guest Accounts
|
||||
cy.apiRequireLicenseForFeature('GuestAccounts');
|
||||
|
||||
// # Enable GuestAccountSettings
|
||||
cy.apiUpdateConfig({
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
});
|
||||
|
||||
// # Create team and guest user account
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// # Visit System Console Users page
|
||||
cy.visit('/admin_console/user_management/users');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Reload current page before each test
|
||||
cy.reload();
|
||||
|
||||
// # Search for Guest User by username
|
||||
cy.get('#searchUsers', {timeout: TIMEOUTS.HALF_MIN}).should('be.visible').type(guestUser.username);
|
||||
});
|
||||
|
||||
it('MM-T1391 Verify the manage options displayed for Guest User', () => {
|
||||
// * Verify Guest user
|
||||
verifyGuest();
|
||||
|
||||
// # Click on the Manage User option
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').click();
|
||||
|
||||
// * Verify the manage options which should be displayed for Guest User
|
||||
const includeOptions = ['Deactivate', 'Manage Roles', 'Manage Teams', 'Reset Password', 'Update Email', 'Promote to Member', 'Revoke Sessions'];
|
||||
includeOptions.forEach((includeOption) => {
|
||||
cy.findByText(includeOption).should('be.visible');
|
||||
});
|
||||
|
||||
// * Verify the manage options which should not be displayed for Guest user
|
||||
const missingOptions = ['Demote to Guest'];
|
||||
missingOptions.forEach((missingOption) => {
|
||||
cy.findByText(missingOption).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-18048 Change Email of a Guest User and Verify', () => {
|
||||
// # Click on the Update Email option
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').click();
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByText('Update Email').click();
|
||||
|
||||
// * Update email of Guest User
|
||||
const email = `temp-${getRandomId()}@mattermost.com`;
|
||||
cy.findByTestId('resetEmailModal').should('be.visible').within(() => {
|
||||
cy.findByTestId('resetEmailForm').should('be.visible').get('input').type(email);
|
||||
cy.findByTestId('resetEmailButton').click();
|
||||
});
|
||||
|
||||
// * Verify if Guest's email was updated
|
||||
cy.findByText(email).should('be.visible');
|
||||
|
||||
// # Reload and verify if behavior is same
|
||||
cy.reload();
|
||||
cy.get('#searchUsers').should('be.visible').type(guestUser.username);
|
||||
cy.findByText(email).should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-18048 Revoke Session of a Guest User and Verify', () => {
|
||||
// # Click on the Revoke Session option
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByTestId('userListRow').find('.MenuWrapper a').should('be.visible').click();
|
||||
cy.wait(TIMEOUTS.HALF_SEC).findByText('Revoke Sessions').click();
|
||||
|
||||
// * Verify the confirmation message displayed
|
||||
cy.get('#confirmModal').should('be.visible').within(() => {
|
||||
cy.get('#confirmModalLabel').should('be.visible').and('have.text', `Revoke Sessions for ${guestUser.username}`);
|
||||
cy.get('.modal-body').should('be.visible').and('have.text', `This action revokes all sessions for ${guestUser.username}. They will be logged out from all devices. Are you sure you want to revoke all sessions for ${guestUser.username}?`);
|
||||
});
|
||||
|
||||
// * Verify the behavior when Cancel button in the confirmation message is clicked
|
||||
cy.get('#cancelModalButton').click();
|
||||
cy.get('#confirmModal').should('not.exist');
|
||||
|
||||
// # Logout sysadmin and login as Guest User to verify if Revoke Session works
|
||||
cy.apiLogout();
|
||||
cy.apiLogin(guestUser);
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
cy.get(`#sidebarItem_${testChannel.name}`).click({force: true});
|
||||
|
||||
// # Issue a Request to Revoke All Sessions as SysAdmin
|
||||
cy.externalRequest({user: admin, method: 'post', path: `users/${guestUser.id}/sessions/revoke/all`}).then(() => {
|
||||
// # Initiate browser activity like visit on test channel
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// * Verify if the regular member is logged out and redirected to login page
|
||||
cy.url({timeout: TIMEOUTS.HALF_MIN}).should('include', '/login');
|
||||
cy.get('.login-body-card', {timeout: TIMEOUTS.HALF_MIN}).should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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 @elasticsearch @incoming_webhook @not_cloud
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
import {
|
||||
enableElasticSearch,
|
||||
} from '../elasticsearch_autocomplete/helpers';
|
||||
|
||||
describe('Incoming webhook', () => {
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
let incomingWebhook;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
// # Create and visit new channel and create incoming webhook
|
||||
cy.apiInitSetup().then(({team, channel}) => {
|
||||
testTeam = team;
|
||||
testChannel = channel;
|
||||
|
||||
const newIncomingHook = {
|
||||
channel_id: channel.id,
|
||||
channel_locked: false,
|
||||
description: 'Incoming webhook - basic formatting',
|
||||
display_name: 'basic-formatting',
|
||||
};
|
||||
|
||||
cy.apiCreateWebhook(newIncomingHook).then((hook) => {
|
||||
incomingWebhook = hook;
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiRequireLicenseForFeature('Elasticsearch');
|
||||
enableElasticSearch();
|
||||
});
|
||||
|
||||
it('MM-T633 Text in Slack-style attachment is searchable', () => {
|
||||
const id = 'MM-T633';
|
||||
|
||||
const payload = {
|
||||
title: 'Title',
|
||||
attachments: [{
|
||||
type: 'slack_attachment',
|
||||
color: '#7CD197',
|
||||
fields: [{short: false, title: 'Area', value: 'This is a test post from the Integrations tab of release testing that will be deleted by someone who has the admin level permissions to do so.'}],
|
||||
text: `${id} This is the text of the attachment. This text should be searchable. Findme.`,
|
||||
}],
|
||||
};
|
||||
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
cy.postIncomingWebhook({url: incomingWebhook.url, data: payload});
|
||||
|
||||
cy.get('#searchBox').wait(TIMEOUTS.HALF_SEC).typeWithForce('findme').typeWithForce('{enter}');
|
||||
|
||||
cy.get('#search-items-container').within(() => {
|
||||
cy.get('.attachment__body').should('contain', id);
|
||||
cy.get('.attachment__body').should('contain', 'Findme.');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,507 @@
|
||||
// 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 @ldap
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
function setLDAPTestSettings(config) {
|
||||
return {
|
||||
siteName: config.TeamSettings.SiteName,
|
||||
siteUrl: config.ServiceSettings.SiteURL,
|
||||
teamName: '',
|
||||
user: null,
|
||||
};
|
||||
}
|
||||
|
||||
// assumes the CYPRESS_* variables are set
|
||||
// assumes that E20 license is uploaded
|
||||
// for setup with AWS: Follow the instructions mentioned in the mattermost/platform-private/config/ldap-test-setup.txt file
|
||||
context('ldap', () => {
|
||||
let testChannel;
|
||||
let testTeam;
|
||||
let testUser;
|
||||
|
||||
describe('LDAP Group Sync Automated Tests', () => {
|
||||
beforeEach(() => {
|
||||
// # Login as sysadmin and add board-one to test team
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// * Check if server has license for LDAP
|
||||
cy.apiRequireLicenseForFeature('LDAP');
|
||||
|
||||
// # Initial api setup
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testTeam = team;
|
||||
testUser = user;
|
||||
|
||||
// # Update LDAP settings
|
||||
cy.apiGetConfig().then(({config}) => {
|
||||
setLDAPTestSettings(config);
|
||||
});
|
||||
|
||||
// # Link board group
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#board_group').then((el) => {
|
||||
if (!el.text().includes('Edit')) {
|
||||
// # Link the Group if its not linked before
|
||||
if (el.find('.icon.fa-unlink').length > 0) {
|
||||
el.find('.icon.fa-unlink').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// # Link developers group
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#developers_group').then((el) => {
|
||||
if (!el.text().includes('Edit')) {
|
||||
// # Link the Group if its not linked before
|
||||
if (el.find('.icon.fa-unlink').length > 0) {
|
||||
el.find('.icon.fa-unlink').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// # Create a test channel
|
||||
cy.apiCreateChannel(testTeam.id, 'ldap-group-sync-automated-tests', 'ldap-group-sync-automated-tests').then(({channel}) => {
|
||||
testChannel = channel;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1537 - Sync Group Removal from Channel Configuration Page', () => {
|
||||
// # Link 2 groups to testChannel
|
||||
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration');
|
||||
cy.wait(TIMEOUTS.TWO_SEC); //eslint-disable-line cypress/no-unnecessary-waiting
|
||||
|
||||
// # Link first group
|
||||
cy.get('#addGroupsToChannelToggle').click();
|
||||
cy.get('#multiSelectList').should('be.visible');
|
||||
cy.get('#multiSelectList>div').children().eq(0).click();
|
||||
cy.uiGetButton('Add').click();
|
||||
|
||||
// # Link second group
|
||||
cy.get('#addGroupsToChannelToggle').click();
|
||||
cy.get('#multiSelectList').should('be.visible');
|
||||
cy.get('#multiSelectList>div').children().eq(0).click();
|
||||
cy.uiGetButton('Add').click();
|
||||
|
||||
// # Click save settings on bottom screen to save settings
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Mattermost Channels');
|
||||
|
||||
// # Go back to the testChannel management page
|
||||
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration');
|
||||
|
||||
// # Remove the board group we have added
|
||||
cy.get('.group-row').eq(0).scrollIntoView().should('be.visible').within(() => {
|
||||
cy.get('.group-name').should('have.text', 'board');
|
||||
cy.get('.group-actions > a').should('have.text', 'Remove').click();
|
||||
});
|
||||
|
||||
// # Save settings
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Mattermost Channels');
|
||||
|
||||
// # Go back to testChannel management page
|
||||
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration');
|
||||
|
||||
// * Ensure we only have one group row (other group is not there)
|
||||
cy.get('.group-row').should('have.length', 1);
|
||||
});
|
||||
|
||||
it('MM-T2618 - Team Configuration Page: Group removal User removed from sync\'ed team', () => {
|
||||
// # Add board-one to test team
|
||||
cy.visit(`/admin_console/user_management/teams/${testTeam.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Team Configuration');
|
||||
cy.wait(TIMEOUTS.TWO_SEC); //eslint-disable-line cypress/no-unnecessary-waiting
|
||||
|
||||
// # Turn on sync group members
|
||||
cy.findByTestId('syncGroupSwitch').
|
||||
scrollIntoView().
|
||||
findByRole('button').
|
||||
click({force: true});
|
||||
|
||||
// # Add board group to team
|
||||
cy.get('#addGroupsToTeamToggle').scrollIntoView().click();
|
||||
cy.get('#multiSelectList').should('be.visible');
|
||||
cy.get('#multiSelectList>div').children().eq(0).click();
|
||||
cy.uiGetButton('Add').click().wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// # Save settings
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
// # Accept confirmation modal
|
||||
cy.get('#confirmModalButton').should('be.visible').click();
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Mattermost Teams');
|
||||
|
||||
// # Go to board group edit page
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#board_edit').click();
|
||||
|
||||
// # Remove the group
|
||||
cy.findByTestId(`${testTeam.display_name}_groupsyncable_remove`).click();
|
||||
|
||||
// * Ensure the confirmation modal shows with the following text
|
||||
cy.get('#confirmModalBody').should('be.visible').and('have.text', `Removing this membership will prevent future users in this group from being added to the ${testTeam.display_name} team.`);
|
||||
|
||||
// # Accept the modal and save settings
|
||||
cy.get('#confirmModalButton').should('be.visible').click();
|
||||
cy.get('#saveSetting').click();
|
||||
});
|
||||
|
||||
it('MM-T2621 - Team List Management Column', () => {
|
||||
let testTeam2;
|
||||
|
||||
// # Go to testTeam config page
|
||||
cy.visit(`/admin_console/user_management/teams/${testTeam.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Team Configuration');
|
||||
cy.wait(TIMEOUTS.TWO_SEC); //eslint-disable-line cypress/no-unnecessary-waiting
|
||||
|
||||
// # Make the team so anyone can join it
|
||||
cy.findByTestId('allowAllToggleSwitch').scrollIntoView().click();
|
||||
|
||||
// # Save the settings
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Mattermost Teams');
|
||||
|
||||
// # Start with a new team
|
||||
cy.apiCreateTeam('team', 'Team').then(({team}) => {
|
||||
testTeam2 = team;
|
||||
|
||||
// # Go to team management
|
||||
cy.visit('/admin_console/user_management/teams');
|
||||
|
||||
// # Search for the team testTeam
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').should('be.visible').type(`${testTeam.display_name}{enter}`);
|
||||
});
|
||||
|
||||
// * Ensure anyone can join text shows
|
||||
cy.findByTestId(`${testTeam.name}Management`).should('have.text', 'Anyone Can Join');
|
||||
|
||||
// * Search for second team we just made
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').should('be.visible').clear().type(`${testTeam2.display_name}{enter}`);
|
||||
});
|
||||
|
||||
// * Ensure the management text shows Invite only
|
||||
cy.findByTestId(`${testTeam2.name}Management`).should('have.text', 'Invite Only');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2628 - List of Channels', () => {
|
||||
// # Add board-one to test team
|
||||
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration');
|
||||
cy.wait(TIMEOUTS.TWO_SEC); //eslint-disable-line cypress/no-unnecessary-waiting
|
||||
|
||||
// Make it private and then cancel
|
||||
cy.findByTestId('allow-all-toggle').click();
|
||||
cy.get('#cancelButtonSettings').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration');
|
||||
|
||||
// * Ensure it still public
|
||||
cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public');
|
||||
|
||||
// Make it private and save
|
||||
cy.findByTestId('allow-all-toggle').click();
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
|
||||
// # Visit the channel config page for testChannel
|
||||
cy.visit(`/admin_console/user_management/channels/${testChannel.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration');
|
||||
|
||||
// * Ensure it is Private
|
||||
cy.findByTestId('allow-all-toggle').should('has.have.text', 'Private');
|
||||
|
||||
// # Go to team page to look for this channel in public channel directory
|
||||
cy.visit(`/${testTeam.name}`);
|
||||
cy.uiBrowseOrCreateChannel('Browse Channels').click();
|
||||
|
||||
// * Search private channel name and make sure it isn't there in public channel directory
|
||||
cy.get('#searchChannelsTextbox').type(testChannel.display_name);
|
||||
cy.get('#moreChannelsList').should('include.text', 'No more channels to join');
|
||||
});
|
||||
|
||||
it('MM-T2629 - Private to public - More....', () => {
|
||||
// # Create new test channel that is private
|
||||
cy.apiCreateChannel(
|
||||
testTeam.id,
|
||||
'private-channel-test',
|
||||
'Private channel',
|
||||
'P',
|
||||
).then(({channel}) => {
|
||||
const privateChannel = channel;
|
||||
|
||||
// # Visit channel configuration of private channel
|
||||
cy.visit(`/admin_console/user_management/channels/${privateChannel.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration');
|
||||
|
||||
// Make it public and then cancel
|
||||
cy.findByTestId('allow-all-toggle').click();
|
||||
cy.get('#cancelButtonSettings').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Mattermost Channels');
|
||||
|
||||
// Reload
|
||||
cy.visit(`/admin_console/user_management/channels/${privateChannel.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration');
|
||||
cy.wait(TIMEOUTS.THREE_SEC); //eslint-disable-line cypress/no-unnecessary-waiting
|
||||
|
||||
// Make it public and save
|
||||
// * Ensure it still showing the channel as private
|
||||
cy.findByTestId('allow-all-toggle').should('has.have.text', 'Private').click();
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Mattermost Channels');
|
||||
|
||||
// Reload
|
||||
cy.visit(`/admin_console/user_management/channels/${privateChannel.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration');
|
||||
|
||||
// * Ensure it still showing the channel as private
|
||||
cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public');
|
||||
|
||||
// # Ensure the last message in the message says that it was converted to a public channel
|
||||
cy.visit(`/${testTeam.name}/channels/${privateChannel.name}`);
|
||||
cy.getLastPostId().then((id) => {
|
||||
// * The system message should contain 'This channel has been converted to a Public Channel and can be joined by any team member'
|
||||
cy.get(`#postMessageText_${id}`).should('contain', 'This channel has been converted to a Public Channel and can be joined by any team member');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2630 - Default channel cannot be toggled to private', () => {
|
||||
cy.visit('/admin_console/user_management/channels');
|
||||
|
||||
// # Search for the channel town square
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').should('be.visible').type('Town Square');
|
||||
});
|
||||
cy.wait(TIMEOUTS.FIVE_SEC); //eslint-disable-line cypress/no-unnecessary-waiting
|
||||
|
||||
cy.findAllByTestId('town-squareedit').then((elements) => {
|
||||
elements[0].click();
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration');
|
||||
|
||||
// * Ensure the toggle to private/public is disabled
|
||||
cy.findByTestId('allow-all-toggle-button').should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2638 - Permalink from when public does not auto-join (non-system-admin) after converting to private', () => {
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// # Post message to use
|
||||
cy.postMessage('DONT YOU SEE I GOT EVERYTHING YOU NEED .... BABY BABY DONT YOU SEE SEE I GOT EVERYTHING YOU NEED NEED ... ;)');
|
||||
|
||||
cy.getLastPostId().then((id) => {
|
||||
const postId = id;
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// # Post /leave command in testChannel to leave it
|
||||
cy.postMessage('/leave ');
|
||||
cy.get('#channelHeaderTitle', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('contain', 'Town Square');
|
||||
|
||||
// Visit the permalink link
|
||||
cy.visit(`/${testTeam.name}/pl/${postId}`);
|
||||
|
||||
// * Ensure the header of the permalink channel is what we expect it to be (testChannel)
|
||||
cy.get('#channelHeaderTitle', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('contain', testChannel.display_name);
|
||||
|
||||
// # Leave the channel again
|
||||
cy.postMessage('/leave ');
|
||||
cy.get('#channelHeaderTitle', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('contain', 'Town Square');
|
||||
|
||||
// # Login as sysadmin and convert testChannel to private channel
|
||||
cy.apiAdminLogin();
|
||||
cy.apiPatchChannelPrivacy(testChannel.id, 'P');
|
||||
|
||||
// # Login as normal user and try to visit the permalink
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${testTeam.name}/pl/${postId}`);
|
||||
|
||||
// * We expect an error that says "Message not found"
|
||||
cy.findByTestId('errorMessageTitle').contains('Message Not Found');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2639 - Policy settings (in System Console tests, likely)', () => {
|
||||
// # Reset system scheme permission
|
||||
cy.uiResetPermissionsToDefault();
|
||||
|
||||
// # Login as testUser and go to channel configuration page of testChannel
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// # Go to manage members rhs and ensure that we can add members to it
|
||||
cy.get('.member-rhs__trigger').click();
|
||||
cy.uiGetRHS().contains('button', 'Add').should('exist').click();
|
||||
|
||||
// * Assess that label is visible and it says we can add new members
|
||||
cy.get('#addUsersToChannelModal').should('be.visible').findByText(`Add people to ${testChannel.display_name}`);
|
||||
|
||||
// # Login as sysadmin and navigate to system scheme page and check off all users can manage private manage channels
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/user_management/permissions/system_scheme');
|
||||
cy.findByTestId('all_users-private_channel-checkbox').click();
|
||||
|
||||
// # Save the settings
|
||||
cy.uiSaveConfig();
|
||||
|
||||
// # Login as sysadmin and convert testChannel to private channel
|
||||
cy.apiPatchChannelPrivacy(testChannel.id, 'P');
|
||||
|
||||
// # Go back to the channel
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// # Go to manage member modal
|
||||
cy.get('.member-rhs__trigger').click();
|
||||
|
||||
// * Assert that the label doesn't exist anymore mentioning we can invite members
|
||||
cy.uiGetRHS().contains('button', 'Add').should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T2640 - Channel appears in channel switcher before conversion but not after (for non-members of the channel)', () => {
|
||||
// # Reset system scheme permissions
|
||||
cy.uiResetPermissionsToDefault();
|
||||
|
||||
// # Create new test channel that is public
|
||||
cy.apiCreateChannel(
|
||||
testTeam.id,
|
||||
'a-channel-im-not-apart-off',
|
||||
'Public channel',
|
||||
'O',
|
||||
).then(({channel: publicChannel}) => {
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// # Open Find Channels
|
||||
cy.uiOpenFindChannels();
|
||||
|
||||
// * Channel switcher hint should be visible
|
||||
cy.get('#quickSwitchHint', {timeout: TIMEOUTS.TWO_SEC}).should('be.visible').should('contain', 'Type to find a channel. Use UP/DOWN to browse, ENTER to select, ESC to dismiss.');
|
||||
cy.wait(TIMEOUTS.THREE_SEC);
|
||||
|
||||
// # Type channel display name on Channel switcher input
|
||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(publicChannel.display_name);
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Should open up suggestion list for channels
|
||||
// * Should match each channel item and group label
|
||||
cy.get('#suggestionList').should('be.visible').children().within((el) => {
|
||||
cy.wrap(el).should('contain', publicChannel.display_name);
|
||||
});
|
||||
|
||||
// # Login as a admin and make channel private
|
||||
cy.apiAdminLogin();
|
||||
cy.apiPatchChannelPrivacy(publicChannel.id, 'P');
|
||||
|
||||
// # Login as normal user
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// # Open Find Channels
|
||||
cy.uiOpenFindChannels();
|
||||
|
||||
// * Channel switcher hint should be visible
|
||||
cy.get('#quickSwitchHint', {timeout: TIMEOUTS.TWO_SEC}).should('be.visible').should('contain', 'Type to find a channel. Use UP/DOWN to browse, ENTER to select, ESC to dismiss.');
|
||||
cy.wait(TIMEOUTS.THREE_SEC);
|
||||
|
||||
// # Type channel display name on Channel switcher input
|
||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(publicChannel.display_name);
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Should open up suggestion list for channels
|
||||
// * should no results after looking for channel
|
||||
cy.get('.no-results__title').should('be.visible').and('contain.text', 'No results for');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2641 - Channel appears in More... under Public Channels before conversion but not after', () => {
|
||||
// # Create new test channel that is public
|
||||
cy.apiCreateChannel(
|
||||
testTeam.id,
|
||||
'a-channel-im-not-apart-off',
|
||||
'Public channel',
|
||||
'O',
|
||||
).then(({channel: publicChannel}) => {
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Visit off-topic channel
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// # Go to LHS and click 'Browse Channels'
|
||||
cy.uiBrowseOrCreateChannel('Browse Channels').click();
|
||||
|
||||
// * Search public channel and ensure it appears in the list
|
||||
cy.get('#searchChannelsTextbox').type(publicChannel.display_name);
|
||||
cy.get('#moreChannelsList').should('include.text', publicChannel.display_name);
|
||||
|
||||
// # login as a admin and revert to private channel
|
||||
cy.apiAdminLogin();
|
||||
cy.apiPatchChannelPrivacy(publicChannel.id, 'P');
|
||||
|
||||
// # Login as a normal user
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Visit off-topic channel
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// # Go to LHS and click 'Browse Channels'
|
||||
cy.uiBrowseOrCreateChannel('Browse Channels').click();
|
||||
|
||||
// * Search private channel name and make sure it isn't there in public channel directory
|
||||
cy.get('#searchChannelsTextbox').type(publicChannel.display_name);
|
||||
cy.get('#moreChannelsList').should('include.text', 'No more channels to join');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2642 - Channel appears in Integrations options before conversion but not after', () => {
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// # Go to integrations
|
||||
cy.visit(`/${testTeam.name}/integrations`);
|
||||
|
||||
// # Go to outgoing webhooks and then add out going web hooks page
|
||||
cy.get('#outgoingWebhooks', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').click();
|
||||
cy.get('#addOutgoingWebhook', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').click();
|
||||
|
||||
// * In the channel select options, ensure our display name appears
|
||||
cy.get('#channelSelect').children().should('contain.text', testChannel.display_name);
|
||||
|
||||
// # Make channel private
|
||||
cy.apiPatchChannelPrivacy(testChannel.id, 'P');
|
||||
|
||||
// # Go to integrations
|
||||
cy.visit(`/${testTeam.name}/integrations`);
|
||||
|
||||
// # Go to outgoing webhooks and then add out going web hooks page
|
||||
cy.get('#outgoingWebhooks', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').click();
|
||||
cy.get('#addOutgoingWebhook', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').click();
|
||||
|
||||
// * Ensure that our channel name doesn't appear in the list of options
|
||||
cy.get('#channelSelect').children().should('not.contain.text', testChannel.display_name);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,322 @@
|
||||
// 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 @ldap
|
||||
|
||||
import ldapUsers from '../../../../fixtures/ldap_users.json';
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
import {getAdminAccount} from '../../../../support/env';
|
||||
import {getRandomId} from '../../../../utils';
|
||||
|
||||
// assumes that E20 license is uploaded
|
||||
// for setup with AWS: Follow the instructions mentioned in the mattermost/platform-private/config/ldap-test-setup.txt file
|
||||
describe('LDAP guest', () => {
|
||||
let testSettings;
|
||||
let user1Data;
|
||||
let user2Data;
|
||||
|
||||
const user1 = ldapUsers['test-2'];
|
||||
const user2 = ldapUsers['test-3'];
|
||||
const userBoard1 = ldapUsers['board-1'];
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP
|
||||
cy.apiRequireLicenseForFeature('LDAP');
|
||||
|
||||
// # Test LDAP configuration and server connection
|
||||
// # Synchronize user attributes
|
||||
cy.apiLDAPTest();
|
||||
cy.apiLDAPSync();
|
||||
|
||||
// # Get testSettings
|
||||
cy.apiGetConfig().then(({config}) => {
|
||||
testSettings = setLDAPTestSettings(config);
|
||||
});
|
||||
|
||||
// # Get user1 data
|
||||
cy.apiLogin(user1).then(({user}) => {
|
||||
user1Data = user;
|
||||
|
||||
// # Remove user1 from all the teams
|
||||
removeUserFromAllTeams(user1Data);
|
||||
});
|
||||
|
||||
// # Get user2 data
|
||||
cy.apiLogin(user2).then(({user}) => {
|
||||
user2Data = user;
|
||||
|
||||
// # Remove user2 fromm all the teams
|
||||
removeUserFromAllTeams(user2Data);
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Login as admin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Make sure LDAP users are not guests
|
||||
promoteGuestToUser(user1Data);
|
||||
promoteGuestToUser(user2Data);
|
||||
});
|
||||
|
||||
it('MM-T1422 LDAP Guest Filter', () => {
|
||||
// # Go to LDAP settings page and update guest filter as user1
|
||||
gotoLDAPSettings();
|
||||
updateGuestFilter(`(uid=${user1.username})`);
|
||||
|
||||
// # Login as LDAP user1
|
||||
testSettings.user = user1;
|
||||
cy.doLDAPLogin(testSettings);
|
||||
|
||||
// * Verify select teams page is loaded
|
||||
cy.get('.select-team__container', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
|
||||
|
||||
// * Verify user does not have access to any team or channel
|
||||
cy.get('.signup__content').should('have.text', 'Your guest account has no channels assigned. Please contact an administrator.');
|
||||
|
||||
// # Logout of LDAP user
|
||||
cy.apiLogout().then(() => {
|
||||
// # Login as admin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Go to LDAP settings page and EMPTY guest filter value
|
||||
gotoLDAPSettings();
|
||||
updateGuestFilter('');
|
||||
|
||||
// # Login again as LDAP user1
|
||||
testSettings.user = user1;
|
||||
cy.doLDAPLogin(testSettings);
|
||||
|
||||
// * Verify select teams page is loaded
|
||||
cy.get('.select-team__container', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
|
||||
|
||||
// * Verify user1 is still a guest user
|
||||
cy.get('#createNewTeamLink').should('not.exist');
|
||||
|
||||
cy.apiLogout().then(() => {
|
||||
// # Login again as LDAP user2
|
||||
testSettings.user = user2;
|
||||
cy.doLDAPLogin(testSettings);
|
||||
|
||||
// * Verify select teams page is loaded
|
||||
cy.get('.select-team__container', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
|
||||
|
||||
// * Verify user2 is not a guest
|
||||
cy.get('#createNewTeamLink').should('exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1424 LDAP Guest Filter behavior when Guest Access is disabled', () => {
|
||||
// # Go to Guest access page and enable guest access
|
||||
gotoGuestAccessSettings();
|
||||
setGuestAccess(true);
|
||||
|
||||
// # Go to LDAP settings page and update guest filter as user1
|
||||
gotoLDAPSettings();
|
||||
updateGuestFilter(`(uid=${user1.username})`);
|
||||
|
||||
// # Go to Guest access page and disable guest access
|
||||
gotoGuestAccessSettings();
|
||||
setGuestAccess(false);
|
||||
|
||||
// # Go to LDAP settings page
|
||||
gotoLDAPSettings();
|
||||
cy.findByTestId('LdapSettings.GuestFilterinput').should('have.attr', 'disabled');
|
||||
|
||||
// # Go to SAML settings page
|
||||
cy.visit('/admin_console/authentication/saml');
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'SAML 2.0');
|
||||
cy.findByTestId('SamlSettings.GuestAttributeinput').should('be.disabled');
|
||||
|
||||
// # Login again as LDAP user1
|
||||
testSettings.user = user1;
|
||||
cy.doLDAPLogin(testSettings);
|
||||
|
||||
// * Verify select teams page is loaded
|
||||
cy.get('.select-team__container', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
|
||||
|
||||
// * Verify user1 is not a guest
|
||||
cy.get('#createNewTeamLink').should('exist');
|
||||
});
|
||||
|
||||
it('MM-T1425 LDAP Guest Filter Change', () => {
|
||||
// # Go to Guest access page and enable guest access
|
||||
gotoGuestAccessSettings();
|
||||
setGuestAccess(true);
|
||||
|
||||
// # Login as LDAP user2
|
||||
testSettings.user = user2;
|
||||
cy.doLDAPLogin(testSettings);
|
||||
|
||||
// # Create team if no membership
|
||||
cy.skipOrCreateTeam(testSettings, getRandomId()).then(() => {
|
||||
// * Verify user is a member
|
||||
cy.findByRole('button', {name: 'Add Channel Dropdown'}).should('exist');
|
||||
|
||||
// # Demote the user
|
||||
demoteUserToGuest(user2Data);
|
||||
|
||||
// # Logout of LDAP user
|
||||
cy.apiLogout().then(() => {
|
||||
// # Login again
|
||||
cy.doLDAPLogin(testSettings);
|
||||
|
||||
// * Check if user is in the team
|
||||
cy.uiAddDirectMessage().should('exist');
|
||||
|
||||
// * Check the user is a guest
|
||||
cy.findByRole('button', {name: 'Add Channel Dropdown'}).should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1427 Prevent Invite Guest for LDAP Group Synced Teams', () => {
|
||||
// # Create a new team
|
||||
cy.apiCreateTeam('team', 'Team').then(({team}) => {
|
||||
// # Get available ldap groups
|
||||
cy.apiGetLDAPGroups().then((result) => {
|
||||
// # Find "board" group
|
||||
const board = result.body.groups.find((group) => group.name === 'board');
|
||||
|
||||
// # Link group
|
||||
cy.apiLinkGroup(board.primary_key).then(() => {
|
||||
// # Add board-one to test team
|
||||
cy.visit(`/admin_console/user_management/teams/${team.id}`);
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Team Configuration');
|
||||
|
||||
// # Turn on sync group members
|
||||
cy.findByTestId('syncGroupSwitch').scrollIntoView().click();
|
||||
|
||||
// # Add board group to team
|
||||
cy.get('#addGroupsToTeamToggle').scrollIntoView().click();
|
||||
cy.get('#multiSelectList').should('be.visible');
|
||||
cy.get('#multiSelectList>div').children().eq(0).click();
|
||||
cy.uiGetButton('Add').click();
|
||||
|
||||
// # Save settings
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
// # Accept confirmation modal
|
||||
cy.get('#confirmModalButton').should('be.visible').click();
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Mattermost Teams');
|
||||
|
||||
// # Login as board.one user
|
||||
testSettings.user = userBoard1;
|
||||
cy.doLDAPLogin(testSettings);
|
||||
|
||||
cy.wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// # Go to the new team
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
|
||||
// # Open team menu and click 'Invite People'
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
cy.wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// # Option to invite guest should not be visible
|
||||
cy.findByTestId('inviteGuestLink').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function gotoGuestAccessSettings() {
|
||||
cy.visit('/admin_console/authentication/guest_access');
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Guest Access');
|
||||
}
|
||||
|
||||
function gotoLDAPSettings() {
|
||||
// # Go to settings page and wait until page is loaded
|
||||
cy.visit('/admin_console/authentication/ldap');
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'AD/LDAP');
|
||||
}
|
||||
|
||||
function promoteGuestToUser(user) {
|
||||
// # Issue a Request to promote the guest to user
|
||||
// Ignoring the response status as it won't be 200 if user is not a guest
|
||||
cy.task('externalRequest', {
|
||||
user: getAdminAccount(),
|
||||
method: 'post',
|
||||
baseUrl: Cypress.config('baseUrl'),
|
||||
path: `users/${user.id}/promote`,
|
||||
});
|
||||
}
|
||||
|
||||
function demoteUserToGuest(user) {
|
||||
// # Issue a Request to demote the user to guest
|
||||
cy.task('externalRequest', {
|
||||
user: getAdminAccount(),
|
||||
method: 'post',
|
||||
baseUrl: Cypress.config('baseUrl'),
|
||||
path: `users/${user.id}/demote`,
|
||||
});
|
||||
}
|
||||
|
||||
function removeUserFromAllTeams(user) {
|
||||
// # Get all teams of a user
|
||||
cy.apiGetTeamsForUser(user.id).then(({teams}) => {
|
||||
// # Remove user from all the teams
|
||||
teams.forEach((team) => {
|
||||
cy.apiDeleteUserFromTeam(team.id, user.id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setGuestAccess(enable) {
|
||||
const inputId = 'GuestAccountsSettings.' + (enable ? 'Enabletrue' : 'Enablefalse');
|
||||
cy.findByTestId(inputId).then((elem) => {
|
||||
// Proceed only if it's not already checked
|
||||
if (!Cypress.$(elem).is(':checked')) {
|
||||
// # Check the radio button
|
||||
cy.findByTestId(inputId).check().should('be.checked');
|
||||
|
||||
// # Save settings
|
||||
cy.findByTestId('saveSetting').click();
|
||||
|
||||
if (!enable) {
|
||||
// # Confirm the modal button
|
||||
cy.get('#confirmModalButton').click();
|
||||
}
|
||||
waitUntilConfigSave();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setLDAPTestSettings(config) {
|
||||
return {
|
||||
siteName: config.TeamSettings.SiteName,
|
||||
siteUrl: config.ServiceSettings.SiteURL,
|
||||
teamName: '',
|
||||
user: null,
|
||||
};
|
||||
}
|
||||
|
||||
function updateGuestFilter(value) {
|
||||
// # Set guest filter value
|
||||
if (value) {
|
||||
cy.findByTestId('LdapSettings.GuestFilterinput').type(value);
|
||||
} else {
|
||||
cy.findByTestId('LdapSettings.GuestFilterinput').clear();
|
||||
}
|
||||
|
||||
// # Save config settings and wait until saved
|
||||
cy.findByTestId('saveSetting').click();
|
||||
waitUntilConfigSave();
|
||||
}
|
||||
|
||||
// # Wait's until the Saving text becomes Save
|
||||
const waitUntilConfigSave = () => {
|
||||
cy.waitUntil(() => cy.findByTestId('saveSetting').then((el) => {
|
||||
return el[0].innerText === 'Save';
|
||||
}));
|
||||
};
|
||||
@@ -0,0 +1,240 @@
|
||||
// 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 @ldap
|
||||
|
||||
import ldapUsers from '../../../../fixtures/ldap_users.json';
|
||||
import {getRandomId} from '../../../../utils';
|
||||
|
||||
// assumes the CYPRESS_* variables are set
|
||||
// assumes that E20 license is uploaded
|
||||
// for setup with AWS: Follow the instructions mentioned in the mattermost/platform-private/config/ldap-test-setup.txt file
|
||||
context('ldap', () => {
|
||||
const user1 = ldapUsers['test-1'];
|
||||
const guest1 = ldapUsers['board-1'];
|
||||
const admin1 = ldapUsers['dev-1'];
|
||||
|
||||
let testSettings;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP
|
||||
cy.apiRequireLicenseForFeature('LDAP');
|
||||
|
||||
// # Test LDAP configuration and server connection
|
||||
// # Synchronize user attributes
|
||||
cy.apiLDAPTest();
|
||||
cy.apiLDAPSync();
|
||||
|
||||
cy.apiGetConfig().then(({config}) => {
|
||||
testSettings = setLDAPTestSettings(config);
|
||||
});
|
||||
|
||||
removeUserFromAllTeams(user1);
|
||||
removeUserFromAllTeams(guest1);
|
||||
removeUserFromAllTeams(admin1);
|
||||
|
||||
disableOnboardingTaskList(user1);
|
||||
disableOnboardingTaskList(guest1);
|
||||
disableOnboardingTaskList(admin1);
|
||||
|
||||
cy.apiAdminLogin();
|
||||
});
|
||||
|
||||
describe('LDAP Login flow - Admin Login', () => {
|
||||
it('MM-T2821 LDAP Admin Filter', () => {
|
||||
testSettings.user = admin1;
|
||||
const ldapSetting = {
|
||||
LdapSettings: {
|
||||
EnableAdminFilter: true,
|
||||
AdminFilter: '(cn=dev*)',
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(ldapSetting).then(() => {
|
||||
cy.doLDAPLogin(testSettings).then(() => {
|
||||
// # Skip or create team
|
||||
cy.skipOrCreateTeam(testSettings, getRandomId()).then(() => {
|
||||
cy.uiGetLHSHeader().then((teamName) => {
|
||||
testSettings.teamName = teamName.text();
|
||||
});
|
||||
|
||||
// # Do LDAP logout
|
||||
cy.doLDAPLogout(testSettings);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('LDAP login existing MM admin', () => {
|
||||
// existing user, verify and logout
|
||||
cy.doLDAPLogin(testSettings).then(() => {
|
||||
// # Do LDAP logout
|
||||
cy.doLDAPLogout(testSettings);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('LDAP Login flow - Member Login)', () => {
|
||||
it('Invalid login with user filter', () => {
|
||||
testSettings.user = user1;
|
||||
const ldapSetting = {
|
||||
LdapSettings: {
|
||||
UserFilter: '(cn=no_users)',
|
||||
},
|
||||
};
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.apiUpdateConfig(ldapSetting).then(() => {
|
||||
cy.doLDAPLogin(testSettings).then(() => {
|
||||
// * Verify login failed
|
||||
cy.checkLoginFailed(testSettings);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('LDAP login, new MM user, no channels', () => {
|
||||
testSettings.user = user1;
|
||||
const ldapSetting = {
|
||||
LdapSettings: {
|
||||
UserFilter: '(cn=test*)',
|
||||
},
|
||||
};
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.apiUpdateConfig(ldapSetting).then(() => {
|
||||
cy.doLDAPLogin(testSettings).then(() => {
|
||||
// # Do member logout from sign up
|
||||
cy.doMemberLogoutFromSignUp(testSettings);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('LDAP Login flow - Guest Login', () => {
|
||||
it('Invalid login with guest filter', () => {
|
||||
testSettings.user = guest1;
|
||||
const ldapSetting = {
|
||||
LdapSettings: {
|
||||
UserFilter: '(cn=no_users)',
|
||||
GuestFilter: '(cn=no_guests)',
|
||||
},
|
||||
};
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.apiUpdateConfig(ldapSetting).then(() => {
|
||||
cy.doLDAPLogin(testSettings).then(() => {
|
||||
// * Verify login failed
|
||||
cy.checkLoginFailed(testSettings);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('LDAP login, new guest, no channels', () => {
|
||||
testSettings.user = guest1;
|
||||
const ldapSetting = {
|
||||
LdapSettings: {
|
||||
UserFilter: '(cn=no_users)',
|
||||
GuestFilter: '(cn=board*)',
|
||||
},
|
||||
};
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.apiUpdateConfig(ldapSetting).then(() => {
|
||||
cy.doLDAPLogin(testSettings).then(() => {
|
||||
// # Do logout from sign up
|
||||
cy.doLogoutFromSignUp(testSettings);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('LDAP Add Member and Guest to teams and test logins', () => {
|
||||
before(() => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
cy.apiGetTeamByName(testSettings.teamName).then(({team}) => {
|
||||
cy.apiGetChannelByName(testSettings.teamName, 'town-square').then(({channel}) => {
|
||||
cy.apiGetUserByEmail(guest1.email).then(({user}) => {
|
||||
cy.apiAddUserToTeam(team.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
});
|
||||
|
||||
// add member user to team
|
||||
cy.apiGetUserByEmail(user1.email).then(({user}) => {
|
||||
cy.apiAddUserToTeam(team.id, user.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('LDAP Member login with team invite', () => {
|
||||
testSettings.user = user1;
|
||||
const ldapSetting = {
|
||||
LdapSettings: {
|
||||
UserFilter: '(cn=test*)',
|
||||
},
|
||||
};
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.apiUpdateConfig(ldapSetting).then(() => {
|
||||
cy.doLDAPLogin(testSettings).then(() => {
|
||||
// # Do LDAP logout
|
||||
cy.doLDAPLogout(testSettings);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('LDAP Guest login with team invite', () => {
|
||||
testSettings.user = guest1;
|
||||
const ldapSetting = {
|
||||
LdapSettings: {
|
||||
GuestFilter: '(cn=board*)',
|
||||
},
|
||||
};
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.apiUpdateConfig(ldapSetting).then(() => {
|
||||
cy.doLDAPLogin(testSettings).then(() => {
|
||||
// # Do LDAP logout
|
||||
cy.doLDAPLogout(testSettings);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setLDAPTestSettings(config) {
|
||||
return {
|
||||
siteName: config.TeamSettings.SiteName,
|
||||
siteUrl: config.ServiceSettings.SiteURL,
|
||||
teamName: '',
|
||||
user: null,
|
||||
};
|
||||
}
|
||||
|
||||
function disableOnboardingTaskList(ldapLogin) {
|
||||
cy.apiLogin(ldapLogin).then(({user}) => {
|
||||
cy.apiSaveOnboardingTaskListPreference(user.id, 'onboarding_task_list_open', 'false');
|
||||
cy.apiSaveOnboardingTaskListPreference(user.id, 'onboarding_task_list_show', 'false');
|
||||
cy.apiSaveSkipStepsPreference(user.id, 'true');
|
||||
});
|
||||
}
|
||||
|
||||
function removeUserFromAllTeams(testUser) {
|
||||
cy.apiGetUsersByUsernames([testUser.username]).then(({users}) => {
|
||||
users.forEach((user) => {
|
||||
cy.apiGetTeamsForUser(user.id).then(({teams}) => {
|
||||
teams.forEach((team) => {
|
||||
cy.apiDeleteUserFromTeam(team.id, user.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// 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 @ldap
|
||||
|
||||
// assumes the CYPRESS_* variables are set
|
||||
// assumes that E20 license is uploaded
|
||||
// for setup with AWS: Follow the instructions mentioned in the mattermost/platform-private/config/ldap-test-setup.txt file
|
||||
|
||||
describe('LDAP settings', () => {
|
||||
beforeEach(() => {
|
||||
// # Login as sysadmin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// * Check if server has license for LDAP
|
||||
cy.apiRequireLicenseForFeature('LDAP');
|
||||
});
|
||||
|
||||
it('MM-T2699 Connection test button - Successful', () => {
|
||||
// # Load AD/LDAP page in system console
|
||||
cy.visitLDAPSettings();
|
||||
|
||||
// # Click "AD/LDAP Test"
|
||||
cy.findByRole('button', {name: /ad\/ldap test/i}).click();
|
||||
|
||||
// * Confirmation message saying the connection is successful.
|
||||
cy.findByText(/ad\/ldap test successful/i).should('be.visible');
|
||||
cy.findByTitle(/success icon/i).should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T2700 LDAP username required', () => {
|
||||
cy.visitLDAPSettings();
|
||||
|
||||
// # Remove text from Username Attribute
|
||||
cy.findByLabelText(/username attribute:/i).click().clear();
|
||||
|
||||
// # Click Save
|
||||
cy.findByRole('button', {name: /save/i}).click();
|
||||
|
||||
// * Verifying message "AD/LDAP field "Username Attribute" is required."
|
||||
cy.findByText('AD/LDAP field "Username Attribute" is required.').should('be.visible');
|
||||
|
||||
// # Set back to what it was
|
||||
cy.findByLabelText(/username attribute:/i).click().type('uid');
|
||||
cy.findByRole('button', {name: /save/i}).click();
|
||||
cy.findByRole('button', {name: /save/i}).should('be.disabled');
|
||||
});
|
||||
|
||||
it('MM-T2701 LDAP LoginidAttribute required', () => {
|
||||
cy.visitLDAPSettings();
|
||||
|
||||
// # Try to save LDAP settings with blank Loginid
|
||||
cy.findByTestId('LdapSettings.LoginIdAttributeinput').click().clear();
|
||||
cy.findByRole('button', {name: /save/i}).click();
|
||||
|
||||
// * Verifying Error Message
|
||||
cy.findByText(/ad\/ldap field "login id attribute" is required./i).should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T2704 Create new LDAP account from login page', () => {
|
||||
const testSettings = {
|
||||
user: {
|
||||
username: 'test.two',
|
||||
password: 'Password1',
|
||||
},
|
||||
siteName: 'Mattermost',
|
||||
};
|
||||
|
||||
// # Login as a new LDAP user
|
||||
cy.doLDAPLogin(testSettings);
|
||||
|
||||
// * Verify user is logged in Successfully
|
||||
cy.findByText(/logout/i).should('be.visible');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
// 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 @ldap_group
|
||||
|
||||
describe('LDAP Group Sync - Test channel public/private toggle', () => {
|
||||
let testTeam;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP Groups
|
||||
cy.apiRequireLicenseForFeature('LDAPGroups');
|
||||
|
||||
// Enable LDAP and LDAP group sync
|
||||
cy.apiUpdateConfig({LdapSettings: {Enable: true}});
|
||||
|
||||
// # Test LDAP configuration and server connection
|
||||
// # Synchronize user attributes
|
||||
cy.apiLDAPTest();
|
||||
cy.apiLDAPSync();
|
||||
|
||||
// # Init test setup
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
testTeam = team;
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4003_1 Verify that System Admin can change channel privacy using toggle', () => {
|
||||
cy.apiCreateChannel(testTeam.id, 'test-channel', 'Test Channel').then(({channel}) => {
|
||||
assert(channel.type === 'O');
|
||||
cy.visit(`/admin_console/user_management/channels/${channel.id}`);
|
||||
cy.get('#channel_profile').contains(channel.display_name);
|
||||
cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(1).click();
|
||||
cy.get('#saveSetting').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
return cy.apiGetChannel(channel.id);
|
||||
}).then(({channel}) => {
|
||||
assert(channel.type === 'P');
|
||||
cy.visit(`/admin_console/user_management/channels/${channel.id}`);
|
||||
cy.get('#channel_profile').contains(channel.display_name);
|
||||
cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(1).click();
|
||||
cy.get('#saveSetting').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
return cy.apiGetChannel(channel.id);
|
||||
}).then(({channel}) => {
|
||||
assert(channel.type === 'O');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4003_2 Verify that resetting sync toggle doesn\'t alter channel privacy toggle', () => {
|
||||
cy.apiCreateChannel(testTeam.id, 'test-channel', 'Test Channel').then(({channel}) => {
|
||||
assert(channel.type === 'O');
|
||||
cy.visit(`/admin_console/user_management/channels/${channel.id}`);
|
||||
cy.get('#channel_profile').contains(channel.display_name);
|
||||
cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(0).click();
|
||||
cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(0).click();
|
||||
cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(1).contains('Public');
|
||||
cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(1).click();
|
||||
cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(0).click();
|
||||
cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(0).click();
|
||||
cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(1).contains('Private');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4003_3 Verify that toggles are disabled for default channel', () => {
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
cy.getCurrentChannelId().then((id) => {
|
||||
cy.visit(`/admin_console/user_management/channels/${id}`);
|
||||
cy.get('#channel_profile').contains('Town Square');
|
||||
cy.get('#channel_manage').scrollIntoView().should('be.visible').within(() => {
|
||||
cy.get('.line-switch').first().within(() => {
|
||||
cy.findByText('Sync Group Members').should('be.visible');
|
||||
cy.findByTestId('syncGroupSwitch-button').should('be.disabled');
|
||||
});
|
||||
cy.get('.line-switch').last().within(() => {
|
||||
cy.findByText('Public channel or private channel').should('be.visible');
|
||||
cy.findByTestId('allow-all-toggle-button').should('be.disabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,272 @@
|
||||
// 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 @ldap_group
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
import users from '../../../../fixtures/ldap_users.json';
|
||||
|
||||
let groupID;
|
||||
let boardUser;
|
||||
let regularUser;
|
||||
let testTeam;
|
||||
|
||||
// Goes to the groups page for the group specified by id as sysadmin
|
||||
const navigateToGroup = (id) => {
|
||||
// # Login as sysadmin and visit board group page, and wait until board user is visible
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(`/admin_console/user_management/groups/${id}`);
|
||||
|
||||
// # Scroll users list into view and then make sure it has loaded before scrolling back to the top
|
||||
cy.get('#group_users').scrollIntoView();
|
||||
cy.findByText(boardUser.email).should('be.visible');
|
||||
cy.get('#group_profile').scrollIntoView();
|
||||
};
|
||||
|
||||
// Goes to the off-topic and attempts to display suggestions for the given group name
|
||||
// Attempts to @mention the given group
|
||||
// Checks to see that the group is not highlighted as a link when viewed by a user without permission to mention
|
||||
// Checks to see that the group is not highlighted as a mention when viewed by user inside the group
|
||||
const assertGroupMentionDisabled = (groupName) => {
|
||||
const suggestion = groupName.substring(0, groupName.length - 1);
|
||||
|
||||
// # Visit off-topic
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// # Type suggestion in channel post text box
|
||||
cy.uiGetPostTextBox().clear().type(`@${suggestion}`).wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Should not open up suggestion list for groups
|
||||
cy.get('#suggestionList').should('not.exist');
|
||||
|
||||
// # Type @groupName and post it to the channel
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}{enter}{enter}`);
|
||||
|
||||
// # Get last post message text
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Assert that the last message posted contains the group name and is not highlighted with the class group-mention-link
|
||||
cy.get(`#postMessageText_${postId}`).find('.group-mention-link').should('not.exist');
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${groupName}`);
|
||||
});
|
||||
|
||||
// # Login as board user
|
||||
cy.apiLogin(boardUser);
|
||||
|
||||
// # Visit off-topic
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// # Get last post message text
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Assert that the last message posted contains the group name and is not highlighted with the class mention--highlight
|
||||
cy.get(`#postMessageText_${postId}`).find('.mention--highlight').should('not.exist');
|
||||
cy.get(`#postMessageText_${postId}`).should('include.text', `@${groupName}`);
|
||||
});
|
||||
};
|
||||
|
||||
// Goes to the off-topic and attempts to display suggestions for the given group name
|
||||
// Attempts to @mention the given group
|
||||
// Checks to see that the group is highlighted as a link when viewed by a user outside of the group
|
||||
// Checks to see that the group is highlighted as a mention when viewed by user inside the group
|
||||
const assertGroupMentionEnabled = (groupName) => {
|
||||
const suggestion = groupName.substring(0, groupName.length - 1);
|
||||
|
||||
// # Visit off-topic
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// # Type suggestion in channel post text box
|
||||
cy.uiGetPostTextBox().clear().type(`@${suggestion}`).wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Should open up suggestion list for groups
|
||||
// * Should match group item and group label
|
||||
cy.get('#suggestionList', {timeout: TIMEOUTS.FIVE_SEC}).should('be.visible').children().within((el) => {
|
||||
cy.wrap(el).eq(0).should('contain', 'Group Mentions');
|
||||
cy.wrap(el).eq(1).should('contain', `@${groupName}`);
|
||||
});
|
||||
|
||||
// # Type @groupName and post it to the channel
|
||||
cy.uiGetPostTextBox().clear().type(`@${groupName}{enter}{enter}`).wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// # Get last post message text
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Assert that the last message posted contains the group name and is highlighted with the class group-mention-link
|
||||
cy.get(`#postMessageText_${postId}`).find('.group-mention-link').should('be.visible').should('include.text', `@${groupName}`);
|
||||
});
|
||||
|
||||
// # Login as board user
|
||||
cy.apiLogin(boardUser);
|
||||
|
||||
// # Visit off-topic
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// # Get last post message text
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Assert that the last message posted contains the group name and is highlighted with the class mention--highlight
|
||||
cy.get(`#postMessageText_${postId}`).find('.mention--highlight').should('be.visible').should('include.text', `@${groupName}`);
|
||||
});
|
||||
};
|
||||
|
||||
// Clicks the save button in the system console page.
|
||||
const saveConfig = () => {
|
||||
// # 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();
|
||||
|
||||
cy.waitUntil(() => cy.get('#saveSetting').then((el) => {
|
||||
return el[0].innerText === 'Save';
|
||||
}));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
describe('System Console', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP Groups
|
||||
cy.apiRequireLicenseForFeature('LDAPGroups');
|
||||
|
||||
// # Enable LDAP
|
||||
cy.apiUpdateConfig({LdapSettings: {Enable: true}});
|
||||
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
regularUser = user;
|
||||
testTeam = team;
|
||||
});
|
||||
|
||||
// # Link board group
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#board_group').then((el) => {
|
||||
if (!el.text().includes('Edit')) {
|
||||
// # Link the Group if its not linked before
|
||||
if (el.find('.icon.fa-unlink').length > 0) {
|
||||
el.find('.icon.fa-unlink').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// # Get board group id
|
||||
cy.apiGetGroups().then((res) => {
|
||||
res.body.forEach((group) => {
|
||||
if (group.display_name === 'board') {
|
||||
// # Set groupID to navigate to group page directly
|
||||
groupID = group.id;
|
||||
|
||||
// # Set allow reference false to ensure correct data for test cases
|
||||
cy.apiPatchGroup(groupID, {allow_reference: false});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// # Login once as board user to ensure the user is created in the system
|
||||
boardUser = users['board-1'];
|
||||
cy.apiLogin(boardUser);
|
||||
|
||||
// # Login as sysadmin and add board-one to test team
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Add board user to test team to ensure that it exists in the team and set its preferences to skip tutorial step
|
||||
cy.apiGetUserByEmail(boardUser.email).then(({user}) => {
|
||||
cy.apiGetChannelByName(testTeam.name, 'off-topic').then(({channel}) => {
|
||||
cy.apiAddUserToTeam(testTeam.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiSaveTutorialStep(user.id, '999');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-23937 - Can enable and disable group mentions with a custom name for a group ', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin and navigate to board group page
|
||||
navigateToGroup(groupID);
|
||||
|
||||
// # Click the allow reference button
|
||||
cy.findByTestId('allowReferenceSwitch').then((el) => {
|
||||
el.find('button').click();
|
||||
|
||||
// # Give the group a custom name different from its DisplayName attribute
|
||||
cy.get('#groupMention').find('input').clear().type(groupName);
|
||||
|
||||
// # Click save button
|
||||
saveConfig();
|
||||
|
||||
// * Assert that the group mention works as expected since the group is enabled and sysadmin always has permission to mention
|
||||
assertGroupMentionEnabled(groupName);
|
||||
|
||||
// # Login as sysadmin and navigate to board group page
|
||||
navigateToGroup(groupID);
|
||||
|
||||
// # Click the allow reference button
|
||||
cy.findByTestId('allowReferenceSwitch').then((elSwitch) => {
|
||||
elSwitch.find('button').click();
|
||||
|
||||
// # Click save button
|
||||
saveConfig();
|
||||
|
||||
// * Assert that the group mention does not do anything since the group is disabled even though sysadmin has permission to mention
|
||||
assertGroupMentionDisabled(groupName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-23937 - Can restrict users from mentioning a group through the use_group_mentions permission', () => {
|
||||
const groupName = `board_test_case_${Date.now()}`;
|
||||
|
||||
// # Login as sysadmin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Set group as allow reference = true with name groupName
|
||||
cy.apiPatchGroup(groupID, {allow_reference: true, name: groupName});
|
||||
|
||||
// # Navigate to system scheme page
|
||||
cy.visit('/admin_console/user_management/permissions/system_scheme');
|
||||
|
||||
// # Click reset to defaults, confirm and save
|
||||
cy.findByTestId('resetPermissionsToDefault').click({force: true});
|
||||
cy.get('#confirmModalButton').click({force: true});
|
||||
saveConfig();
|
||||
|
||||
// # Login as a normal user
|
||||
cy.apiLogin(regularUser);
|
||||
|
||||
// * Assert that the group mention works as expected since the group is enabled and user has permission to mention
|
||||
assertGroupMentionEnabled(groupName);
|
||||
|
||||
// # Login as sysadmin and navigate to system scheme
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/user_management/permissions/system_scheme');
|
||||
|
||||
// # Disable group mentions for users if enabled and save
|
||||
cy.findByTestId('all_users-posts-use_group_mentions-checkbox').then((btn) => {
|
||||
if (btn.hasClass('checked')) {
|
||||
btn.click();
|
||||
}
|
||||
|
||||
saveConfig();
|
||||
|
||||
// # Login as a regular member
|
||||
cy.apiLogin(regularUser);
|
||||
|
||||
// * Assert that the group mention does not do anything since the user does not have the permission to mention the group
|
||||
assertGroupMentionDisabled(groupName);
|
||||
});
|
||||
});
|
||||
|
||||
after(() => {
|
||||
// # Login as sysadmin and navigate to system scheme page
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/user_management/permissions/system_scheme');
|
||||
|
||||
// # Click reset to defaults confirm and save
|
||||
cy.findByTestId('resetPermissionsToDefault').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
saveConfig();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,127 @@
|
||||
// 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 @ldap_group
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
// # Function to get all the teams associated to group and unlink them
|
||||
const getTeamsAssociatedToGroupAndUnlink = (groupId) => {
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/groups/${groupId}/teams`,
|
||||
method: 'GET',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
response.body.forEach((element) => {
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/groups/${element.group_id}/teams/${element.team_id}/link`,
|
||||
method: 'DELETE',
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// # Function to get all the channels associated to group and unlink them
|
||||
const getChannelsAssociatedToGroupAndUnlink = (groupId) => {
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/groups/${groupId}/channels`,
|
||||
method: 'GET',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
response.body.forEach((element) => {
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/groups/${element.group_id}/channels/${element.channel_id}/link`,
|
||||
method: 'DELETE',
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
describe('LDAP Group Sync', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP Groups
|
||||
cy.apiRequireLicenseForFeature('LDAPGroups');
|
||||
|
||||
// Enable LDAP
|
||||
cy.apiUpdateConfig({LdapSettings: {Enable: true}});
|
||||
|
||||
// # Test LDAP configuration and server connection
|
||||
// # Synchronize user attributes
|
||||
cy.apiLDAPTest();
|
||||
cy.apiLDAPSync();
|
||||
});
|
||||
|
||||
it('MM-T2668 Team admin role can be set and saved', () => {
|
||||
// # Go to system admin page and to team configuration page
|
||||
cy.visit('/admin_console/user_management/groups');
|
||||
cy.get('#developers_group').then((el) => {
|
||||
if (el.text().includes('Edit')) {
|
||||
cy.get('#developers_edit').then((buttonEl) => {
|
||||
// # Get the Group ID and remove all the teams and channels currently attached to it then click the button
|
||||
const anchorElement = buttonEl[0] as HTMLAnchorElement;
|
||||
const groupId = anchorElement.href.match(/\/(?:.(?!\/))+$/)[0].substring(1);
|
||||
getTeamsAssociatedToGroupAndUnlink(groupId);
|
||||
getChannelsAssociatedToGroupAndUnlink(groupId);
|
||||
cy.get('#developers_edit').click();
|
||||
});
|
||||
} else {
|
||||
// # Link the Group if its not linked before
|
||||
if (el.find('.icon.fa-unlink').length > 0) {
|
||||
el.find('.icon.fa-unlink').click();
|
||||
}
|
||||
|
||||
// # Get the Group ID and remove all the teams and channels currently attached to it then click the button
|
||||
cy.get('#developers_configure').then((buttonEl) => {
|
||||
const anchorElement = buttonEl[0] as HTMLAnchorElement;
|
||||
const groupId = anchorElement.href.match(/\/(?:.(?!\/))+$/)[0].substring(1);
|
||||
getTeamsAssociatedToGroupAndUnlink(groupId);
|
||||
getChannelsAssociatedToGroupAndUnlink(groupId);
|
||||
cy.get('#developers_configure').click();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// # Wait until the groups retrieved and show up
|
||||
cy.wait(TIMEOUTS.HALF_SEC); //eslint-disable-line cypress/no-unnecessary-waiting
|
||||
|
||||
// # Add the first team in the group list then save
|
||||
cy.get('#add_team_or_channel').click();
|
||||
cy.get('#add_team').click();
|
||||
cy.get('#multiSelectList').should('be.visible').children().first().click({force: true});
|
||||
cy.uiGetButton('Add').click();
|
||||
|
||||
// # Add the first channel in the group list then save
|
||||
cy.get('#add_team_or_channel').click();
|
||||
cy.get('#add_channel').click();
|
||||
cy.get('#multiSelectList').children().first().click();
|
||||
cy.uiGetButton('Add').click();
|
||||
|
||||
// # Wait until the groups retrieved and show up
|
||||
cy.wait(TIMEOUTS.HALF_SEC); //eslint-disable-line cypress/no-unnecessary-waiting
|
||||
|
||||
cy.get('#team_and_channel_membership_table').then((el) => {
|
||||
// * Ensure that the text in the roles column is Member as default text for each row
|
||||
const table = el[0] as HTMLTableElement;
|
||||
const name = table.rows[1].cells[0].innerText;
|
||||
cy.findByTestId(`${name}_current_role`).scrollIntoView().should('contain.text', 'Member');
|
||||
|
||||
// # Change the option to the admin roles (Channel Admin/Team Admin) for each row
|
||||
cy.findByTestId(`${name}_current_role`).scrollIntoView().click();
|
||||
cy.get(`#${name}_change_role_options button`).scrollIntoView().click();
|
||||
|
||||
// * Ensure that each row roles have changed successfully (by making sure that the Member text is not existent anymore)
|
||||
cy.findByTestId(`${name}_current_role`).scrollIntoView().should('not.contain.text', 'Member');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
// 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 @ldap_group
|
||||
|
||||
describe('Group Synced Team - Bot invitation flow', () => {
|
||||
let groupConstrainedTeam;
|
||||
let bot;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP Groups
|
||||
cy.apiRequireLicenseForFeature('LDAPGroups');
|
||||
|
||||
// # Enable LDAP
|
||||
cy.apiUpdateConfig({LdapSettings: {Enable: true}});
|
||||
|
||||
// # Get the first group constrained team available on the server
|
||||
cy.apiGetAllTeams().then(({teams}) => {
|
||||
teams.forEach((team) => {
|
||||
if (team.group_constrained && !groupConstrainedTeam) {
|
||||
groupConstrainedTeam = team;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// # Get the first bot on the server
|
||||
cy.apiGetBots().then(({bots}) => {
|
||||
bot = bots[0];
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-21793 Invite and remove a bot within a group synced team', () => {
|
||||
if (!groupConstrainedTeam || !bot) {
|
||||
return;
|
||||
}
|
||||
|
||||
// # Logout sysadmin and login as an LDAP Group synced user
|
||||
cy.apiLogout();
|
||||
|
||||
const user = {
|
||||
username: 'test.one',
|
||||
password: 'Password1',
|
||||
} as Cypress.UserProfile;
|
||||
cy.apiLogin(user);
|
||||
|
||||
// # Visit the group constrained team
|
||||
cy.visit(`/${groupConstrainedTeam.name}`);
|
||||
|
||||
// # Click 'Invite People' at team menu
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
// # Type the first letters of a bot
|
||||
cy.get('.users-emails-input__control input').typeWithForce(bot.username);
|
||||
|
||||
// * Verify user is on the list, then select by clicking on it
|
||||
cy.get('.users-emails-input__menu').
|
||||
children().should('have.length', 1).
|
||||
eq(0).should('contain', `@${bot.username}`).
|
||||
click();
|
||||
|
||||
// # Invite the bot
|
||||
cy.get('#inviteMembersButton').click();
|
||||
|
||||
// * Ensure that the response message was not an error
|
||||
cy.get('.InviteResultRow').find('.reason').should('not.contain', 'Error');
|
||||
|
||||
// # Visit the group constrained team
|
||||
cy.visit(`/${groupConstrainedTeam.name}`);
|
||||
|
||||
// # Click 'Manage Members' at team menu
|
||||
cy.uiOpenTeamMenu('Manage Members');
|
||||
|
||||
// # Search for the bot that we want to remove
|
||||
cy.get('#searchUsersInput').should('be.visible').type(bot.username);
|
||||
|
||||
cy.get(`#teamMembersDropdown_${bot.username}`).should('be.visible').then((el) => {
|
||||
// # Have to use a jquery click here instead of a cypress click due to in order for the dropdown menu to stay open
|
||||
el.click();
|
||||
|
||||
// * Ensure that we have the ability to remove the bot and click the dropdown option
|
||||
cy.get('#removeFromTeam').should('be.visible').click();
|
||||
});
|
||||
|
||||
// * Ensure that the bot is no longer there
|
||||
cy.findByTestId('noUsersFound').should('be.visible');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,122 @@
|
||||
// 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 @ldap_group
|
||||
|
||||
import {getRandomId} from '../../../../utils';
|
||||
|
||||
describe('Search channels', () => {
|
||||
const PAGE_SIZE = 10;
|
||||
let testTeamId;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP Groups
|
||||
cy.apiRequireLicenseForFeature('LDAPGroups');
|
||||
|
||||
// Enable LDAP
|
||||
cy.apiUpdateConfig({LdapSettings: {Enable: true}});
|
||||
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
testTeamId = team.id;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.visit('/admin_console/user_management/channels');
|
||||
});
|
||||
|
||||
it('loads with no search text', () => {
|
||||
// * Check that text input loads empty.
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').should('be.visible').and('have.text', '');
|
||||
});
|
||||
});
|
||||
|
||||
it('returns results', () => {
|
||||
// # Create a channel.
|
||||
const displayName = getRandomId();
|
||||
cy.apiCreateChannel(testTeamId, 'channel-search', displayName);
|
||||
|
||||
// # Search for the channel.
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').type(displayName + '{enter}');
|
||||
});
|
||||
|
||||
// * Check that channel is in search results.
|
||||
cy.findAllByTestId('channel-display-name').contains(displayName);
|
||||
});
|
||||
|
||||
it('results are paginated', () => {
|
||||
// # Create enough new channels with common name prefixes to get multiple pages of search results.
|
||||
const displayName = getRandomId();
|
||||
for (let i = 0; i < PAGE_SIZE + 2; i++) {
|
||||
cy.apiCreateChannel(testTeamId, 'channel-search-paged-' + i, displayName + ' ' + i);
|
||||
}
|
||||
|
||||
// # Search using the common channel name prefix.
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').type(displayName + '{enter}');
|
||||
});
|
||||
|
||||
// * Check that the first page of results is full.
|
||||
cy.findAllByTestId('channel-display-name').should('have.length', PAGE_SIZE);
|
||||
|
||||
// # Click the next pagination arrow.
|
||||
cy.get('.DataGrid_footer').should('have.text', '1 - 10 of 12').within(() => {
|
||||
cy.get('.next').should('be.enabled').click();
|
||||
});
|
||||
|
||||
// * Check that the 2nd page of results has the expected amount.
|
||||
cy.findAllByTestId('channel-display-name').should('have.length', 2);
|
||||
});
|
||||
|
||||
it('clears the results when "x" is clicked', () => {
|
||||
// # Create a new channel.
|
||||
const displayName = getRandomId();
|
||||
cy.apiCreateChannel(testTeamId, 'channel-search', displayName);
|
||||
|
||||
// # Search for the channel.
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').as('searchInput').type(displayName + '{enter}');
|
||||
});
|
||||
|
||||
// * Check that the list of channels is in search results mode.
|
||||
cy.findAllByTestId('channel-display-name').should('have.length', 1);
|
||||
|
||||
// # Click the x in the search input.
|
||||
cy.findByTestId('clear-search').click();
|
||||
|
||||
// * Check that the search input text is cleared.
|
||||
cy.get('@searchInput').should('be.visible').and('have.text', '');
|
||||
|
||||
// * Check that the search results are reset to the default page-load list.
|
||||
cy.findAllByTestId('channel-display-name').should('have.length', PAGE_SIZE);
|
||||
});
|
||||
|
||||
it('clears the results when the search term is deleted with backspace', () => {
|
||||
// # Create a channel.
|
||||
const displayName = getRandomId();
|
||||
cy.apiCreateChannel(testTeamId, 'channel-search', displayName);
|
||||
|
||||
// # Search for the channel.
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').as('searchInput').type(displayName + '{enter}');
|
||||
});
|
||||
|
||||
// * Check that the list of teams is in search results mode.
|
||||
cy.findAllByTestId('channel-display-name').should('have.length', 1);
|
||||
|
||||
// # Clear the search input by deleting the search text.
|
||||
cy.get('@searchInput').type('{selectall}{del}');
|
||||
|
||||
// * Check that the search results are reset to the default page-load list.
|
||||
cy.findAllByTestId('channel-display-name').should('have.length', PAGE_SIZE);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,225 @@
|
||||
// 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 @ldap_group
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
// # Save setting and get back to the resource page
|
||||
const saveAndNavigateBackTo = (name, displayName, page) => {
|
||||
cy.get('#saveSetting').should('be.enabled').click().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify that it redirects to page and wait for a while to load
|
||||
cy.url().should('include', `/admin_console/user_management/${page}`).wait(TIMEOUTS.TWO_SEC);
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').should('be.visible').type(`${displayName}{enter}`).wait(TIMEOUTS.HALF_SEC);
|
||||
});
|
||||
cy.findByTestId(`${name}edit`).should('be.visible').click();
|
||||
};
|
||||
|
||||
const changeRole = (type, fromRole, toRole) => {
|
||||
// # Wait for data grid to load
|
||||
cy.get(`#${type}Members`).scrollIntoView().within(() => {
|
||||
cy.get('.UserGrid_nameRow').should('be.visible');
|
||||
});
|
||||
|
||||
// * Ensure current role is fromRole then click
|
||||
cy.get(`#${type}_groups`).scrollIntoView().findByTestId('current-role').should('have.text', fromRole).click();
|
||||
|
||||
// # Change role
|
||||
cy.get('#role-to-be-menu').then((el) => {
|
||||
// * Assert that only one option exists in the dropdown for changing roles
|
||||
expect(el[0].firstElementChild.children.length).equal(1);
|
||||
|
||||
// # Click on toRole
|
||||
cy.wrap(el).findByText(toRole).click().wait(TIMEOUTS.HALF_SEC);
|
||||
});
|
||||
};
|
||||
|
||||
describe('System Console', () => {
|
||||
const groupDisplayName = 'board';
|
||||
let testTeam;
|
||||
let teamName;
|
||||
let teamDisplayName;
|
||||
let channelName;
|
||||
let channelDisplayName;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for LDAP Groups
|
||||
cy.apiRequireLicenseForFeature('LDAPGroups');
|
||||
|
||||
cy.apiInitSetup({
|
||||
teamPrefix: {name: 'a-team', displayName: 'A Team'},
|
||||
channelPrefix: {name: 'a-channel', displayName: 'A Channel'},
|
||||
}).then(({team, channel}) => {
|
||||
testTeam = team;
|
||||
teamName = team.display_name;
|
||||
teamDisplayName = team.display_name;
|
||||
channelName = channel.name;
|
||||
channelDisplayName = channel.display_name;
|
||||
|
||||
cy.apiGetLDAPGroups().then((res) => {
|
||||
res.body.groups.forEach((group) => {
|
||||
if (group.name === groupDisplayName) {
|
||||
cy.apiAddLDAPGroupLink(group.primary_key);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiGetTeamGroups(testTeam.id).then((resGroups) => {
|
||||
resGroups.body.groups.forEach((group) => {
|
||||
if (group.display_name === groupDisplayName) {
|
||||
cy.apiDeleteLinkFromTeamToGroup(group.id, testTeam.id);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-20059 - System Admin can map roles to groups from Team Configuration screen', () => {
|
||||
// # Go to system admin page and to team configuration page
|
||||
cy.visit('/admin_console/user_management/teams');
|
||||
|
||||
// # Search for the team.
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').should('be.visible').type(`${teamDisplayName}{enter}`);
|
||||
});
|
||||
cy.findByTestId(`${teamName}edit`).click();
|
||||
|
||||
// # Add the first group in the group list then save
|
||||
cy.findByTestId('addGroupsToTeamToggle').scrollIntoView().click();
|
||||
cy.get('#multiSelectList').should('be.visible');
|
||||
cy.get('#multiSelectList>div').children().eq(0).click();
|
||||
cy.get('#saveItems').click();
|
||||
|
||||
// # Change role from Member to Team Admin
|
||||
changeRole('team', 'Member', 'Team Admin');
|
||||
|
||||
// # Save the setting and navigate back to page
|
||||
saveAndNavigateBackTo(teamName, teamDisplayName, 'teams');
|
||||
|
||||
// # Change role from Team Admin to Member
|
||||
changeRole('team', 'Team Admin', 'Member');
|
||||
|
||||
// # Save the setting and navigate back to page
|
||||
saveAndNavigateBackTo(teamName, teamDisplayName, 'teams');
|
||||
|
||||
// * Check to make the the current role text is displayed as Member
|
||||
cy.get('#team_groups').scrollIntoView().findByTestId('current-role').should('have.text', 'Member');
|
||||
|
||||
// # Wait for the board group to show up before continuing to next steps
|
||||
cy.waitUntil(() => cy.get('.group-row').eq(0).scrollIntoView().find('.group-name').then((el) => {
|
||||
return el[0].innerText === groupDisplayName;
|
||||
}), {
|
||||
errorMsg: `${groupDisplayName} group didn't show up in time`,
|
||||
timeout: TIMEOUTS.TEN_SEC,
|
||||
});
|
||||
|
||||
// # Remove "board" group
|
||||
cy.get('.group-row').eq(0).scrollIntoView().should('be.visible').within(() => {
|
||||
cy.get('.group-name').should('have.text', groupDisplayName);
|
||||
cy.get('.group-actions > a').should('have.text', 'Remove').click();
|
||||
});
|
||||
|
||||
// * Assert that the group was removed successfully
|
||||
cy.get('#groups-list--body').should('be.visible').contains('No groups specified yet');
|
||||
|
||||
// # Save the setting and navigate back to page
|
||||
saveAndNavigateBackTo(teamName, teamDisplayName, 'teams');
|
||||
|
||||
// * Assert that the group was removed successfully
|
||||
cy.get('#groups-list--body').scrollIntoView().should('be.visible').contains('No groups specified yet');
|
||||
});
|
||||
|
||||
it('MM-21789 - Add a group and change the role and then save and ensure the role was updated on team configuration page', () => {
|
||||
// # Go to system admin page and to team configuration page
|
||||
cy.visit('/admin_console/user_management/teams');
|
||||
|
||||
// # Search for the team.
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').should('be.visible').type(`${teamDisplayName}{enter}`);
|
||||
});
|
||||
cy.findByTestId(`${teamName}edit`).click();
|
||||
|
||||
// # Add the first group in the group list then save
|
||||
cy.findByTestId('addGroupsToTeamToggle').click();
|
||||
cy.get('#multiSelectList').should('be.visible');
|
||||
cy.get('#multiSelectList>div').children().eq(0).click();
|
||||
cy.get('#saveItems').click();
|
||||
|
||||
// # Change role from Member to Team Admin
|
||||
changeRole('team', 'Member', 'Team Admin');
|
||||
|
||||
// # Save the setting and navigate back to page
|
||||
saveAndNavigateBackTo(teamName, teamDisplayName, 'teams');
|
||||
|
||||
// * Check to make the the current role text is displayed as Team Admin
|
||||
cy.get('#team_groups').scrollIntoView().findByTestId('current-role').should('have.text', 'Team Admin');
|
||||
});
|
||||
|
||||
it('MM-20646 - System Admin can map roles to groups from Channel Configuration screen', () => {
|
||||
// # Go to system admin page and to channel configuration page of channel "autem"
|
||||
cy.visit('/admin_console/user_management/channels');
|
||||
|
||||
// # Search for the channel.
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').should('be.visible').type(`${channelDisplayName}{enter}`);
|
||||
});
|
||||
cy.findByTestId(`${channelName}edit`).click();
|
||||
|
||||
// # Add the first group in the group list then save
|
||||
cy.get('#addGroupsToChannelToggle').click();
|
||||
cy.get('#multiSelectList').should('be.visible');
|
||||
cy.get('#multiSelectList>div').children().eq(0).click();
|
||||
cy.get('#saveItems').click();
|
||||
|
||||
// # Change role from Member to Channel Admin
|
||||
changeRole('channel', 'Member', 'Channel Admin');
|
||||
|
||||
// # Save the setting and navigate back to page
|
||||
saveAndNavigateBackTo(channelName, channelDisplayName, 'channels');
|
||||
|
||||
// # Change role from Channel Admin to Member
|
||||
changeRole('channel', 'Channel Admin', 'Member');
|
||||
|
||||
// # Save the setting and navigate back to page
|
||||
saveAndNavigateBackTo(channelName, channelDisplayName, 'channels');
|
||||
|
||||
// * Check to make the the current role text is displayed as Member
|
||||
cy.get('#channel_groups').scrollIntoView().findByTestId('current-role').should('have.text', 'Member');
|
||||
});
|
||||
|
||||
it('MM-21789 - Add a group and change the role and then save and ensure the role was updated on channel configuration page', () => {
|
||||
// # Go to system admin page and to channel configuration page of channel "autem"
|
||||
cy.visit('/admin_console/user_management/channels');
|
||||
|
||||
// # Search for the channel.
|
||||
cy.get('.DataGrid_searchBar').within(() => {
|
||||
cy.findByPlaceholderText('Search').should('be.visible').type(`${channelDisplayName}{enter}`);
|
||||
});
|
||||
cy.findByTestId(`${channelName}edit`).click();
|
||||
|
||||
// # Add the first group in the group list then save
|
||||
cy.get('#addGroupsToChannelToggle').click();
|
||||
cy.get('#multiSelectList').should('be.visible');
|
||||
cy.get('#multiSelectList>div').children().eq(0).click();
|
||||
cy.get('#saveItems').click();
|
||||
|
||||
// # Change role from Member to Channel Admin
|
||||
changeRole('channel', 'Member', 'Channel Admin');
|
||||
|
||||
// # Save the setting and navigate back to page
|
||||
saveAndNavigateBackTo(channelName, channelDisplayName, 'channels');
|
||||
|
||||
// * Check to make the the current role text is displayed as Channel Admin
|
||||
cy.get('#channel_groups').scrollIntoView().findByTestId('current-role').should('have.text', 'Channel Admin');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,459 @@
|
||||
// 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 @integrations
|
||||
|
||||
import {getRandomId} from '../../../../utils';
|
||||
import {checkboxesTitleToIdMap} from '../system_console/channel_moderation/constants';
|
||||
|
||||
import {enablePermission, goToSystemScheme, saveConfigForScheme} from '../system_console/channel_moderation/helpers';
|
||||
|
||||
describe('Integrations page', () => {
|
||||
const webhookBaseUrl = Cypress.env('webhookBaseUrl');
|
||||
|
||||
let user1;
|
||||
let user2;
|
||||
let testChannelUrl1;
|
||||
let oauthClientID;
|
||||
let oauthClientSecret;
|
||||
const testApp = `Test${getRandomId()}`;
|
||||
|
||||
before(() => {
|
||||
cy.apiRequireLicense();
|
||||
cy.requireWebhookServer();
|
||||
|
||||
// # Set ServiceSettings to expected values
|
||||
cy.apiUpdateConfig({ServiceSettings: {EnableOAuthServiceProvider: true}});
|
||||
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
user1 = user;
|
||||
testChannelUrl1 = `/${team.name}/channels/town-square`;
|
||||
|
||||
cy.apiCreateUser().then(({user: otherUser}) => {
|
||||
user2 = otherUser;
|
||||
cy.apiAddUserToTeam(team.id, user2.id);
|
||||
});
|
||||
});
|
||||
|
||||
goToSystemScheme();
|
||||
enablePermission(checkboxesTitleToIdMap.ALL_USERS_MANAGE_OAUTH_APPLICATIONS);
|
||||
saveConfigForScheme();
|
||||
});
|
||||
|
||||
it('MM-T646 OAuth 2.0 trusted', () => {
|
||||
cy.apiLogin(user1);
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
// # Navigate to OAuthApps in integrations menu
|
||||
cy.uiOpenProductMenu('Integrations');
|
||||
cy.get('#oauthApps').click();
|
||||
|
||||
// # Click on the Add button
|
||||
cy.get('#addOauthApp').click();
|
||||
|
||||
// * Should not find is trusted
|
||||
cy.findByText('Is Trusted').should('not.exist');
|
||||
|
||||
// * First child should be Display Name
|
||||
cy.get('div.backstage-form > form > div:first').should('contain', 'Display Name');
|
||||
});
|
||||
|
||||
it('MM-T647 Copy icon for OAuth 2.0 Applications', () => {
|
||||
cy.apiLogin(user1);
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
// # Navigate to OAuthApps in integrations menu
|
||||
cy.uiOpenProductMenu('Integrations');
|
||||
cy.get('#oauthApps').click();
|
||||
|
||||
// # Click on the Add button
|
||||
cy.get('#addOauthApp').click();
|
||||
|
||||
// # Fill all fields
|
||||
const randomApp = `Random${getRandomId()}`;
|
||||
cy.get('#name').type(randomApp);
|
||||
cy.get('#description').type(randomApp);
|
||||
cy.get('#homepage').type('https://www.test.com/');
|
||||
cy.get('#callbackUrls').type('https://www.test.com/');
|
||||
|
||||
// # Save
|
||||
cy.get('#saveOauthApp').click();
|
||||
|
||||
// * Copy button should be visible
|
||||
cy.get('.fa-copy').should('exist');
|
||||
|
||||
// # Store client ID
|
||||
cy.findByText('Client ID').parent().invoke('text').then((text) => {
|
||||
cy.wrap(text.substring(3)).as('clientID');
|
||||
});
|
||||
|
||||
// # Click Done
|
||||
cy.get('#doneButton').click();
|
||||
|
||||
cy.get('@clientID').then((clientID) => {
|
||||
const cId = clientID as unknown as string;
|
||||
cy.contains('.item-details', cId).within(() => {
|
||||
// * Copy button should exist for Client ID
|
||||
cy.contains('.item-details__token', 'Client ID').within(() => {
|
||||
cy.get('.fa-copy').should('exist');
|
||||
});
|
||||
|
||||
cy.contains('.item-details__token', 'Client Secret').within(() => {
|
||||
// * Client secret should not show
|
||||
cy.contains('*******************').should('exist');
|
||||
|
||||
// * Copy button should not exist
|
||||
cy.get('.fa-copy').should('not.exist');
|
||||
});
|
||||
|
||||
// # Show secret
|
||||
cy.findByText('Show Secret').click();
|
||||
|
||||
// * Show secret text should have changed to Hide Secret
|
||||
cy.findByText('Hide Secret').should('exist');
|
||||
cy.findByText('Show Secret').should('not.exist');
|
||||
|
||||
cy.contains('.item-details__token', 'Client Secret').within(() => {
|
||||
// * Token should not be obscured
|
||||
cy.contains('*******************').should('not.exist');
|
||||
|
||||
// * Copy button should exist
|
||||
cy.get('.fa-copy').should('exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T648_1 OAuth 2.0 Application - Setup', () => {
|
||||
cy.apiLogin(user1);
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
// # Navigate to OAuthApps in integrations menu
|
||||
cy.uiOpenProductMenu('Integrations');
|
||||
cy.get('#oauthApps').click();
|
||||
|
||||
// # Click on the Add button
|
||||
cy.get('#addOauthApp').click();
|
||||
|
||||
// # Fill all fields
|
||||
cy.get('#name').type(testApp);
|
||||
cy.get('#description').type(testApp);
|
||||
cy.get('#homepage').type('https://www.test.com/');
|
||||
cy.get('#callbackUrls').type(`${webhookBaseUrl}/complete_oauth`);
|
||||
|
||||
// # Save
|
||||
cy.get('#saveOauthApp').click();
|
||||
|
||||
// * Copy button should be visible
|
||||
cy.get('.fa-copy').should('exist');
|
||||
|
||||
// # Store client ID
|
||||
cy.findByText('Client ID').parent().invoke('text').then((text) => {
|
||||
cy.wrap(text.substring(11)).as('clientID');
|
||||
});
|
||||
|
||||
// # Store client secret
|
||||
cy.findByText('Client Secret').parent().invoke('text').then((text) => {
|
||||
cy.wrap(text.substring(15)).as('clientSecret');
|
||||
});
|
||||
|
||||
cy.get('@clientID').then((clientID) => {
|
||||
oauthClientID = clientID;
|
||||
cy.get('@clientSecret').then((clientSecret) => {
|
||||
oauthClientSecret = clientSecret;
|
||||
|
||||
// # Send credentials
|
||||
cy.postIncomingWebhook({
|
||||
url: `${webhookBaseUrl}/send_oauth_credentials`,
|
||||
data: {
|
||||
appID: clientID,
|
||||
appSecret: clientSecret,
|
||||
}});
|
||||
});
|
||||
});
|
||||
|
||||
// # Click Done
|
||||
cy.get('#doneButton').click();
|
||||
});
|
||||
|
||||
it('MM-T648_2 OAuth 2.0 Application - Exchange tokens', () => {
|
||||
cy.apiLogin(user1);
|
||||
|
||||
// # Visit the webhook url to start the OAuth handshake
|
||||
cy.visit(`${webhookBaseUrl}/start_oauth`);
|
||||
|
||||
// # Click on the allow button
|
||||
cy.findByText('Allow').click();
|
||||
|
||||
// * Exchange successful
|
||||
cy.findByText('OK').should('exist');
|
||||
});
|
||||
|
||||
it('MM-T648_3 OAuth 2.0 Application - Post message using OAuth credentials', () => {
|
||||
// # Visit a channel
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
cy.getCurrentChannelId().then((channelId) => {
|
||||
const message = 'OAuth test 01';
|
||||
|
||||
// # Post message using OAuth credentials
|
||||
cy.postIncomingWebhook({
|
||||
url: `${webhookBaseUrl}/post_oauth_message`,
|
||||
data: {
|
||||
channelId,
|
||||
message,
|
||||
}});
|
||||
|
||||
// * The message should be posted
|
||||
cy.findByText(message).should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T649 Edit Oauth 2.0 Application', () => {
|
||||
cy.apiLogin(user2);
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
// # Navigate to OAuthApps in integrations menu
|
||||
cy.uiOpenProductMenu('Integrations');
|
||||
cy.get('#oauthApps').click();
|
||||
|
||||
// # Other users should not see the apps from other users
|
||||
cy.get('.item-details').should('not.exist');
|
||||
|
||||
// # Login as sysadmin
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
// # Navigate to OAuthApps in integrations menu
|
||||
cy.uiOpenProductMenu('Integrations');
|
||||
cy.get('#oauthApps').click();
|
||||
|
||||
// * Sysadmin should see the app
|
||||
cy.get('.item-details').should('be.visible');
|
||||
cy.contains('.item-details', oauthClientID).should('exist').within(() => {
|
||||
cy.get('.item-details__token').should('contain', oauthClientID);
|
||||
|
||||
// * Sysadmin should see the Edit button
|
||||
// # Click on the edit button
|
||||
cy.findByText('Edit').should('exist').click();
|
||||
});
|
||||
|
||||
// # Update description
|
||||
cy.get('#description').type('Edited');
|
||||
|
||||
// # Save
|
||||
cy.get('#saveOauthApp').click({force: true});
|
||||
|
||||
cy.contains('.item-details', oauthClientID).should('exist').within(() => {
|
||||
// * Description should be edited
|
||||
cy.findByText(`${testApp}Edited`).should('exist');
|
||||
});
|
||||
|
||||
// # Visit a channel
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
cy.getCurrentChannelId().then((channelId) => {
|
||||
const message = 'OAuth test 02';
|
||||
|
||||
// # Post message using OAuth credentials
|
||||
cy.postIncomingWebhook({
|
||||
url: `${webhookBaseUrl}/post_oauth_message`,
|
||||
data: {
|
||||
channelId,
|
||||
message,
|
||||
}});
|
||||
|
||||
// * The message should be posted
|
||||
cy.findByText(message).should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T650 Deauthorize OAuth 2.0 Application', () => {
|
||||
cy.apiLogin(user1);
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
// # Go to OAuth apps settings
|
||||
cy.uiGetSetStatusButton().click();
|
||||
cy.get('#accountSettings').click();
|
||||
cy.get('#securityButton').click();
|
||||
cy.get('#appsEdit').click();
|
||||
|
||||
// * The app we created should be present
|
||||
// # Click deauthorize
|
||||
cy.get(`[data-app="${oauthClientID}"]`).should('exist').click();
|
||||
|
||||
// * The app should no longer exist
|
||||
cy.get(`[data-app="${oauthClientID}"]`).should('not.exist');
|
||||
|
||||
// # Close the account settings modal
|
||||
cy.get('#accountSettingsHeader').within(() => {
|
||||
cy.get('button.close').click();
|
||||
});
|
||||
|
||||
cy.getCurrentChannelId().then((channelId) => {
|
||||
const message = 'OAuth test 03';
|
||||
|
||||
// # Post message using OAuth credentials
|
||||
cy.postIncomingWebhook({
|
||||
url: `${webhookBaseUrl}/post_oauth_message`,
|
||||
data: {
|
||||
channelId,
|
||||
message,
|
||||
}});
|
||||
|
||||
// * The message should not be posted
|
||||
cy.findByText(message).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T651_1 Reconnect OAuth 2.0 Application - Connect application', () => {
|
||||
cy.apiLogin(user1);
|
||||
|
||||
// # Visit the webhook url to start the OAuth handshake
|
||||
cy.visit(`${webhookBaseUrl}/start_oauth`);
|
||||
|
||||
// # Click on the allow button
|
||||
cy.findByText('Allow').click();
|
||||
|
||||
// * Exchange successful
|
||||
cy.findByText('OK').should('exist');
|
||||
});
|
||||
|
||||
it('MM-T651_2 Reconnect OAuth 2.0 Application - Post message using OAuth credentials', () => {
|
||||
cy.apiLogin(user1);
|
||||
|
||||
// # Visit a channel
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
cy.getCurrentChannelId().then((channelId) => {
|
||||
const message = 'OAuth test 04';
|
||||
|
||||
// # Post message using OAuth credentials
|
||||
cy.postIncomingWebhook({
|
||||
url: `${webhookBaseUrl}/post_oauth_message`,
|
||||
data: {
|
||||
channelId,
|
||||
message,
|
||||
}});
|
||||
|
||||
// * The message should be posted
|
||||
cy.findByText(message).should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T652 Regenerate Secret', () => {
|
||||
cy.apiLogin(user1);
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
// # Navigate to OAuthApps in integrations menu
|
||||
cy.uiOpenProductMenu('Integrations');
|
||||
cy.get('#oauthApps').click();
|
||||
|
||||
cy.contains('.item-details', oauthClientID).within(() => {
|
||||
// # Regenerate secret
|
||||
cy.findByText('Regenerate Secret').click();
|
||||
cy.contains('.item-details__token', 'Client Secret').within(() => {
|
||||
cy.get('strong').invoke('text').then((clientSecret) => {
|
||||
// * Secret should be different to previous secret
|
||||
expect(clientSecret).to.not.equal(oauthClientSecret);
|
||||
|
||||
// # Save secret for later
|
||||
oauthClientSecret = clientSecret;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// # Visit a channel
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
cy.getCurrentChannelId().then((channelId) => {
|
||||
const message = 'OAuth test 05';
|
||||
|
||||
// # Post message using OAuth credentials
|
||||
cy.postIncomingWebhook({
|
||||
url: `${webhookBaseUrl}/post_oauth_message`,
|
||||
data: {
|
||||
channelId,
|
||||
message,
|
||||
}});
|
||||
|
||||
// * The message should be posted
|
||||
cy.findByText(message).should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T653 Unsuccessful reconnect with incorrect secret', () => {
|
||||
cy.apiLogin(user2);
|
||||
|
||||
// # Visit the webhook url to start the OAuth handshake
|
||||
cy.visit(`${webhookBaseUrl}/start_oauth`, {failOnStatusCode: false});
|
||||
|
||||
// # Click on the allow button
|
||||
cy.findByText('Allow').click();
|
||||
|
||||
// * Exchange not unsuccessful
|
||||
cy.contains('Invalid client credentials.').should('exist');
|
||||
});
|
||||
|
||||
it('MM-T654 Successful reconnect with updated secret', () => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Send new credentials
|
||||
cy.postIncomingWebhook({
|
||||
url: `${webhookBaseUrl}/send_oauth_credentials`,
|
||||
data: {
|
||||
appID: oauthClientID,
|
||||
appSecret: oauthClientSecret,
|
||||
}});
|
||||
|
||||
// # Visit the webhook url to start the OAuth handshake
|
||||
cy.visit(`${webhookBaseUrl}/start_oauth`, {failOnStatusCode: false});
|
||||
|
||||
// # Click on the allow button
|
||||
cy.findByText('Allow').click();
|
||||
|
||||
// * Exchange successful
|
||||
cy.findByText('OK').should('exist');
|
||||
});
|
||||
|
||||
it('MM-T655 Delete OAuth 2.0 Application', () => {
|
||||
cy.apiLogin(user1);
|
||||
cy.visit(testChannelUrl1);
|
||||
|
||||
// # Navigate to OAuthApps in integrations menu
|
||||
cy.uiOpenProductMenu('Integrations');
|
||||
cy.get('#oauthApps').click();
|
||||
|
||||
cy.contains('.item-details', oauthClientID).within(() => {
|
||||
// # Click Delete
|
||||
cy.findByText('Delete').click();
|
||||
});
|
||||
|
||||
// # Confirm Delete
|
||||
cy.contains('#confirmModalButton', 'Delete').click();
|
||||
|
||||
// # Go back to channels
|
||||
cy.visit(testChannelUrl1);
|
||||
cy.getCurrentChannelId().then((channelId) => {
|
||||
const message = 'OAuth test 06';
|
||||
|
||||
// # Post message using OAuth credentials
|
||||
cy.postIncomingWebhook({
|
||||
url: `${webhookBaseUrl}/post_oauth_message`,
|
||||
data: {
|
||||
channelId,
|
||||
message,
|
||||
}});
|
||||
|
||||
// * The message should not be posted
|
||||
cy.findByText(message).should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,226 @@
|
||||
// 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 @permissions
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
const deleteExistingTeamOverrideSchemes = () => {
|
||||
cy.apiGetSchemes('team').then(({schemes}) => {
|
||||
schemes.forEach((scheme) => {
|
||||
cy.apiDeleteScheme(scheme.id);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const createTeamOverrideSchemeWithPermission = (name, team, permissionId, permissionValue) => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Go to `User Management / Permissions` section
|
||||
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);
|
||||
|
||||
// # Type Name and Description
|
||||
cy.get('#scheme-name').should('be.visible').type(name);
|
||||
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(team.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
|
||||
cy.findByTestId(permissionId).then((el) => {
|
||||
if ((!el.hasClass('checked') && permissionValue) || (el.hasClass('checked') && !permissionValue)) {
|
||||
el.click();
|
||||
}
|
||||
});
|
||||
|
||||
// # Save scheme
|
||||
cy.get('#saveSetting').click().wait(TIMEOUTS.TWO_SEC);
|
||||
cy.apiLogout();
|
||||
};
|
||||
|
||||
describe('Team Permissions', () => {
|
||||
let testTeam;
|
||||
let testUser;
|
||||
let testPrivateCh;
|
||||
let otherUser;
|
||||
const schemeName = 'schemetest';
|
||||
before(() => {
|
||||
cy.apiRequireLicense();
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testTeam = team;
|
||||
testUser = user;
|
||||
cy.apiCreateChannel(testTeam.id, 'private-permissions-test', 'Private Permissions Test', 'P', '').then(({channel}) => {
|
||||
cy.apiAddUserToChannel(channel.id, testUser.id);
|
||||
testPrivateCh = channel;
|
||||
});
|
||||
cy.apiCreateUser().then(({user: newUser}) => {
|
||||
otherUser = newUser;
|
||||
cy.apiAddUserToTeam(testTeam.id, otherUser.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.apiResetRoles();
|
||||
deleteExistingTeamOverrideSchemes();
|
||||
});
|
||||
|
||||
it('MM-T2871 Member cannot add members to the team', () => {
|
||||
createTeamOverrideSchemeWithPermission(schemeName, testTeam, 'all_users-teams_team_scope-send_invites-checkbox', false);
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Go to main channel
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
|
||||
// # Open hamburger menu
|
||||
cy.uiOpenTeamMenu().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify `Invite People` menu item is not present
|
||||
cy.get('#invitePeople').should('not.exist');
|
||||
|
||||
// # Click `View Members` menu item
|
||||
cy.get('#viewMembers').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify team members modal opens
|
||||
cy.get('#teamMembersModal').should('be.visible');
|
||||
|
||||
// * Verify 'Invite People` button is not present
|
||||
cy.get('#invitePeople').should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T2876 Member cannot add or remove other members from private channel', () => {
|
||||
createTeamOverrideSchemeWithPermission(schemeName, testTeam, 'all_users-private_channel-manage_private_channel_members_and_read_groups-checkbox', false);
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Go to private channel
|
||||
cy.visit(`/${testTeam.name}/channels/${testPrivateCh.name}`);
|
||||
|
||||
// # Open channel header menu
|
||||
cy.uiOpenChannelMenu().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify dropdown opens
|
||||
cy.get('#channelHeaderDropdownMenu .Menu__content.dropdown-menu').should('be.visible');
|
||||
|
||||
// * Verify `Add Members` menu item is not present
|
||||
cy.get('#channelAddMembers').should('not.exist');
|
||||
|
||||
// * Verify `Manage Members` menu item is not present
|
||||
cy.get('#channelManageMembers').should('not.exist');
|
||||
|
||||
// * Verify `View Members` menu item is visible
|
||||
cy.get('#channelViewMembers').should('be.visible');
|
||||
|
||||
// # Close channel header menu
|
||||
cy.get('body').type('{esc}');
|
||||
|
||||
// # Open channel members list
|
||||
cy.get('.member-rhs__trigger').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify it does not countains Add or Manage buttons
|
||||
cy.uiGetRHS().contains('button', 'Manage').should('not.exist');
|
||||
cy.uiGetRHS().contains('button', 'Add').should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T2878 Member cannot create a private channel', () => {
|
||||
createTeamOverrideSchemeWithPermission(schemeName, testTeam, 'all_users-private_channel-create_private_channel-checkbox', false);
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Go to main channel
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
|
||||
// # Click on create new channel at LHS
|
||||
cy.uiBrowseOrCreateChannel('Create New Channel').click();
|
||||
|
||||
// * Verify that the create private channel is disabled
|
||||
cy.findByRole('dialog', {name: 'Create a new channel'}).find('#public-private-selector-button-P').should('have.class', 'disabled');
|
||||
});
|
||||
|
||||
it('MM-T2900 As a Channel Admin, the test user is now able to add or remove other users from public channel', () => {
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Create new public channel
|
||||
cy.apiCreateChannel(testTeam.id, 'public-permissions-test', 'Public Permissions Test', 'O', '').then(({channel}) => {
|
||||
// # Visit the created channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel header menu
|
||||
cy.uiOpenChannelMenu().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify dropdown opens
|
||||
cy.get('#channelHeaderDropdownMenu .Menu__content.dropdown-menu').should('be.visible');
|
||||
|
||||
// # Click on `Add Members`
|
||||
cy.get('#channelAddMembers').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// # Search and select otherUser
|
||||
cy.get('#selectItems input').typeWithForce(otherUser.username).wait(TIMEOUTS.HALF_SEC);
|
||||
cy.get('#multiSelectList div').eq(0).click();
|
||||
|
||||
// # Click `Save` button
|
||||
cy.get('#saveItems').should('be.visible').click().wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// # Open channel header menu
|
||||
cy.uiOpenChannelMenu().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify dropdown opens
|
||||
cy.get('#channelHeaderDropdownMenu .Menu__content.dropdown-menu').should('be.visible');
|
||||
|
||||
// # Click on `Manage Members`
|
||||
cy.get('#channelManageMembers').should('be.visible').click().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// # Click on `Member`
|
||||
cy.uiGetRHS().findByTestId(`memberline-${otherUser.id}`).within(() => {
|
||||
cy.findByTestId('rolechooser').should('be.visible').and('contain.text', 'Member').click().wait(TIMEOUTS.HALF_SEC);
|
||||
cy.findByTestId('rolechooser').within(() => {
|
||||
// * Verify the user can be removed
|
||||
cy.get('.Menu__content.dropdown-menu .MenuItem').eq(1).should('be.visible').and('contain.text', 'Remove from Channel').click();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2908 As a Team Admin, the test user is able to update the public channel Name, Header and Purpose', () => {
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Create new team
|
||||
cy.apiCreateTeam('test-team-permissions', 'Test Team Permissions').then(({team}) => {
|
||||
// # Visit the `Off-Topic` channel in the new team
|
||||
cy.visit(`/${team.name}/channels/off-topic`);
|
||||
|
||||
// # Open channel header menu
|
||||
cy.uiOpenChannelMenu().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify dropdown opens
|
||||
cy.get('#channelHeaderDropdownMenu .Menu__content.dropdown-menu').should('be.visible');
|
||||
|
||||
// * Verify `Edit Channel Header` menu item is visible
|
||||
cy.get('#channelEditHeader').should('be.visible');
|
||||
|
||||
// * Verify `Edit Channel Purpose` menu item is visible
|
||||
cy.get('#channelEditPurpose').should('be.visible');
|
||||
|
||||
// * Verify `Rename Channel` menu item is visible
|
||||
cy.get('#channelRename').should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,495 @@
|
||||
// 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 @profile_popover
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
import {createPrivateChannel} from '../elasticsearch_autocomplete/helpers';
|
||||
import {getAdminAccount} from '../../../../support/env';
|
||||
|
||||
describe('Profile popover', () => {
|
||||
let testTeam: Cypress.Team;
|
||||
let testUser: Cypress.UserProfile;
|
||||
let testChannel: Cypress.Channel;
|
||||
let privateChannel: Cypress.Channel;
|
||||
let otherUser: Cypress.UserProfile;
|
||||
let offTopicUrl: string;
|
||||
|
||||
before(() => {
|
||||
cy.apiRequireLicense();
|
||||
cy.apiInitSetup().then(({team, user, channel, offTopicUrl: url}) => {
|
||||
testTeam = team;
|
||||
testUser = user;
|
||||
testChannel = channel;
|
||||
offTopicUrl = url;
|
||||
|
||||
cy.apiCreateUser().then(({user: secondUser}) => {
|
||||
otherUser = secondUser;
|
||||
cy.apiAddUserToTeam(testTeam.id, secondUser.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
cy.apiResetRoles();
|
||||
cy.visit('/admin_console/user_management/permissions/system_scheme');
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').and('have.text', 'System Scheme');
|
||||
});
|
||||
|
||||
it('MM-T2 Add user — Error if already in channel', () => {
|
||||
cy.findByTestId('all_users-public_channel-checkbox').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are enabled
|
||||
verifyPermissionSubSections('all_users', 'public', true);
|
||||
|
||||
// * Verify that all the sub-checkboxes are enabled
|
||||
verifyPermissionSubSections('all_users', 'private', true);
|
||||
|
||||
cy.apiLogout();
|
||||
|
||||
// # Login as test user and go to off-topic
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
// # Send message
|
||||
cy.postMessage('Hi there');
|
||||
cy.apiLogout();
|
||||
|
||||
// # Login as the second user now
|
||||
cy.apiLogin(otherUser);
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
clickAddToChannel(testUser);
|
||||
|
||||
cy.get('div[aria-labelledby="addChannelModalLabel"]').within(() => {
|
||||
// # Type "Town" and press enter.
|
||||
cy.get('input').should('be.visible').type('Town').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// * Verify error message
|
||||
cy.get('#add-user-to-channel-modal__user-is-member').should('have.text', `${testUser.first_name} ${testUser.last_name} is already a member of that channel`);
|
||||
|
||||
// * And verify that button is disabled
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3 Add user — Public ON / Private OFF', () => {
|
||||
cy.findByTestId('all_users-private_channel-checkbox').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled
|
||||
verifyPermissionSubSections('all_users', 'private', false);
|
||||
|
||||
cy.findByTestId('saveSetting').as('saveButton').scrollIntoView();
|
||||
cy.get('@saveButton').should('be.visible').click();
|
||||
|
||||
cy.apiLogout();
|
||||
|
||||
// # Login as the second user now
|
||||
cy.apiLogin(otherUser);
|
||||
|
||||
// # Create a private channel
|
||||
createPrivateChannel(testTeam.id, otherUser).then((channel) => {
|
||||
privateChannel = channel;
|
||||
});
|
||||
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
clickAddToChannel(testUser);
|
||||
|
||||
cy.get('div[aria-labelledby="addChannelModalLabel"]').within(() => {
|
||||
// # Type "private" and press enter.
|
||||
cy.get('input').should('be.visible').type('private').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// # Verify that button is disabled
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4 Add user — Public OFF / Private ON', () => {
|
||||
cy.findByTestId('all_users-public_channel-checkbox').scrollIntoView().should('be.visible').click().click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled
|
||||
verifyPermissionSubSections('all_users', 'public', false);
|
||||
|
||||
// * Verify that all the sub-checkboxes are enabled
|
||||
verifyPermissionSubSections('all_users', 'private', true);
|
||||
|
||||
cy.findByTestId('saveSetting').as('saveButton').scrollIntoView();
|
||||
cy.get('@saveButton').should('be.visible').click();
|
||||
|
||||
cy.apiLogout();
|
||||
|
||||
// # Login as the second user now
|
||||
cy.apiLogin(otherUser);
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
clickAddToChannel(testUser);
|
||||
|
||||
cy.get('div[aria-labelledby="addChannelModalLabel"]').within(() => {
|
||||
// # Type "Town" and press enter.
|
||||
cy.get('input').should('be.visible').type('Town').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// * And verify that button is disabled
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('be.disabled');
|
||||
|
||||
// # Clear text box, type "Test Channel" and press enter.
|
||||
cy.get('input').should('be.visible').clear().type('Test Channel').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// * Verify that button is enabled
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('not.be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T6 Add User - Channel Admins (Public only)', () => {
|
||||
cy.findByTestId('all_users-public_channel-checkbox').scrollIntoView().should('be.visible').click().click();
|
||||
|
||||
cy.findByTestId('all_users-private_channel-checkbox').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled
|
||||
verifyPermissionSubSections('all_users', 'public', false);
|
||||
|
||||
// * Verify that all the sub-checkboxes are enabled
|
||||
verifyPermissionSubSections('all_users', 'private', false);
|
||||
|
||||
cy.findByTestId('channel_admin-public_channel-checkbox').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are enabled.
|
||||
verifyPermissionSubSections('channel_admin', 'public', true);
|
||||
|
||||
// # Clicking twice to disable it
|
||||
cy.findByTestId('channel_admin-private_channel-checkbox').scrollIntoView().should('be.visible').click().click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled
|
||||
verifyPermissionSubSections('channel_admin', 'private', false);
|
||||
|
||||
cy.findByTestId('saveSetting').as('saveButton').scrollIntoView();
|
||||
cy.get('@saveButton').should('be.visible').click();
|
||||
|
||||
// # Remove testUser from channel
|
||||
cy.removeUserFromChannel(testChannel.id, testUser.id);
|
||||
|
||||
cy.apiLogout();
|
||||
|
||||
// # Login
|
||||
cy.apiLogin(otherUser);
|
||||
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
|
||||
|
||||
// # Promote to channel admin
|
||||
promoteToChannelOrTeamAdmin(otherUser, testChannel.id);
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
clickAddToChannel(testUser);
|
||||
|
||||
cy.get('div[aria-labelledby="addChannelModalLabel"]').within(() => {
|
||||
// # Type "Channel" and press enter.
|
||||
cy.get('input').should('be.visible').type('Channel').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// * And verify that button is enabled
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('not.be.disabled');
|
||||
|
||||
// # Clear text box, type "private" and press enter.
|
||||
cy.get('input').should('be.visible').clear().type('private').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// * Verify that button is disabled.
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('be.disabled');
|
||||
|
||||
// # Clear text box, type "Channel" and press enter.
|
||||
cy.get('input').clear().type('Channel').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// # Now click the Add button
|
||||
cy.get('#add-user-to-channel-modal__add-button').click();
|
||||
});
|
||||
|
||||
// * Now verify that popup is gone
|
||||
cy.get('div[aria-labelledby="addChannelModalLabel"]').should('not.exist');
|
||||
|
||||
// # Visit that channel
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// * Verify that user added message is there.
|
||||
cy.findByTestId('postView', {timeout: TIMEOUTS.ONE_MIN}).find('.post-message__text').should('contain.text', `@${testUser.username} added to the channel by you.`);
|
||||
});
|
||||
|
||||
it('MM-T7 Add User — Team admins (Private only)', () => {
|
||||
cy.findByTestId('all_users-public_channel-checkbox').scrollIntoView().should('be.visible').click().click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled
|
||||
verifyPermissionSubSections('all_users', 'public', false);
|
||||
|
||||
cy.findByTestId('all_users-private_channel-checkbox').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled
|
||||
verifyPermissionSubSections('all_users', 'private', false);
|
||||
|
||||
cy.findByTestId('channel_admin-private_channel-checkbox').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are enabled
|
||||
verifyPermissionSubSections('channel_admin', 'private', true);
|
||||
|
||||
// # Clicking twice to disable it
|
||||
cy.findByTestId('team_admin-public_channel-checkbox').scrollIntoView().should('be.visible').click().click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled
|
||||
verifyPermissionSubSections('team_admin', 'public', false);
|
||||
cy.findByTestId('team_admin-private_channel-checkbox').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are enabled
|
||||
verifyPermissionSubSections('team_admin', 'private', true);
|
||||
|
||||
cy.findByTestId('saveSetting').as('saveButton').scrollIntoView();
|
||||
cy.get('@saveButton').should('be.visible').click();
|
||||
|
||||
// # Remove testUser from channel
|
||||
cy.removeUserFromChannel(testChannel.id, testUser.id);
|
||||
|
||||
// # Demote from being a channel admin.
|
||||
demoteToChannelOrTeamMember(otherUser, testChannel.id);
|
||||
|
||||
// # Promote other user to team admin
|
||||
promoteToChannelOrTeamAdmin(otherUser, testTeam.id, 'teams');
|
||||
cy.apiLogout();
|
||||
|
||||
// # Login as otheruser
|
||||
cy.apiLogin(otherUser);
|
||||
|
||||
// # Visit off-topic
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
clickAddToChannel(testUser);
|
||||
|
||||
cy.get('div[aria-labelledby="addChannelModalLabel"]').within(() => {
|
||||
// # Type "Public" and press enter.
|
||||
cy.get('input').should('be.visible').type('Public').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// * And verify that button is disabled
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('be.disabled');
|
||||
|
||||
// # Clear text box, type "Test Channel" and press enter.
|
||||
cy.get('input').should('be.visible').clear().type('Test Channel').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// * Verify that button is enabled.
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('not.be.disabled');
|
||||
|
||||
// # Now click the Add button
|
||||
cy.get('#add-user-to-channel-modal__add-button').click();
|
||||
});
|
||||
|
||||
// * Now verify that popup is gone
|
||||
cy.get('div[aria-labelledby="addChannelModalLabel"]').should('not.exist');
|
||||
|
||||
// # Visit that channel
|
||||
cy.visit(`/${testTeam.name}/channels/${privateChannel.name}`);
|
||||
|
||||
// * Verify that user added message is there.
|
||||
cy.findByTestId('postView', {timeout: TIMEOUTS.ONE_MIN}).find('.post-message__text').should('contain.text', `@${testUser.username} added to the channel by you.`);
|
||||
});
|
||||
|
||||
it('MM-T9 Add User - Any user (can add users)', () => {
|
||||
cy.findByTestId('all_users-public_channel-checkbox').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are enabled
|
||||
verifyPermissionSubSections('all_users', 'public', true);
|
||||
|
||||
// * Verify that all the sub-checkboxes are enabled
|
||||
verifyPermissionSubSections('all_users', 'private', true);
|
||||
|
||||
// # Demote other user to team member
|
||||
demoteToChannelOrTeamMember(otherUser, testTeam.id, 'teams');
|
||||
|
||||
// # Remove testUser from the private channel.
|
||||
cy.removeUserFromChannel(privateChannel.id, testUser.id);
|
||||
|
||||
cy.apiCreateChannel(testTeam.id, 'nomember', 'No Member');
|
||||
cy.apiLogout();
|
||||
|
||||
// # Login as otheruser
|
||||
cy.apiLogin(otherUser);
|
||||
|
||||
// # Visit off-topic
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
clickAddToChannel(testUser);
|
||||
|
||||
cy.get('div[aria-labelledby="addChannelModalLabel"]').within(() => {
|
||||
// # Type "No Member" and press enter.
|
||||
cy.get('input').should('be.visible').type('No Member').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// * Verify that button is disabled.
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('be.disabled');
|
||||
|
||||
// # Clear text box, type "Test Channel" and press enter.
|
||||
cy.get('input').should('be.visible').clear().type('Test Channel').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// * Verify that button is enabled.
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('not.be.disabled');
|
||||
|
||||
// # Type "Channel" and press enter.
|
||||
cy.get('input').should('be.visible').clear().type('Channel').wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||
|
||||
// * And verify that button is enabled
|
||||
cy.get('#add-user-to-channel-modal__add-button').should('not.be.disabled');
|
||||
|
||||
// # Now click the Add button
|
||||
cy.get('#add-user-to-channel-modal__add-button').click();
|
||||
});
|
||||
|
||||
// * Now verify that popup is gone
|
||||
cy.get('div[aria-labelledby="addChannelModalLabel"]').should('not.exist');
|
||||
|
||||
// # Visit that channel
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// * Verify that there are 2 post views now.
|
||||
cy.findAllByTestId('postView', {timeout: TIMEOUTS.ONE_MIN}).should('have.length', 2);
|
||||
|
||||
// * Verify that user added message is there.
|
||||
cy.findAllByTestId('postView').last().find('.post-message__text').should('contain.text', `@${testUser.username} added to the channel by you.`);
|
||||
});
|
||||
|
||||
it('MM-T1 Add User - System Admin only', () => {
|
||||
cy.findByTestId('all_users-public_channel-checkbox').scrollIntoView().should('be.visible').click().click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled.
|
||||
verifyPermissionSubSections('all_users', 'public', false);
|
||||
|
||||
cy.findByTestId('all_users-private_channel-checkbox').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled.
|
||||
verifyPermissionSubSections('all_users', 'public', false);
|
||||
|
||||
cy.findByTestId('channel_admin-public_channel-checkbox').scrollIntoView().should('be.visible').click().click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled.
|
||||
verifyPermissionSubSections('channel_admin', 'public', false);
|
||||
|
||||
cy.findByTestId('channel_admin-private_channel-checkbox').scrollIntoView().should('be.visible').click().click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled.
|
||||
verifyPermissionSubSections('channel_admin', 'private', false);
|
||||
|
||||
cy.findByTestId('team_admin-public_channel-checkbox').scrollIntoView().should('be.visible').click().click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled.
|
||||
verifyPermissionSubSections('team_admin', 'public', false);
|
||||
|
||||
cy.findByTestId('team_admin-private_channel-checkbox').scrollIntoView().should('be.visible').click().click();
|
||||
|
||||
// * Verify that all the sub-checkboxes are disabled.
|
||||
verifyPermissionSubSections('team_admin', 'private', false);
|
||||
|
||||
cy.findByTestId('saveSetting').as('saveButton').scrollIntoView();
|
||||
cy.get('@saveButton').should('be.visible').click();
|
||||
|
||||
cy.apiLogout();
|
||||
|
||||
// # Login
|
||||
cy.apiLogin(otherUser);
|
||||
cy.visit(offTopicUrl);
|
||||
verifyAddToChannel(testUser, false);
|
||||
|
||||
// # Promote to channel admin
|
||||
promoteToChannelOrTeamAdmin(otherUser, testChannel.id);
|
||||
|
||||
cy.apiLogout();
|
||||
|
||||
cy.apiLogin(otherUser);
|
||||
cy.visit(offTopicUrl);
|
||||
verifyAddToChannel(testUser, false);
|
||||
|
||||
// # Promote to team admin
|
||||
promoteToChannelOrTeamAdmin(otherUser, testTeam.id, 'teams');
|
||||
|
||||
cy.apiLogout();
|
||||
|
||||
cy.apiLogin(otherUser);
|
||||
cy.visit(offTopicUrl);
|
||||
verifyAddToChannel(testUser, false);
|
||||
cy.apiLogout();
|
||||
|
||||
// login as system admin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
cy.visit(offTopicUrl);
|
||||
|
||||
verifyAddToChannel(testUser);
|
||||
});
|
||||
});
|
||||
|
||||
const verifyPermissionSubSections = (category: string, publicOrPrivate: string, checked: boolean) => {
|
||||
let classCondition: string;
|
||||
if (checked) {
|
||||
classCondition = 'have.class';
|
||||
} else {
|
||||
classCondition = 'not.have.class';
|
||||
}
|
||||
|
||||
// # Expand the section
|
||||
cy.get('#' + category + '-' + publicOrPrivate + '_channel > .fa').scrollIntoView().should('be.visible').click();
|
||||
|
||||
if (category !== 'channel_admin') {
|
||||
cy.findByTestId(category + '-' + publicOrPrivate + '_channel-create_' + publicOrPrivate + '_channel-checkbox').should(classCondition, 'checked');
|
||||
}
|
||||
if (publicOrPrivate === 'public') {
|
||||
cy.findByTestId(`${category}-public_channel-convert_public_channel_to_private-checkbox`).should(classCondition, 'checked');
|
||||
}
|
||||
cy.findByTestId(`${category}-${publicOrPrivate}_channel-manage_${publicOrPrivate}_channel_properties-checkbox`).should(classCondition, 'checked');
|
||||
cy.findByTestId(`${category}-${publicOrPrivate}_channel-manage_${publicOrPrivate}_channel_members_and_read_groups-checkbox`).should(classCondition, 'checked');
|
||||
cy.findByTestId(`${category}-${publicOrPrivate}_channel-delete_${publicOrPrivate}_channel-checkbox`).should(classCondition, 'checked');
|
||||
};
|
||||
|
||||
const verifyAddToChannel = (user: Cypress.UserProfile, visible = true) => {
|
||||
// # Open profile popover
|
||||
cy.get('#postListContent', {timeout: TIMEOUTS.ONE_MIN}).within(() => {
|
||||
cy.findAllByText(user.username).first().should('have.text', user.username).click();
|
||||
});
|
||||
|
||||
if (visible) {
|
||||
// * Add to a Channel should not be visible
|
||||
cy.get('#addToChannelButton').should('be.visible');
|
||||
} else {
|
||||
// * Add to a Channel should not be visible
|
||||
cy.get('#addToChannelButton').should('not.exist');
|
||||
}
|
||||
};
|
||||
|
||||
const clickAddToChannel = (user: Cypress.UserProfile) => {
|
||||
// # Open profile popover
|
||||
cy.get('#postListContent', {timeout: TIMEOUTS.ONE_MIN}).within(() => {
|
||||
cy.findAllByText(`${user.username}`).first().should('have.text', user.username).click();
|
||||
});
|
||||
|
||||
// * Add to a Channel should not be visible
|
||||
cy.get('#addToChannelButton').should('be.visible').click();
|
||||
};
|
||||
|
||||
const promoteToChannelOrTeamAdmin = (user: Cypress.UserProfile, id: string, channelsOrTeams = 'channels') => {
|
||||
cy.externalRequest({
|
||||
user: getAdminAccount(),
|
||||
method: 'put',
|
||||
path: `${channelsOrTeams}/${id}/members/${user.id}/schemeRoles`,
|
||||
data: {
|
||||
scheme_user: true,
|
||||
scheme_admin: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const demoteToChannelOrTeamMember = (user: Cypress.UserProfile, id: string, channelsOrTeams = 'channels') => {
|
||||
cy.externalRequest({
|
||||
user: getAdminAccount(),
|
||||
method: 'put',
|
||||
path: `${channelsOrTeams}/${id}/members/${user.id}/schemeRoles`,
|
||||
data: {
|
||||
scheme_user: true,
|
||||
scheme_admin: false,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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 @profile_popover
|
||||
|
||||
describe('Profile popover User A & B', () => {
|
||||
let testTeam: Cypress.Team;
|
||||
let testUser: Cypress.UserProfile;
|
||||
let otherUser: Cypress.UserProfile;
|
||||
|
||||
before(() => {
|
||||
cy.apiRequireLicense();
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testTeam = team;
|
||||
testUser = user;
|
||||
|
||||
cy.apiCreateUser().then(({user: secondUser}) => {
|
||||
otherUser = secondUser;
|
||||
cy.apiAddUserToTeam(testTeam.id, secondUser.id);
|
||||
});
|
||||
|
||||
// # Remove the user from the team
|
||||
cy.removeUserFromTeam(testTeam.id, testUser.id);
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
cy.apiResetRoles();
|
||||
});
|
||||
|
||||
it('MM-T5 User A & User B (removed from team)', () => {
|
||||
// # Login as the other user
|
||||
cy.apiLogin(otherUser);
|
||||
cy.visit(`/${testTeam.name}/channels/off-topic`);
|
||||
|
||||
// # @ mention the kicked out user
|
||||
cy.postMessage(`Hi there @${testUser.username} `);
|
||||
|
||||
// # Click on the @ mention
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).
|
||||
find(`[data-mention=${testUser.username}]`).
|
||||
should('be.visible').
|
||||
click();
|
||||
});
|
||||
|
||||
// * Add to a Channel should not be shown.
|
||||
cy.findByText('Add to a Channel').should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T8 Add User - UserA & UserB (not on team)', () => {
|
||||
// # Create a new team
|
||||
cy.apiCreateTeam('team', 'Test NoMember').then(({team}) => {
|
||||
cy.apiAddUserToTeam(team.id, testUser.id);
|
||||
|
||||
// # Login as testuser
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Visit off-topic
|
||||
cy.visit(`/${team.name}/channels/off-topic`);
|
||||
|
||||
// # @ mention the kicked out user
|
||||
cy.postMessage(`Hi there @${otherUser.username} `);
|
||||
|
||||
// # Click on the @ mention
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).
|
||||
find(`[data-mention=${otherUser.username}]`).
|
||||
should('be.visible').
|
||||
click();
|
||||
cy.get('#user-profile-popover').should('be.visible');
|
||||
});
|
||||
|
||||
// # Add to a Channel should not be shown.
|
||||
cy.findByText('Add to a Channel').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,317 @@
|
||||
// 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 @saml
|
||||
// Skip: @headless @electron @firefox // run on Chrome (headed) only
|
||||
|
||||
import users from '../../../../fixtures/saml_users.json';
|
||||
|
||||
//Manual Setup required: Follow the instructions mentioned in the mattermost/platform-private/config/saml-okta-setup.txt file
|
||||
context('Okta', () => {
|
||||
const loginButtonText = 'SAML';
|
||||
|
||||
const regular1 = users.regulars['samluser-1'];
|
||||
const guest1 = users.guests['samlguest-1'];
|
||||
const guest2 = users.guests['samlguest-2'];
|
||||
const admin1 = users.admins['samladmin-1'];
|
||||
const admin2 = users.admins['samladmin-2'];
|
||||
|
||||
const {
|
||||
oktaBaseUrl,
|
||||
oktaMMAppName,
|
||||
oktaMMEntityId,
|
||||
} = Cypress.env();
|
||||
const idpUrl = `${oktaBaseUrl}/app/${oktaMMAppName}/${oktaMMEntityId}/sso/saml`;
|
||||
const idpMetadataUrl = `${oktaBaseUrl}/app/${oktaMMEntityId}/sso/saml/metadata`;
|
||||
|
||||
const newConfig = {
|
||||
SamlSettings: {
|
||||
Enable: true,
|
||||
EnableSyncWithLdap: false,
|
||||
EnableSyncWithLdapIncludeAuth: false,
|
||||
Verify: true,
|
||||
Encrypt: true,
|
||||
SignRequest: true,
|
||||
IdpURL: idpUrl,
|
||||
IdpDescriptorURL: `http://www.okta.com/${oktaMMEntityId}`,
|
||||
IdpMetadataURL: idpMetadataUrl,
|
||||
ServiceProviderIdentifier: `${Cypress.config('baseUrl')}/login/sso/saml`,
|
||||
AssertionConsumerServiceURL: `${Cypress.config('baseUrl')}/login/sso/saml`,
|
||||
SignatureAlgorithm: 'RSAwithSHA1',
|
||||
CanonicalAlgorithm: 'Canonical1.0',
|
||||
IdpCertificateFile: 'saml-idp.crt',
|
||||
PublicCertificateFile: 'saml-public.crt',
|
||||
PrivateKeyFile: 'saml-private.key',
|
||||
IdAttribute: '',
|
||||
GuestAttribute: '',
|
||||
EnableAdminAttribute: false,
|
||||
AdminAttribute: '',
|
||||
FirstNameAttribute: '',
|
||||
LastNameAttribute: '',
|
||||
EmailAttribute: 'Email',
|
||||
UsernameAttribute: 'Username',
|
||||
LoginButtonText: loginButtonText,
|
||||
},
|
||||
ExperimentalSettings: {
|
||||
UseNewSAMLLibrary: true,
|
||||
},
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
};
|
||||
|
||||
let testSettings;
|
||||
|
||||
//Note: the assumption is that this test suite runs on a clean setup (empty DB) which would ensure that the users are not present in the Mattermost instance beforehand
|
||||
describe('SAML Login flow', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for SAML
|
||||
cy.apiRequireLicenseForFeature('SAML');
|
||||
|
||||
// # Get certificates status and upload as necessary
|
||||
cy.apiGetSAMLCertificateStatus().then((resp) => {
|
||||
const data = resp.body;
|
||||
|
||||
if (!data.idp_certificate_file) {
|
||||
cy.apiUploadSAMLIDPCert('saml-idp.crt');
|
||||
}
|
||||
|
||||
if (!data.public_certificate_file) {
|
||||
cy.apiUploadSAMLPublicCert('saml-public.crt');
|
||||
}
|
||||
|
||||
if (!data.private_key_file) {
|
||||
cy.apiUploadSAMLPrivateKey('saml-private.key');
|
||||
}
|
||||
});
|
||||
|
||||
// # Check SAML metadata if working properly
|
||||
cy.apiGetMetadataFromIdp(idpMetadataUrl);
|
||||
|
||||
cy.oktaAddUsers(users);
|
||||
cy.apiUpdateConfig(newConfig).then(({config}) => {
|
||||
cy.setTestSettings(loginButtonText, config).then((_response) => {
|
||||
testSettings = _response;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Saml login new and existing MM regular user', () => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
testSettings.user = regular1;
|
||||
|
||||
//login new user
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
|
||||
cy.doSamlLogout(testSettings).then(() => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
//login existing user
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.doSamlLogout(testSettings).then(() => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Saml login new and existing MM guest user(userType=Guest)', () => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
testSettings.user = guest1;
|
||||
newConfig.SamlSettings.GuestAttribute = 'UserType=Guest';
|
||||
|
||||
cy.apiUpdateConfig(newConfig).then(() => {
|
||||
//login new user
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
|
||||
cy.doLogoutFromSignUp().then(() => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
//login existing user
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.doLogoutFromSignUp().then(() => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Saml login new and existing MM guest(isGuest=true)', () => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
testSettings.user = guest2;
|
||||
newConfig.SamlSettings.GuestAttribute = 'IsGuest=true';
|
||||
|
||||
cy.apiUpdateConfig(newConfig).then(() => {
|
||||
//login new user
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
|
||||
cy.doLogoutFromSignUp().then(() => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
//login existing user
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.doLogoutFromSignUp().then(() => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Saml login new and existing MM admin(userType=Admin)', () => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
testSettings.user = admin1;
|
||||
newConfig.SamlSettings.EnableAdminAttribute = true;
|
||||
newConfig.SamlSettings.AdminAttribute = 'UserType=Admin';
|
||||
|
||||
cy.apiUpdateConfig(newConfig).then(() => {
|
||||
//login new user
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
|
||||
cy.doSamlLogout(testSettings).then(() => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
//login existing user
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.doSamlLogout(testSettings).then(() => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Saml login new and existing MM admin(isAdmin=true)', () => {
|
||||
cy.apiAdminLogin();
|
||||
testSettings.user = admin2;
|
||||
newConfig.SamlSettings.EnableAdminAttribute = true;
|
||||
newConfig.SamlSettings.AdminAttribute = 'IsAdmin=true';
|
||||
|
||||
cy.apiUpdateConfig(newConfig).then(() => {
|
||||
//login new user
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
|
||||
cy.doSamlLogout(testSettings).then(() => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.doSamlLogout(testSettings).then(() => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Saml login invited Guest user to a team', () => {
|
||||
cy.apiAdminLogin();
|
||||
testSettings.user = regular1;
|
||||
|
||||
//login as a regular user - generate an invite link
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.skipOrCreateTeam(testSettings, oktaUserId).then((teamName) => {
|
||||
testSettings.teamName = teamName;
|
||||
|
||||
//get invite link
|
||||
cy.getInvitePeopleLink(testSettings).then((inviteUrl) => {
|
||||
//logout regular1
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogout(testSettings).then(() => {
|
||||
testSettings.user = guest1;
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((_oktaUserId) => {
|
||||
cy.visit(inviteUrl).then(() => {
|
||||
cy.oktaDeleteSession(_oktaUserId);
|
||||
|
||||
//login the guest
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.doLogoutFromSignUp();
|
||||
cy.oktaDeleteSession(_oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,197 @@
|
||||
// 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 @saml
|
||||
// Skip: @headless @electron @firefox // run on Chrome (headed) only
|
||||
|
||||
import users from '../../../../fixtures/saml_users.json';
|
||||
|
||||
//Manual Setup required: Follow the instructions mentioned in the mattermost/platform-private/config/saml-okta-setup.txt file
|
||||
context('LDAP SAML - Automated Tests (SAML TESTS)', () => {
|
||||
const loginButtonText = 'SAML';
|
||||
|
||||
const regular1 = users.regulars['samluser-1'];
|
||||
|
||||
const {
|
||||
oktaBaseUrl,
|
||||
oktaMMAppName,
|
||||
oktaMMEntityId,
|
||||
} = Cypress.env();
|
||||
const idpUrl = `${oktaBaseUrl}/app/${oktaMMAppName}/${oktaMMEntityId}/sso/saml`;
|
||||
const idpMetadataUrl = `${oktaBaseUrl}/app/${oktaMMEntityId}/sso/saml/metadata`;
|
||||
|
||||
const newConfig = {
|
||||
SamlSettings: {
|
||||
Enable: true,
|
||||
EnableSyncWithLdap: false,
|
||||
EnableSyncWithLdapIncludeAuth: false,
|
||||
Verify: true,
|
||||
Encrypt: true,
|
||||
SignRequest: true,
|
||||
IdpURL: idpUrl,
|
||||
IdpDescriptorURL: `http://www.okta.com/${oktaMMEntityId}`,
|
||||
IdpMetadataURL: idpMetadataUrl,
|
||||
ServiceProviderIdentifier: `${Cypress.config('baseUrl')}/login/sso/saml`,
|
||||
AssertionConsumerServiceURL: `${Cypress.config('baseUrl')}/login/sso/saml`,
|
||||
SignatureAlgorithm: 'RSAwithSHA1',
|
||||
CanonicalAlgorithm: 'Canonical1.0',
|
||||
IdpCertificateFile: 'saml-idp.crt',
|
||||
PublicCertificateFile: 'saml-public.crt',
|
||||
PrivateKeyFile: 'saml-private.key',
|
||||
IdAttribute: '',
|
||||
GuestAttribute: '',
|
||||
EnableAdminAttribute: false,
|
||||
AdminAttribute: '',
|
||||
FirstNameAttribute: '',
|
||||
LastNameAttribute: '',
|
||||
EmailAttribute: 'Email',
|
||||
UsernameAttribute: 'Username',
|
||||
LoginButtonText: loginButtonText,
|
||||
},
|
||||
ExperimentalSettings: {
|
||||
UseNewSAMLLibrary: false,
|
||||
},
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
};
|
||||
|
||||
let testSettings;
|
||||
|
||||
//Note: the assumption is that this test suite runs on a clean setup (empty DB) which would ensure that the users are not present in the Mattermost instance beforehand
|
||||
describe('LDAP SAML - Automated Tests (SAML TESTS)', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for SAML
|
||||
cy.apiRequireLicenseForFeature('SAML');
|
||||
|
||||
// # Get certificates status and upload as necessary
|
||||
cy.apiGetSAMLCertificateStatus().then((resp) => {
|
||||
const data = resp.body;
|
||||
|
||||
if (!data.idp_certificate_file) {
|
||||
cy.apiUploadSAMLIDPCert('saml-idp.crt');
|
||||
}
|
||||
|
||||
if (!data.public_certificate_file) {
|
||||
cy.apiUploadSAMLPublicCert('saml-public.crt');
|
||||
}
|
||||
|
||||
if (!data.private_key_file) {
|
||||
cy.apiUploadSAMLPrivateKey('saml-private.key');
|
||||
}
|
||||
});
|
||||
|
||||
// # Check SAML metadata if working properly
|
||||
cy.apiGetMetadataFromIdp(idpMetadataUrl);
|
||||
|
||||
cy.oktaAddUsers(users);
|
||||
cy.apiUpdateConfig(newConfig).then(({config}) => {
|
||||
cy.setTestSettings(loginButtonText, config).then((_response) => {
|
||||
testSettings = _response;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3012 - Check SAML Metadata without Enable Encryption', () => {
|
||||
cy.apiAdminLogin();
|
||||
const test1Settings = {
|
||||
...newConfig,
|
||||
SamlSettings: {
|
||||
...newConfig.SamlSettings,
|
||||
Encrypt: false,
|
||||
PublicCertificateFile: '',
|
||||
PrivateKeyFile: '',
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(test1Settings).then(() => {
|
||||
const baseUrl = Cypress.config('baseUrl');
|
||||
cy.request(`${baseUrl}/api/v4/saml/metadata`).then((resp) => {
|
||||
expect(resp.status).to.eq(200);
|
||||
expect(resp.headers['content-type']).to.eq('application/xml');
|
||||
expect(resp.body).to.contain('<?xml version');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3280 - SAML Login Audit', () => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
cy.apiUpdateConfig(newConfig).then(() => {
|
||||
testSettings.user = regular1;
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
|
||||
cy.uiOpenProfileModal('Security');
|
||||
cy.findByTestId('viewAccessHistory').click();
|
||||
cy.findByTestId('auditTableBody').find('td').
|
||||
each(($el) => {
|
||||
cy.wrap($el).
|
||||
invoke('text').
|
||||
then((text) => {
|
||||
if (text.includes('Saml obtained user')) {
|
||||
expect(text).to.contains('Saml obtained user');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3281 - SAML Signature Algorithm using RSAwithSHA256', () => {
|
||||
cy.apiAdminLogin();
|
||||
const test1Settings = {
|
||||
...newConfig,
|
||||
SamlSettings: {
|
||||
...newConfig.SamlSettings,
|
||||
SignatureAlgorithm: 'RSAwithSHA256',
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(test1Settings).then(() => {
|
||||
testSettings.user = regular1;
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.skipOrCreateTeam(testSettings, oktaUserId);
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('SAML Signature Algorithm using RSAwithSHA512', () => {
|
||||
cy.apiAdminLogin();
|
||||
const test1Settings = {
|
||||
...newConfig,
|
||||
SamlSettings: {
|
||||
...newConfig.SamlSettings,
|
||||
SignatureAlgorithm: 'RSAwithSHA512',
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(test1Settings).then(() => {
|
||||
testSettings.user = regular1;
|
||||
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
|
||||
cy.oktaDeleteSession(oktaUserId);
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
cy.doOktaLogin(testSettings.user).then(() => {
|
||||
cy.skipOrCreateTeam(testSettings, oktaUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,209 @@
|
||||
// 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 @saml
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
import {getRandomId} from '../../../../utils';
|
||||
|
||||
// assumes that E20 license is uploaded
|
||||
// Update config.mk to make sure docker images for openldap and keycloak
|
||||
// - assumes openldap docker available on config default http://localhost:389
|
||||
// - assumes keycloak docker - uses api to update
|
||||
// assumes the CYPRESS_* variables are set (CYPRESS_keycloakBaseUrl / CYPRESS_keycloakAppName)
|
||||
// requires {"chromeWebSecurity": false}
|
||||
// copy ./mattermost-server/build/docker/keycloak/keycloak.crt -> ./mattermost-webapp/e2e/cypress/tests/fixtures/keycloak.crt
|
||||
describe('SAML Guest', () => {
|
||||
const loginButtonText = 'SAML';
|
||||
|
||||
const guestUser = {
|
||||
username: 'guest.test',
|
||||
password: 'Password1',
|
||||
email: 'guest.test@mmtest.com',
|
||||
firstname: 'Guest',
|
||||
lastname: 'OneSaml',
|
||||
keycloakId: '',
|
||||
};
|
||||
const userFilter = `username=${guestUser.username}`;
|
||||
const keycloakBaseUrl = Cypress.env('keycloakBaseUrl') || 'http://localhost:8484';
|
||||
const keycloakAppName = Cypress.env('keycloakAppName') || 'mattermost';
|
||||
const idpUrl = `${keycloakBaseUrl}/auth/realms/${keycloakAppName}/protocol/saml`;
|
||||
const idpDescriptorUrl = `${keycloakBaseUrl}/auth/realms/${keycloakAppName}`;
|
||||
|
||||
const newConfig = {
|
||||
GuestAccountsSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
SamlSettings: {
|
||||
Enable: true,
|
||||
EnableSyncWithLdap: false,
|
||||
EnableSyncWithLdapIncludeAuth: false,
|
||||
Verify: true,
|
||||
Encrypt: false,
|
||||
SignRequest: false,
|
||||
IdpURL: idpUrl,
|
||||
IdpDescriptorURL: idpDescriptorUrl,
|
||||
IdpMetadataURL: '',
|
||||
ServiceProviderIdentifier: `${Cypress.config('baseUrl')}/login/sso/saml`,
|
||||
AssertionConsumerServiceURL: `${Cypress.config('baseUrl')}/login/sso/saml`,
|
||||
SignatureAlgorithm: 'RSAwithSHA256',
|
||||
CanonicalAlgorithm: 'Canonical1.0',
|
||||
IdpCertificateFile: 'saml-idp.crt',
|
||||
PublicCertificateFile: '',
|
||||
PrivateKeyFile: '',
|
||||
IdAttribute: 'username',
|
||||
GuestAttribute: '',
|
||||
EnableAdminAttribute: false,
|
||||
AdminAttribute: '',
|
||||
FirstNameAttribute: 'firstName',
|
||||
LastNameAttribute: 'lastName',
|
||||
EmailAttribute: 'email',
|
||||
UsernameAttribute: 'username',
|
||||
LoginButtonText: loginButtonText,
|
||||
},
|
||||
};
|
||||
|
||||
let testSettings;
|
||||
|
||||
before(() => {
|
||||
// * Check if server has license for SAML
|
||||
cy.apiRequireLicenseForFeature('SAML');
|
||||
|
||||
// # Upload certificate, overwrite existing
|
||||
cy.apiUploadSAMLIDPCert('keycloak.crt');
|
||||
|
||||
// # Update Configs
|
||||
cy.apiUpdateConfig(newConfig).then(({config}) => {
|
||||
cy.setTestSettings(loginButtonText, config).then((_response) => {
|
||||
testSettings = _response;
|
||||
cy.keycloakResetUsers({guestUser});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1423_1 - SAML Guest Setting disabled if Guest Access is turned off', () => {
|
||||
// # Visit saml settings
|
||||
cy.visit('/admin_console/authentication/saml');
|
||||
|
||||
// # Turn on Guest Attribute Filter
|
||||
cy.findByTestId('SamlSettings.GuestAttributeinput').clear().type('username=e2etest.one');
|
||||
|
||||
// # Save SAML Settings
|
||||
cy.findByText('Save').click().wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// # Visit Guest Access settings
|
||||
cy.visit('/admin_console/authentication/guest_access');
|
||||
|
||||
// # Turn off Guest Access
|
||||
cy.findByTestId('GuestAccountsSettings.Enablefalse').check();
|
||||
|
||||
// # Save Guest Access Settings
|
||||
cy.findByText('Save').click().wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// # Handle confirmation model
|
||||
cy.findByText('Save and Disable Guest Access').click().wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// # Visit saml settings
|
||||
cy.visit('/admin_console/authentication/saml');
|
||||
|
||||
// * verify Guest Attribute is disabled.
|
||||
cy.findByTestId('SamlSettings.GuestAttributeinput').should('be.disabled');
|
||||
});
|
||||
|
||||
it('MM-T1423_2 - SAML User will login as member', () => {
|
||||
const testConfig = {
|
||||
...newConfig,
|
||||
GuestAccountsSettings: {
|
||||
Enable: false,
|
||||
},
|
||||
};
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.apiUpdateConfig(testConfig);
|
||||
});
|
||||
|
||||
testSettings.user = guestUser;
|
||||
|
||||
// # MM Login via SAML
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
// # Login to Keycloak
|
||||
cy.doKeycloakLogin(testSettings.user).then(() => {
|
||||
// # Create team if no membership
|
||||
cy.skipOrCreateTeam(testSettings, getRandomId()).then(() => {
|
||||
// * check the user is member, if can create public channel
|
||||
cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').click();
|
||||
cy.get('#showNewChannel button').should('exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1426_1 - User logged in as member, filter does not match', () => {
|
||||
const testConfig = {
|
||||
...newConfig,
|
||||
GuestAccountsSettings: {
|
||||
...newConfig.GuestAccountSettings,
|
||||
Enable: true,
|
||||
},
|
||||
SamlSettings: {
|
||||
...newConfig.SamlSettings,
|
||||
GuestAttribute: 'username=Wrong',
|
||||
},
|
||||
};
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.apiUpdateConfig(testConfig);
|
||||
});
|
||||
|
||||
testSettings.user = guestUser;
|
||||
|
||||
// # MM Login via SAML
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
// # Login to Keycloak
|
||||
cy.doKeycloakLogin(testSettings.user).then(() => {
|
||||
// # Create team if no membership
|
||||
cy.skipOrCreateTeam(testSettings, getRandomId()).then(() => {
|
||||
// * check the user is member, if can create public channel
|
||||
cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').click();
|
||||
cy.get('#showNewChannel button').should('exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1426_2 - User logged in as guest, correct filter', () => {
|
||||
const testConfig = {
|
||||
...newConfig,
|
||||
GuestAccountsSettings: {
|
||||
...newConfig.GuestAccountsSettings,
|
||||
Enable: true,
|
||||
},
|
||||
SamlSettings: {
|
||||
...newConfig.SamlSettings,
|
||||
GuestAttribute: userFilter,
|
||||
},
|
||||
};
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.apiUpdateConfig(testConfig);
|
||||
});
|
||||
|
||||
testSettings.user = guestUser;
|
||||
|
||||
// # MM Login via SAML
|
||||
cy.doSamlLogin(testSettings).then(() => {
|
||||
// # Login to Keycloak
|
||||
cy.doKeycloakLogin(testSettings.user).then(() => {
|
||||
// # Create team if no membership
|
||||
cy.skipOrCreateTeam(testSettings, getRandomId()).then(() => {
|
||||
// * check the user is guest, cannot create public channel
|
||||
cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// 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 @saml
|
||||
|
||||
/**
|
||||
* Note: This test requires Enterprise license to be uploaded
|
||||
*/
|
||||
const testSamlMetadataUrl = 'http://test_saml_metadata_url';
|
||||
const testIdpURL = 'http://test_idp_url';
|
||||
const testIdpDescriptorURL = 'http://test_idp_descriptor_url';
|
||||
const getSamlMetadataErrorMessage = 'SAML Metadata URL did not connect and pull data successfully';
|
||||
|
||||
let config;
|
||||
|
||||
describe('SystemConsole->SAML 2.0 - Get Metadata from Idp Flow', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for SAML
|
||||
cy.apiRequireLicenseForFeature('SAML');
|
||||
|
||||
cy.apiUpdateConfig({
|
||||
SamlSettings: {
|
||||
Enable: true,
|
||||
AssertionConsumerServiceURL: Cypress.config('baseUrl') + '/login/sso/saml',
|
||||
ServiceProviderIdentifier: Cypress.config('baseUrl') + '/login/sso/saml',
|
||||
IdpMetadataURL: '',
|
||||
IdpURL: testIdpURL,
|
||||
IdpDescriptorURL: testIdpDescriptorURL,
|
||||
},
|
||||
}).then((data) => {
|
||||
({config} = data);
|
||||
});
|
||||
|
||||
//make sure we can navigate to SAML settings
|
||||
cy.visit('/admin_console/authentication/saml');
|
||||
cy.get('.admin-console__header').should('be.visible').and('have.text', 'SAML 2.0');
|
||||
});
|
||||
|
||||
it('fail to fetch metadata from Idp Metadata Url', () => {
|
||||
// * Verify that the metadata Url textbox is enabled and empty
|
||||
cy.findByTestId('SamlSettings.IdpMetadataURLinput').
|
||||
scrollIntoView().should('be.visible').and('be.enabled').and('have.text', '');
|
||||
|
||||
// * Verify that the Get Metadata Url fetch button is disabled
|
||||
cy.get('#getSamlMetadataFromIDPButton').find('button').should('be.visible').and('be.disabled');
|
||||
|
||||
// # Type in the metadata Url in the metadata Url textbox
|
||||
cy.findByTestId('SamlSettings.IdpMetadataURLinput').
|
||||
scrollIntoView().should('be.visible').
|
||||
focus().type(testSamlMetadataUrl);
|
||||
|
||||
// # Click on the Get SAML Metadata Button
|
||||
cy.get('#getSamlMetadataFromIDPButton button').click();
|
||||
|
||||
// * Verify that we get the right error message
|
||||
cy.get('#getSamlMetadataFromIDPButton').should('be.visible').contains(getSamlMetadataErrorMessage);
|
||||
|
||||
// * Verify that the IdpURL textbox content has not been updated
|
||||
cy.findByTestId('SamlSettings.IdpURLinput').then((elem) => {
|
||||
Cypress.$(elem).val() === config.SamlSettings.IdpURL;
|
||||
});
|
||||
|
||||
// * Verify that the IdpDescriptorURL textbox content has not been updated
|
||||
cy.findByTestId('SamlSettings.IdpDescriptorURL').then((elem) => {
|
||||
Cypress.$(elem).val() === config.SamlSettings.IdpDescriptorURL;
|
||||
});
|
||||
|
||||
// * Verify that the IdpDescriptorURL textbox content has been updated
|
||||
cy.findByTestId('SamlSettings.ServiceProviderIdentifier').then((elem) => {
|
||||
Cypress.$(elem).val() === config.SamlSettings.ServiceProviderIdentifier;
|
||||
});
|
||||
|
||||
// * Verify that we can successfully save the settings (we have not affected previous state)
|
||||
cy.get('#saveSetting').click();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,194 @@
|
||||
// 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
|
||||
|
||||
function withTrialBefore(trialed: string) {
|
||||
cy.intercept('GET', '**/api/v4/trial-license/prev', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
IsLicensed: trialed,
|
||||
IsTrial: trialed,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function withTrialLicense(trial: string) {
|
||||
cy.intercept('GET', '**/api/v4/license/client?format=old', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
IsLicensed: 'true',
|
||||
IsTrial: trial,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
describe('Self hosted Pricing modal', () => {
|
||||
let urlL: string | undefined;
|
||||
let createdUser: Cypress.UserProfile | undefined;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({user, offTopicUrl: url}) => {
|
||||
urlL = url;
|
||||
createdUser = user;
|
||||
cy.apiAdminLogin();
|
||||
cy.apiDeleteLicense();
|
||||
cy.visit(url);
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Upgrade button in global header for admin users on starter plan', () => {
|
||||
// * Check that Upgrade button does not show
|
||||
cy.get('#UpgradeButton').should('exist').contains('View plans');
|
||||
|
||||
// * Check for Upgrade button tooltip
|
||||
cy.get('#UpgradeButton').trigger('mouseover').then(() => {
|
||||
cy.get('#upgrade_button_tooltip').should('be.visible').contains('Only visible to system admins');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not show Upgrade button in global header for non admin users', () => {
|
||||
cy.apiLogout();
|
||||
cy.apiLogin(createdUser);
|
||||
cy.visit(urlL);
|
||||
|
||||
// * Check that Upgrade button does not show
|
||||
cy.get('#UpgradeButton').should('not.exist');
|
||||
});
|
||||
|
||||
it('should not show Upgrade button for admin users on non trial licensed server', () => {
|
||||
// * Ensure the server has trial license
|
||||
withTrialBefore('false');
|
||||
withTrialLicense('false');
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// * Verify the license is not trial
|
||||
cy.visit('admin_console/about/license');
|
||||
cy.get('div.Badge').should('not.exist');
|
||||
cy.findByTitle('Back Icon').should('be.visible').click();
|
||||
|
||||
// * Open pricing modal
|
||||
cy.get('#UpgradeButton').should('not.exist');
|
||||
});
|
||||
|
||||
it('Upgrade button should open pricing modal admin users when no trial has ever been added on free plan', () => {
|
||||
// *Ensure the server has had no trial license before
|
||||
withTrialBefore('false');
|
||||
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// * Open pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
|
||||
// * Check that professional upgrade button is available
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#professional').should('be.visible');
|
||||
cy.get('#professional_action').should('not.be.disabled').contains('Upgrade');
|
||||
|
||||
// * Check that enteprise trial button is available
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#enterprise').should('be.visible');
|
||||
cy.get('#start_trial_btn').should('not.be.disabled').contains('Try free for 30 days');
|
||||
});
|
||||
|
||||
it('Upgrade button should open pricing modal admin users when the server has requested a trial before on free plan', () => {
|
||||
// *Ensure the server has had no trial license before
|
||||
withTrialBefore('true');
|
||||
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// * Open pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// *Check that option to get cloud exists
|
||||
cy.get('.alert-option').should('be.visible');
|
||||
cy.get('span').contains('Looking for a cloud option?');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
|
||||
// * Check that professional upgrade button is available
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#professional').should('be.visible');
|
||||
cy.get('#professional_action').should('not.be.disabled').contains('Upgrade');
|
||||
|
||||
// * Check that contact sales button is now showing and not trial button
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#enterprise').should('be.visible');
|
||||
cy.get('#enterprise_action').should('not.be.disabled').contains('Contact Sales');
|
||||
});
|
||||
|
||||
it('Upgrade button should open pricing modal admin users when the server is on a trial', () => {
|
||||
// * Ensure the server has trial license
|
||||
withTrialBefore('false');
|
||||
withTrialLicense('true');
|
||||
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// * Verify the license is not trial
|
||||
cy.visit('admin_console/about/license');
|
||||
cy.get('div.Badge').should('exist').should('contain', 'Trial');
|
||||
cy.findByTitle('Back Icon').should('be.visible').click();
|
||||
cy.visit(urlL);
|
||||
|
||||
// * Open pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// *Check that free card Downgrade button is disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
|
||||
// * Check that professional upgrade button is available
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#professional').should('be.visible');
|
||||
cy.get('#professional_action').should('not.be.disabled').contains('Upgrade');
|
||||
|
||||
// * Check that contact sales button is now showing and not trial button
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#enterprise').should('be.visible');
|
||||
cy.get('#start_trial_btn').should('not.be.disabled');
|
||||
});
|
||||
|
||||
it('Upgrade button should open air gapped modal when hosted signup is not available', () => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
cy.intercept('GET', '**/api/v4/hosted_customer/signup_available', {
|
||||
statusCode: 501,
|
||||
body: {
|
||||
message: 'An unknown error occurred. Please try again or contact support.',
|
||||
},
|
||||
}).as('airGappedCheck');
|
||||
|
||||
// * Open pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
cy.wait('@airGappedCheck');
|
||||
|
||||
// * Click the upgrade button to open the modal
|
||||
cy.get('#professional_action').should('exist').click();
|
||||
|
||||
cy.get('.air-gapped-purchase-modal').should('exist');
|
||||
|
||||
cy.findByText('https://mattermost.com/pricing/#self-hosted').last().should('exist');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,473 @@
|
||||
// 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.
|
||||
// ***************************************************************
|
||||
|
||||
// e.g. not_cloud cloud because we always want to exclude running automatically
|
||||
// until we create the special self-hosted run setup
|
||||
// Stage: @dev
|
||||
// Group: @channels @enterprise @not_cloud @cloud @hosted_customer
|
||||
|
||||
// To run this locally, the necessary test setup is:
|
||||
// * Ensure on latest mattermost-webapp, mattermost-server, enterprise
|
||||
// * Ensure MM_SERVICESETTINGS_ENABLEDEVELOPER=false in server shell
|
||||
// * Ensure CloudSettings.CWSURL is set to https://portal.test.cloud.mattermost.com
|
||||
// * Ensure CloudSettings.CWSAPIURL is set to https://portal.internal.test.cloud.mattermost.com
|
||||
// * Change mattermost-server utils/license.go to test public key
|
||||
// * e.g. see (https://github.com/mattermost/mattermost-server/pull/16778/files)
|
||||
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
function verifyPurchaseModal() {
|
||||
cy.contains('Provide your payment details');
|
||||
cy.contains('Contact Sales');
|
||||
cy.contains('Compare plans');
|
||||
cy.contains('Credit Card');
|
||||
cy.contains('Billing address');
|
||||
cy.contains('Enterprise Edition Subscription Terms');
|
||||
cy.contains('You will be billed today.');
|
||||
}
|
||||
|
||||
interface PurchaseForm {
|
||||
card: string;
|
||||
expires: string;
|
||||
cvc: string;
|
||||
org: string;
|
||||
name: string;
|
||||
country: string;
|
||||
address: string;
|
||||
city: string;
|
||||
state: string;
|
||||
zip: string;
|
||||
agree: boolean;
|
||||
seats?: number;
|
||||
}
|
||||
const additionalSeatsToPurchase = 10;
|
||||
const successCardNumber = '4242424242424242';
|
||||
const failCardNumber = '4000000000000002';
|
||||
const defaultSuccessForm: PurchaseForm = {
|
||||
card: successCardNumber,
|
||||
expires: '424', // e.g. 4/24
|
||||
cvc: '242',
|
||||
org: 'My org',
|
||||
name: 'The Cardholder',
|
||||
country: 'United States of America',
|
||||
address: '123 Main Street',
|
||||
city: 'Minneapolis',
|
||||
state: 'Minnesota',
|
||||
zip: '55423',
|
||||
agree: true,
|
||||
};
|
||||
|
||||
const prefilledProvinceCountryRegions = {
|
||||
'United States of America': true,
|
||||
Canada: true,
|
||||
};
|
||||
|
||||
function changeByPlaceholder(placeholder: string, value: string) {
|
||||
cy.findByPlaceholderText(placeholder).type(value);
|
||||
}
|
||||
function selectDropdownValue(placeholder: string, value: string) {
|
||||
cy.contains(placeholder).click();
|
||||
cy.contains(value).click();
|
||||
}
|
||||
|
||||
function fillForm(form: PurchaseForm, currentUsers: Cypress.Chainable<number>) {
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(form.card);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(form.expires);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(form.cvc);
|
||||
});
|
||||
|
||||
changeByPlaceholder('Organization Name', form.org);
|
||||
|
||||
changeByPlaceholder('Name on Card', form.name);
|
||||
selectDropdownValue('Country', form.country);
|
||||
changeByPlaceholder('Address', form.address);
|
||||
changeByPlaceholder('City', form.city);
|
||||
if (prefilledProvinceCountryRegions[form.country]) {
|
||||
selectDropdownValue('State/Province', form.state);
|
||||
} else {
|
||||
changeByPlaceholder('State/Province', form.state);
|
||||
}
|
||||
changeByPlaceholder('Zip/Postal Code', form.zip);
|
||||
|
||||
if (form.agree) {
|
||||
cy.get('#self_hosted_purchase_terms').click();
|
||||
}
|
||||
|
||||
if (form === defaultSuccessForm) {
|
||||
currentUsers.then((userCount) => {
|
||||
cy.findByTestId('selfHostedPurchaseSeatsInput').clear().type((userCount + additionalSeatsToPurchase).toString());
|
||||
});
|
||||
} else if (form.seats) {
|
||||
cy.findByTestId('selfHostedPurchaseSeatsInput').clear().type(form.seats.toString());
|
||||
}
|
||||
|
||||
// while this will not work if the caller passes in an object
|
||||
// that has member equality but not reference equality, this is
|
||||
// good enough for the limited usage this function has
|
||||
if (form === defaultSuccessForm) {
|
||||
cy.contains('Upgrade').should('be.enabled');
|
||||
}
|
||||
|
||||
return cy.contains('Upgrade');
|
||||
}
|
||||
|
||||
function assertLine(lines: string[], key: string, value: string) {
|
||||
const line = lines.find((line) => line.includes(key));
|
||||
if (!line) {
|
||||
throw new Error('Expected license to show start date line but did not');
|
||||
}
|
||||
if (!line.includes(value)) {
|
||||
throw new Error(`Expected license ${key} of ${value}, but got ${line}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentUsers(): Cypress.Chainable<number> {
|
||||
return cy.request('/api/v4/analytics/old?name=standard&team_id=').then((response) => {
|
||||
const userCount = response.body.find((row: Cypress.AnalyticsRow) => row.name === 'unique_user_count');
|
||||
return userCount.value;
|
||||
});
|
||||
}
|
||||
|
||||
describe('Self hosted Purchase', () => {
|
||||
let adminUser: Cypress.UserProfile | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
// prevent failed tests from bleeding over
|
||||
window.localStorage.removeItem('PURCHASE_IN_PROGRESS');
|
||||
});
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(() => {
|
||||
cy.apiAdminLogin().then((result) => {
|
||||
// assertion because current typings are wrong.
|
||||
adminUser = (result as unknown as {user: Cypress.UserProfile}).user;
|
||||
cy.apiDeleteLicense();
|
||||
cy.visit('/');
|
||||
|
||||
// in case there is lingering state from a prior local run or some other
|
||||
// failed test, we clear it out
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/hosted_customer/bootstrap',
|
||||
method: 'POST',
|
||||
qs: {
|
||||
reset: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('happy path, can purchase a license and have it applied automatically', () => {
|
||||
cy.apiAdminLogin();
|
||||
cy.apiDeleteLicense();
|
||||
|
||||
cy.intercept('GET', '**/api/v4/hosted_customer/signup_available').as('airGappedCheck');
|
||||
cy.intercept('GET', 'https://js.stripe.com/v3').as('stripeCheck');
|
||||
cy.intercept('GET', '**/api/v4/cloud/products/selfhosted').as('products');
|
||||
|
||||
// # Open pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
cy.wait('@airGappedCheck');
|
||||
cy.wait('@stripeCheck');
|
||||
|
||||
// The waits for these fetches is usually enough. Add a little wait
|
||||
// for all the selectors to be updated and rerenders to happen
|
||||
// so that we do not accidentally hit the air-gapped modal
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(50);
|
||||
|
||||
// # Click the upgrade button to open the modal
|
||||
cy.get('#professional_action').should('exist').click();
|
||||
|
||||
// * Verify basic purchase elements are available
|
||||
verifyPurchaseModal();
|
||||
|
||||
// # fill out purchase form
|
||||
fillForm(defaultSuccessForm, getCurrentUsers());
|
||||
|
||||
// # Wait explicitly for purchase to occur because it takes so long.
|
||||
cy.intercept('POST', '**/api/v4/hosted_customer/customer').as('createCustomer');
|
||||
cy.intercept('POST', '**/api/v4/hosted_customer/confirm').as('purchaseLicense');
|
||||
|
||||
cy.contains('Upgrade').click();
|
||||
|
||||
cy.wait('@createCustomer');
|
||||
|
||||
// The purchase endpoint is a long once. The server itself waits two minutes.
|
||||
// Waiting a little longer ensures we don't give up on the server when it
|
||||
// succeeds (albeit slowly)
|
||||
cy.wait('@purchaseLicense', {responseTimeout: TIMEOUTS.TWO_MIN + TIMEOUTS.ONE_HUNDRED_MILLIS});
|
||||
|
||||
// * Verify license was applied
|
||||
cy.contains('Your Professional license has now been applied.');
|
||||
|
||||
// # Close modal
|
||||
cy.contains('Close').click();
|
||||
|
||||
const today = new Date().toLocaleString().split(/\D/).slice(0, 3).join('/');
|
||||
const expiresDate = new Date(Date.now() + (366 * 24 * 60 * 60 * 1000)).toLocaleString().split(/\D/).slice(0, 3).join('/');
|
||||
const todayPadded = new Date().toLocaleString().split(/\D/).slice(0, 3).map((num) => num.padStart(2, '0')).join('/');
|
||||
|
||||
// # Visit Edition and License page
|
||||
cy.visit('/admin_console/about/license');
|
||||
|
||||
// * Verify information on the new purchased license
|
||||
|
||||
cy.contains('Edition and License');
|
||||
cy.contains('Mattermost Professional');
|
||||
|
||||
// need to wait for all data to load in, so you don't get flaky
|
||||
// asserts over still not filled in items
|
||||
cy.wait(TIMEOUTS.ONE_SEC);
|
||||
cy.findByTestId('EnterpriseEditionLeftPanel').
|
||||
get('.item-element').
|
||||
then(($els) => Cypress._.map($els, 'innerText')).
|
||||
then((lines) => {
|
||||
assertLine(lines, 'START DATE', today);
|
||||
assertLine(lines, 'EXPIRES', expiresDate);
|
||||
|
||||
getCurrentUsers().then((userCount) => {
|
||||
// * Verify user input of extra seats was honored
|
||||
assertLine(lines, 'USERS', (userCount + additionalSeatsToPurchase).toString());
|
||||
assertLine(lines, 'ACTIVE USERS', userCount.toString());
|
||||
});
|
||||
assertLine(lines, 'EDITION', 'Mattermost Professional');
|
||||
assertLine(lines, 'ISSUED', today);
|
||||
|
||||
assertLine(lines, 'NAME', adminUser.first_name + ' ' + adminUser.last_name);
|
||||
assertLine(lines, 'COMPANY / ORG', defaultSuccessForm.org);
|
||||
});
|
||||
|
||||
// # Visit invoices page
|
||||
cy.visit('/admin_console/billing/billing_history');
|
||||
|
||||
// * Ensure we are not redirected
|
||||
cy.contains('Billing History');
|
||||
|
||||
// * Ensure summary values are correct
|
||||
cy.contains(todayPadded);
|
||||
cy.contains('Self-Hosted Professional');
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const dollarUSLocale = Intl.NumberFormat('en-US', {style: 'currency', currency: 'USD', minimumFractionDigits: 2});
|
||||
|
||||
// * Verify payment matches what the user was told they would pay
|
||||
getCurrentUsers().then((userCount) => {
|
||||
cy.contains(`${userCount + additionalSeatsToPurchase} users`);
|
||||
cy.wait('@products').then((res) => {
|
||||
const product = res.response.body.find((product: Cypress.Product) => product.sku === 'professional');
|
||||
const purchaseAmount = dollarUSLocale.format((userCount + additionalSeatsToPurchase) * (product).price_per_seat * 12);
|
||||
cy.contains(purchaseAmount);
|
||||
});
|
||||
});
|
||||
cy.contains('Paid');
|
||||
|
||||
// * Check the content from the downloaded pdf file
|
||||
cy.get('.BillingHistory__table-invoice >a').then((link) => {
|
||||
cy.request({
|
||||
url: link.prop('href'),
|
||||
encoding: 'binary',
|
||||
}).then(
|
||||
(response) => {
|
||||
const fileName = 'self-hosted-purchase-invoice';
|
||||
const filePath = Cypress.config('downloadsFolder') + '/' + fileName + '.pdf';
|
||||
cy.writeFile(filePath, response.body, 'binary');
|
||||
cy.task('getPdfContent', filePath).then((data) => {
|
||||
const allLines = (data as {text: string}).text.split('\n');
|
||||
const prodLine = allLines.filter((line) => line.includes('Self-Hosted Professional'));
|
||||
expect(prodLine.length).to.be.equal(1);
|
||||
getCurrentUsers().then((userCount) => {
|
||||
cy.wait('@products').then((res) => {
|
||||
const product = res.response.body.find((product: Cypress.Product) => product.sku === 'professional');
|
||||
const purchaseAmount = dollarUSLocale.format((userCount + additionalSeatsToPurchase) * (product).price_per_seat * 12);
|
||||
const amountLine = allLines.find((line: string) => line.includes('Amount paid'));
|
||||
if (!amountLine.includes(purchaseAmount)) {
|
||||
throw new Error(`Expected purchase amount ${purchaseAmount}, but amount line was ${amountLine}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// * Check that creating groups, a professional feature, is now available for use.
|
||||
cy.visit('/');
|
||||
cy.uiGetProductMenuButton().click();
|
||||
cy.contains('User Groups').click();
|
||||
cy.contains('Create Group').should('be.enabled');
|
||||
});
|
||||
|
||||
it('must purchase a license for at least the current number of users', () => {
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/');
|
||||
cy.apiDeleteLicense();
|
||||
|
||||
cy.intercept('GET', '**/api/v4/hosted_customer/signup_available').as('airGappedCheck');
|
||||
cy.intercept('GET', 'https://js.stripe.com/v3').as('stripeCheck');
|
||||
cy.intercept('GET', '**/api/v4/cloud/products/selfhosted').as('products');
|
||||
|
||||
// # Open pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
cy.wait('@airGappedCheck');
|
||||
cy.wait('@stripeCheck');
|
||||
cy.wait('@products');
|
||||
|
||||
// The waits for these fetches is usually enough. Add a little wait
|
||||
// for all the selectors to be updated and rerenders to happen
|
||||
// so that we do not accidentally hit the air-gapped modal
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(50);
|
||||
|
||||
// # Click the upgrade button to open the modal
|
||||
cy.get('#professional_action').should('exist').click();
|
||||
|
||||
// * Verify basic purchase elements are available
|
||||
verifyPurchaseModal();
|
||||
|
||||
// # Fill form with too low of a number of seats
|
||||
fillForm({...defaultSuccessForm, seats: 1}, getCurrentUsers());
|
||||
|
||||
getCurrentUsers().then((currentUsers) => {
|
||||
// * Verify form can not be submitted
|
||||
cy.contains(`Your workspace currently has ${currentUsers} users`).should('not.be.enabled');
|
||||
cy.contains('Upgrade').should('not.be.enabled');
|
||||
|
||||
// # Fill form the same number of seats as current users
|
||||
cy.findByTestId('selfHostedPurchaseSeatsInput').clear().type(currentUsers.toString());
|
||||
});
|
||||
|
||||
// * Verify form can be submitted
|
||||
cy.contains('Upgrade').should('be.enabled');
|
||||
|
||||
// # Close purchase flow, as otherwise you will get a purchase in progress error
|
||||
cy.get('#closeIcon').click();
|
||||
});
|
||||
|
||||
it('failed payment in stripe means no license is received', () => {
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/');
|
||||
cy.apiDeleteLicense();
|
||||
|
||||
cy.intercept('GET', '**/api/v4/hosted_customer/signup_available').as('airGappedCheck');
|
||||
cy.intercept('GET', 'https://js.stripe.com/v3').as('stripeCheck');
|
||||
cy.intercept('GET', '**/api/v4/cloud/products/selfhosted').as('products');
|
||||
|
||||
// # Open pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
cy.wait('@airGappedCheck');
|
||||
cy.wait('@stripeCheck');
|
||||
cy.wait('@products');
|
||||
|
||||
// The waits for these fetches is usually enough. Add a little wait
|
||||
// for all the selectors to be updated and rerenders to happen
|
||||
// so that we do not accidentally hit the air-gapped modal
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(50);
|
||||
|
||||
// # Click the upgrade button to open the modal
|
||||
cy.get('#professional_action').should('exist').click();
|
||||
|
||||
// * Verify basic purchase elements are available
|
||||
verifyPurchaseModal();
|
||||
|
||||
// # Fill form with a known failing card
|
||||
fillForm({...defaultSuccessForm, card: failCardNumber}, getCurrentUsers());
|
||||
|
||||
// # Wait explicitly for parts of the purchase because they can take long.
|
||||
cy.intercept('POST', '**/api/v4/hosted_customer/customer').as('createCustomer');
|
||||
|
||||
cy.contains('Upgrade').should('be.enabled').click();
|
||||
|
||||
cy.wait('@createCustomer');
|
||||
|
||||
// # Verify failure screen presented
|
||||
cy.contains('Sorry, the payment verification failed');
|
||||
cy.contains('Try again');
|
||||
cy.contains('Contact Support');
|
||||
|
||||
// # Close purchase flow
|
||||
cy.get('#closeIcon').click();
|
||||
|
||||
// # Go to license page
|
||||
cy.visit('/admin_console/about/license');
|
||||
|
||||
// * Verify no license was applied
|
||||
cy.contains('Upgrade to the Professional Plan');
|
||||
cy.contains('Purchase');
|
||||
});
|
||||
|
||||
it('customer in region banned from purchase is not able to purchase and is told their transaction is under review.', () => {
|
||||
// this test must run last within this suite because it sets a value in the DB that prevents further purchase for 3 days.
|
||||
// For now, we do not have a programmatic way to reset this.
|
||||
// So if you are running locally you need to log into the DB and run
|
||||
// DELETE FROM systems where name = 'HostedPurchaseNeedsScreening';
|
||||
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/');
|
||||
cy.apiDeleteLicense();
|
||||
|
||||
cy.intercept('GET', '**/api/v4/hosted_customer/signup_available').as('airGappedCheck');
|
||||
cy.intercept('GET', '**/api/v4/cloud/products/selfhosted').as('products');
|
||||
|
||||
// # Open pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
cy.wait('@airGappedCheck');
|
||||
cy.wait('@products');
|
||||
|
||||
// The waits for these fetches is usually enough. Add a little wait
|
||||
// for all the selectors to be updated and rerenders to happen
|
||||
// so that we do not accidentally hit the air-gapped modal
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(50);
|
||||
|
||||
// # Click the upgrade button to open the modal
|
||||
cy.get('#professional_action').should('exist').click();
|
||||
|
||||
// * Verify basic purchase elements are available
|
||||
verifyPurchaseModal();
|
||||
|
||||
// # Fill form with a known screened region
|
||||
fillForm({...defaultSuccessForm, country: 'Iran, Islamic Republic of'}, getCurrentUsers());
|
||||
|
||||
// # Wait explicitly for parts of the purchase because they can take long.
|
||||
cy.intercept('POST', '**/api/v4/hosted_customer/customer').as('createCustomer');
|
||||
|
||||
cy.contains('Upgrade').should('be.enabled').click();
|
||||
|
||||
cy.wait('@createCustomer');
|
||||
|
||||
// * Verify screening in progress UI presented
|
||||
cy.contains('Your transaction is being reviewed');
|
||||
cy.contains('We will check things on our side and get back to you');
|
||||
|
||||
// # Close purchase flow
|
||||
cy.get('#closeIcon').click();
|
||||
|
||||
// # attempt to re-open purchase flow
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
cy.wait('@airGappedCheck');
|
||||
cy.wait('@products');
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(50);
|
||||
|
||||
// # Click the upgrade button to open the modal
|
||||
cy.get('#professional_action').should('exist').click();
|
||||
|
||||
// * Verify screening in progress UI presented
|
||||
cy.contains('Your transaction is being reviewed');
|
||||
cy.contains('We will check things on our side and get back to you');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,147 @@
|
||||
// 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 @license_removal
|
||||
|
||||
import * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
import {getAdminAccount} from '../../../../../support/env';
|
||||
|
||||
import {promoteToChannelOrTeamAdmin} from '../channel_moderation/helpers.js';
|
||||
|
||||
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 for E20 licenses', () => {
|
||||
cy.visit('/admin_console/about/license');
|
||||
cy.get('.admin-console__header').
|
||||
should('be.visible').
|
||||
and('have.text', 'Edition and License');
|
||||
|
||||
// Validate prompt to increase headcount in Enterprise licenses
|
||||
cy.get('.EnterpriseEditionRightPannel').
|
||||
should('be.visible').
|
||||
within(() => {
|
||||
cy.findByText('Need to increase your headcount?');
|
||||
cy.findByText('We’re here to work with you and your needs. Contact us today to get more seats on your plan.');
|
||||
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').click();
|
||||
|
||||
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('#channelHeaderDropdownIcon', {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},
|
||||
]);
|
||||
}
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
// 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;
|
||||
|
||||
before(() => {
|
||||
cy.apiRequireLicense();
|
||||
|
||||
cy.apiUpdateConfig({
|
||||
TeamSettings: {
|
||||
ExperimentalViewArchivedChannels: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.apiInitSetup({
|
||||
channelPrefix: {name: '000-archive', displayName: '000 Archive Test'},
|
||||
}).then(({channel}) => {
|
||||
testChannel = channel;
|
||||
|
||||
// # Archive the channel
|
||||
cy.apiDeleteChannel(testChannel.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.ArchiveButton', {timeout: TIMEOUTS.ONE_MIN}).findByText('Unarchive Channel').should('be.visible');
|
||||
|
||||
// * 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.ArchiveButton', {timeout: TIMEOUTS.ONE_MIN}).findAllByText('Unarchive Channel').click();
|
||||
|
||||
// * Verify the Archive Channel button is visible
|
||||
cy.get('button.ArchiveButton', {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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,120 @@
|
||||
// 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 @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.get('#searchUsers').clear().type(adminUsername).wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify sign-in method
|
||||
cy.findByTestId('userListRow').within(() => {
|
||||
cy.get('.more-modal__details').
|
||||
should('be.visible').
|
||||
and('contain.text', 'Sign-in Method: Email');
|
||||
});
|
||||
|
||||
// # Type saml user
|
||||
cy.get('#searchUsers').clear().type(samlUser.username).wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify sign-in method
|
||||
cy.findByTestId('userListRow').within(() => {
|
||||
cy.get('.more-modal__details').
|
||||
should('be.visible').
|
||||
and('contain.text', 'Sign-in Method: SAML');
|
||||
});
|
||||
|
||||
// # Type ldap user
|
||||
cy.get('#searchUsers').clear().type(ldapUser.username).wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify sign-in method
|
||||
cy.findByTestId('userListRow').within(() => {
|
||||
cy.get('.more-modal__details').
|
||||
should('be.visible').
|
||||
and('contain.text', 'Sign-in Method: LDAP');
|
||||
});
|
||||
|
||||
// # Type mfa user
|
||||
cy.get('#searchUsers').clear().type(mfaUser.username).wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Verify sign-in method
|
||||
cy.findByTestId('userListRow').within(() => {
|
||||
cy.get('.more-modal__details').
|
||||
should('be.visible').
|
||||
and('contain.text', 'MFA: Yes');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
@@ -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('textbox', {name: 'Search for people'}).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
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
// 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 {checkboxesTitleToIdMap} from './constants';
|
||||
|
||||
import {
|
||||
disablePermission,
|
||||
enablePermission,
|
||||
postChannelMentionsAndVerifySystemMessageExist,
|
||||
postChannelMentionsAndVerifySystemMessageNotExist,
|
||||
saveConfigForChannel,
|
||||
saveConfigForScheme,
|
||||
visitChannel,
|
||||
visitChannelConfigPage,
|
||||
} from './helpers';
|
||||
|
||||
describe('MM-23102 - Channel Moderation - Channel Mentions', () => {
|
||||
let regularUser;
|
||||
let guestUser;
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
|
||||
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('#confirmModalLabel').should('not.exist');
|
||||
|
||||
// * Type at channel and enter that no confirmation dialogue shows up
|
||||
cy.postMessage('@channel ');
|
||||
cy.get('#confirmModalLabel').should('not.exist');
|
||||
|
||||
// * Type at here and enter that no confirmation dialogue shows up
|
||||
cy.postMessage('@here ');
|
||||
cy.get('#confirmModalLabel').should('not.exist');
|
||||
});
|
||||
});
|
||||
@@ -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,
|
||||
];
|
||||
@@ -0,0 +1,109 @@
|
||||
// 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 {checkboxesTitleToIdMap} from './constants';
|
||||
|
||||
import {
|
||||
disablePermission,
|
||||
enablePermission,
|
||||
saveConfigForChannel,
|
||||
visitChannel,
|
||||
visitChannelConfigPage,
|
||||
} from './helpers';
|
||||
|
||||
describe('MM-23102 - Channel Moderation - Create Posts', () => {
|
||||
let regularUser;
|
||||
let guestUser;
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
|
||||
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_placeholder').should('have.text', '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_placeholder').should('have.text', `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_placeholder').should('have.text', '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_placeholder').should('have.text', `Write to ${testChannel.display_name}`);
|
||||
cy.findByTestId('post_textbox').should('not.be.disabled');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,304 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
import {getAdminAccount} from '../../../../../support/env';
|
||||
|
||||
import {checkBoxes} from './constants';
|
||||
|
||||
// # Visits the channel configuration for a channel with channelName
|
||||
export const visitChannelConfigPage = (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) => {
|
||||
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 = false, 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, channel, 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) => {
|
||||
function getSystemMessage(text) {
|
||||
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) => {
|
||||
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) => {
|
||||
function getSystemMessage(text) {
|
||||
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, 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, editOrDelete) => {
|
||||
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, 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,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
// # 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, id, 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, id, 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();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,320 @@
|
||||
// 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 {getRandomId} from '../../../../../utils';
|
||||
|
||||
import {checkboxesTitleToIdMap} from './constants';
|
||||
|
||||
import {
|
||||
deleteOrEditTeamScheme,
|
||||
demoteToChannelOrTeamMember,
|
||||
disablePermission,
|
||||
enablePermission,
|
||||
enableDisableAllChannelModeratedPermissionsViaAPI,
|
||||
goToPermissionsAndCreateTeamOverrideScheme,
|
||||
goToSystemScheme,
|
||||
postChannelMentionsAndVerifySystemMessageNotExist,
|
||||
promoteToChannelOrTeamAdmin,
|
||||
saveConfigForChannel,
|
||||
saveConfigForScheme,
|
||||
viewManageChannelMembersModal,
|
||||
visitChannel,
|
||||
visitChannelConfigPage,
|
||||
} from './helpers';
|
||||
|
||||
describe('MM-23102 - Channel Moderation - Higher Scoped Scheme', () => {
|
||||
let regularUser;
|
||||
let guestUser;
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
|
||||
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
|
||||
viewManageChannelMembersModal('View');
|
||||
|
||||
// * 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
|
||||
viewManageChannelMembersModal('View');
|
||||
|
||||
// * 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
|
||||
viewManageChannelMembersModal('View');
|
||||
|
||||
// * 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
|
||||
viewManageChannelMembersModal('View');
|
||||
|
||||
// * 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
|
||||
viewManageChannelMembersModal('Manage');
|
||||
|
||||
// * 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
|
||||
viewManageChannelMembersModal('Manage');
|
||||
|
||||
// * Add Members button does not exist
|
||||
cy.get('#showInviteModal').should('exist');
|
||||
|
||||
demoteToChannelOrTeamMember(regularUser.id, testTeam.id, 'teams');
|
||||
});
|
||||
});
|
||||
@@ -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.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @enterprise @system_console @channel_moderation
|
||||
|
||||
import * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
import {getRandomId} from '../../../../../utils';
|
||||
|
||||
import {checkboxesTitleToIdMap} from './constants';
|
||||
|
||||
import {
|
||||
deleteOrEditTeamScheme,
|
||||
disablePermission,
|
||||
enablePermission,
|
||||
goToPermissionsAndCreateTeamOverrideScheme,
|
||||
goToSystemScheme,
|
||||
saveConfigForChannel,
|
||||
saveConfigForScheme,
|
||||
viewManageChannelMembersRHS,
|
||||
visitChannel,
|
||||
visitChannelConfigPage,
|
||||
} from './helpers';
|
||||
|
||||
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;
|
||||
let guestUser;
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,227 @@
|
||||
// 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 * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
import {getRandomId} from '../../../../../utils';
|
||||
import {getAdminAccount} from '../../../../../support/env';
|
||||
|
||||
import {checkboxesTitleToIdMap} from './constants';
|
||||
|
||||
import {
|
||||
deleteOrEditTeamScheme,
|
||||
disablePermission,
|
||||
enablePermission,
|
||||
goToPermissionsAndCreateTeamOverrideScheme,
|
||||
goToSystemScheme,
|
||||
saveConfigForChannel,
|
||||
saveConfigForScheme,
|
||||
visitChannel,
|
||||
visitChannelConfigPage,
|
||||
} from './helpers';
|
||||
|
||||
describe('MM-23102 - Channel Moderation - Post Reactions', () => {
|
||||
let regularUser;
|
||||
let guestUser;
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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 @channel_moderation
|
||||
|
||||
import * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
|
||||
import {checkBoxes} from './constants';
|
||||
|
||||
import {
|
||||
disableAllChannelModeratedPermissions,
|
||||
enableAllChannelModeratedPermissions,
|
||||
saveConfigForChannel,
|
||||
} from './helpers';
|
||||
|
||||
describe('Channel Moderation', () => {
|
||||
let guestUser;
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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 Experimental Gossip Encryption
|
||||
cy.apiUpdateConfig({
|
||||
ClusterSettings: {
|
||||
Enable: null,
|
||||
EnableExperimentalGossipEncryption: null,
|
||||
},
|
||||
});
|
||||
|
||||
// # Visit high availability system console page
|
||||
cy.visit('/admin_console/environment/high_availability');
|
||||
});
|
||||
|
||||
it('SC25050 - Can change Experimental Gossip Encryption', () => {
|
||||
cy.findByTestId('EnableExperimentalGossipEncryption').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 Experimental 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 Experimental Gossip Encryption is set to false by default
|
||||
cy.get('#EnableExperimentalGossipEncryptionfalse').should('have.attr', 'checked');
|
||||
});
|
||||
|
||||
// # Enable Experimental Gossip Encryption
|
||||
cy.apiUpdateConfig({
|
||||
ClusterSettings: {
|
||||
Enable: true,
|
||||
EnableExperimentalGossipEncryption: true,
|
||||
},
|
||||
});
|
||||
cy.reload();
|
||||
|
||||
cy.findByTestId('EnableExperimentalGossipEncryption').scrollIntoView().should('be.visible').within(() => {
|
||||
// * Verify that Experimental Gossip Encryption is set to true
|
||||
cy.get('#EnableExperimentalGossipEncryptiontrue').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');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,144 @@
|
||||
// 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;
|
||||
});
|
||||
|
||||
// # 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');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,167 @@
|
||||
// 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 * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
|
||||
import {verifyExportedMessagesCount, gotoTeamAndPostImage} 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;
|
||||
});
|
||||
|
||||
// # 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(1)').should('have.text', 'Status');
|
||||
cy.get('th:eq(2)').should('have.text', 'Files');
|
||||
cy.get('th:eq(3)').should('have.text', 'Finish Time');
|
||||
cy.get('th:eq(4)').should('have.text', 'Run Time');
|
||||
cy.get('th:eq(5)').should('have.text', 'Details');
|
||||
});
|
||||
|
||||
// * Verify first row (last run job) data
|
||||
cy.get('@firstRow').within(() => {
|
||||
cy.get('td:eq(1)').should('have.text', 'Success');
|
||||
cy.get('td:eq(2)').should('have.text', 'Download');
|
||||
cy.get('td:eq(4)').contains('seconds');
|
||||
cy.get('td:eq(5)').should('have.text', '1 messages 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.disabled');
|
||||
});
|
||||
|
||||
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(1)').should('have.text', 'Canceled');
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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();
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
// 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-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();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
// 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.shellFind(targetFolder, /actiance_export.xml/).
|
||||
then((files) => {
|
||||
cy.readFile(files[files.length - 1]).
|
||||
should('exist').
|
||||
and(type, match);
|
||||
});
|
||||
}
|
||||
|
||||
export function verifyExportedMessagesCount(expectedNumber) {
|
||||
// * Verifying number of exported messages
|
||||
cy.get('@firstRow').find('td:eq(5)').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).type('{enter}').wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * 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(1)', {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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// 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 * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
|
||||
import {gotoTeamAndPostImage} from './helpers';
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
// # 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.env();
|
||||
|
||||
// # 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,567 @@
|
||||
// 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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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 its role wasn't updated
|
||||
cy.apiGetGroupTeam(groupID, testTeam.id).then(({body}) => {
|
||||
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 its role wasn't updated
|
||||
cy.apiGetGroupChannel(groupID, testChannel.id).then(({body}) => {
|
||||
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');
|
||||
}
|
||||
@@ -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('System Roles', {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('textbox', {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;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user