Этот коммит содержится в:
Mario Vitale
2023-03-27 16:28:42 +02:00
родитель da7a6825ce
Коммит ba6b97fb62
1142 изменённых файлов: 44 добавлений и 44 удалений

Просмотреть файл

@@ -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 users 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 users 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 users 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('Were 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);
});
});

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше