Move /e2e -> /e2e-tests
Этот коммит содержится в:
59
e2e-tests/cypress/tests/support/ui/account_settings_modal.d.ts
поставляемый
Обычный файл
59
e2e-tests/cypress/tests/support/ui/account_settings_modal.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiOpenProfileModal`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Open the account settings modal
|
||||
* @param {string} section - such as `'General'`, `'Security'`, `'Notifications'`, `'Display'`, `'Sidebar'` and `'Advanced'`
|
||||
* @return the "#accountSettingsModal"
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenProfileModal().within(() => {
|
||||
* // Do something here
|
||||
* });
|
||||
*/
|
||||
uiOpenProfileModal(section?: string): Chainable<JQuery<HTMLElement>>;
|
||||
|
||||
/**
|
||||
* Close the account settings modal given that the modal itself is opened.
|
||||
*
|
||||
* @example
|
||||
* cy.uiCloseAccountSettingsModal();
|
||||
*/
|
||||
uiCloseAccountSettingsModal(): Chainable;
|
||||
|
||||
/**
|
||||
* Navigate to account settings and verify the user's first, last name
|
||||
* @param {String} firstname - expected user firstname
|
||||
* @param {String} lastname - expected user lastname
|
||||
*/
|
||||
verifyAccountNameSettings(firstname: string, lastname: string): Chainable;
|
||||
|
||||
/**
|
||||
* Navigate to account display settings and change collapsed reply threads setting
|
||||
* @param {String} setting - ON or OFF
|
||||
*/
|
||||
uiChangeCRTDisplaySetting(setting: string): Chainable;
|
||||
|
||||
/**
|
||||
* Navigate to account display settings and change message display setting
|
||||
* @param {String} setting - COMPACT or STANDARD
|
||||
*/
|
||||
uiChangeMessageDisplaySetting(setting: string): Chainable;
|
||||
}
|
||||
}
|
||||
60
e2e-tests/cypress/tests/support/ui/account_settings_modal.js
Обычный файл
60
e2e-tests/cypress/tests/support/ui/account_settings_modal.js
Обычный файл
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiOpenProfileModal', (section = '') => {
|
||||
// # Open profile settings modal
|
||||
cy.uiOpenUserMenu('Profile');
|
||||
|
||||
const profileSettingsModal = () => cy.findByRole('dialog', {name: 'Profile'}).should('be.visible');
|
||||
|
||||
if (!section) {
|
||||
return profileSettingsModal();
|
||||
}
|
||||
|
||||
// # Click on a particular section
|
||||
cy.findByRoleExtended('tab', {name: section}).should('be.visible').click();
|
||||
|
||||
return profileSettingsModal();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('verifyAccountNameSettings', (firstname, lastname) => {
|
||||
// # Go to Profile
|
||||
cy.uiOpenProfileModal();
|
||||
|
||||
// * Check name value
|
||||
cy.get('#nameDesc').should('have.text', `${firstname} ${lastname}`);
|
||||
cy.uiClose();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiChangeGenericDisplaySetting', (setting, option) => {
|
||||
cy.uiOpenSettingsModal('Display');
|
||||
cy.get(setting).scrollIntoView();
|
||||
cy.get(setting).click();
|
||||
cy.get('.section-max').scrollIntoView();
|
||||
|
||||
cy.get(option).check().should('be.checked');
|
||||
|
||||
cy.uiSaveAndClose();
|
||||
});
|
||||
|
||||
/*
|
||||
* Change the message display setting
|
||||
* @param {String} setting - as 'STANDARD' or 'COMPACT'
|
||||
*/
|
||||
Cypress.Commands.add('uiChangeMessageDisplaySetting', (setting = 'STANDARD') => {
|
||||
const SETTINGS = {STANDARD: '#message_displayFormatA', COMPACT: '#message_displayFormatB'};
|
||||
cy.uiChangeGenericDisplaySetting('#message_displayTitle', SETTINGS[setting]);
|
||||
});
|
||||
|
||||
/*
|
||||
* Change the collapsed reply threads display setting
|
||||
* @param {String} setting - as 'OFF' or 'ON'
|
||||
*/
|
||||
Cypress.Commands.add('uiChangeCRTDisplaySetting', (setting = 'OFF') => {
|
||||
const SETTINGS = {
|
||||
ON: '#collapsed_reply_threadsFormatA',
|
||||
OFF: '#collapsed_reply_threadsFormatB',
|
||||
};
|
||||
|
||||
cy.uiChangeGenericDisplaySetting('#collapsed_reply_threadsTitle', SETTINGS[setting]);
|
||||
});
|
||||
28
e2e-tests/cypress/tests/support/ui/announcement_bar.d.ts
поставляемый
Обычный файл
28
e2e-tests/cypress/tests/support/ui/announcement_bar.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiCloseAnnouncementBar`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Close the announcement bar if shown in the UI
|
||||
*
|
||||
* @example
|
||||
* cy.uiCloseAnnouncementBar();
|
||||
*/
|
||||
uiCloseAnnouncementBar(): Chainable;
|
||||
}
|
||||
}
|
||||
11
e2e-tests/cypress/tests/support/ui/announcement_bar.js
Обычный файл
11
e2e-tests/cypress/tests/support/ui/announcement_bar.js
Обычный файл
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiCloseAnnouncementBar', () => {
|
||||
cy.document().then((doc) => {
|
||||
const announcementBar = doc.getElementsByClassName('announcement-bar')[0];
|
||||
if (announcementBar) {
|
||||
cy.get('.announcement-bar__close').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
56
e2e-tests/cypress/tests/support/ui/boards.d.ts
поставляемый
Обычный файл
56
e2e-tests/cypress/tests/support/ui/boards.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiCreateEmptyBoard`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Create a board on a given menu item.
|
||||
*
|
||||
* @param {string} item - one of the template menu options, ex. 'Empty board'
|
||||
*/
|
||||
uiCreateBoard(item: string): Chainable;
|
||||
|
||||
/**
|
||||
* Create an empty board.
|
||||
* @example
|
||||
* cy.uiCreateEmptyBoard();
|
||||
*/
|
||||
uiCreateEmptyBoard(): Chainable;
|
||||
|
||||
/**
|
||||
* Create a board with the given title
|
||||
*
|
||||
* @param {string} title - title of the new board
|
||||
*/
|
||||
uiCreateNewBoard: (title?: string) => Chainable;
|
||||
|
||||
/**
|
||||
* Create a new group with the given name
|
||||
*
|
||||
* @param {string} name - name of the new group
|
||||
*/
|
||||
uiAddNewGroup: (name?: string) => Chainable;
|
||||
|
||||
/**
|
||||
* Create a card with the given title
|
||||
*
|
||||
* @param {string} title - title of the new card
|
||||
* @param {string} columnIndex - the column index to create the card
|
||||
*/
|
||||
uiAddNewCard: (title?: string, columnIndex?: number) => Chainable;
|
||||
}
|
||||
}
|
||||
66
e2e-tests/cypress/tests/support/ui/boards.js
Обычный файл
66
e2e-tests/cypress/tests/support/ui/boards.js
Обычный файл
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import timeouts from '../../fixtures/timeouts';
|
||||
|
||||
/* eslint-disable cypress/no-unnecessary-waiting */
|
||||
Cypress.Commands.add('uiCreateBoard', (item) => {
|
||||
cy.log(`Create new board: ${item}`);
|
||||
|
||||
cy.uiAddBoard('Create new board');
|
||||
cy.contains(item).click();
|
||||
cy.contains('Use this template').click({force: true}).wait(timeouts.ONE_SEC);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiCreateEmptyBoard', () => {
|
||||
cy.log('Create new empty board');
|
||||
|
||||
cy.contains('Create an empty board').click({force: true}).wait(timeouts.ONE_SEC);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiAddBoard', (item) => {
|
||||
cy.get('.add-board-icon').should('be.visible').click();
|
||||
cy.get('.menu-contents').should('be.visible');
|
||||
|
||||
if (item) {
|
||||
cy.findByRole('button', {name: item}).click();
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiCreateNewBoard', (title) => {
|
||||
cy.log('**Create new empty board**');
|
||||
cy.uiCreateEmptyBoard();
|
||||
|
||||
cy.findByPlaceholderText('Untitled board').should('be.visible');
|
||||
cy.wait(timeouts.QUARTER_SEC);
|
||||
if (title) {
|
||||
cy.log('**Rename board**');
|
||||
cy.findByPlaceholderText('Untitled board').type(`${title}{enter}`);
|
||||
cy.findByRole('textbox', {name: title}).should('exist');
|
||||
}
|
||||
cy.wait(timeouts.HALF_SEC);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiAddNewGroup', (name) => {
|
||||
cy.log('**Add a new group**');
|
||||
cy.findByRole('button', {name: '+ Add a group'}).click();
|
||||
cy.findByRole('textbox', {name: 'New group'}).should('exist');
|
||||
|
||||
if (name) {
|
||||
cy.log('**Rename group**');
|
||||
cy.findByRole('textbox', {name: 'New group'}).type(`{selectall}${name}{enter}`);
|
||||
cy.findByRole('textbox', {name}).should('exist');
|
||||
}
|
||||
cy.wait(timeouts.HALF_SEC);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiAddNewCard', (title, columnIndex) => {
|
||||
cy.log('**Add a new card**');
|
||||
cy.findByRole('button', {name: '+ New'}).eq(columnIndex || 0).click();
|
||||
cy.findByRole('dialog').should('exist');
|
||||
|
||||
if (title) {
|
||||
cy.log('**Change card title**');
|
||||
cy.findByPlaceholderText('Untitled').type(title);
|
||||
}
|
||||
});
|
||||
67
e2e-tests/cypress/tests/support/ui/channel.d.ts
поставляемый
Обычный файл
67
e2e-tests/cypress/tests/support/ui/channel.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiCreateChannel`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Create a new channel in the current team.
|
||||
* @param {string} options.prefix - Prefix for the name of the channel, it will be added a random string ot it.
|
||||
* @param {boolean} options.isPrivate - is the channel private or public (default)?
|
||||
* @param {string} options.purpose - Channel's purpose
|
||||
* @param {string} options.header - Channel's header
|
||||
* @param {boolean} options.isNewSidebar) - the new sidebar has a different ui flow, set this setting to true to use that. Defaults to false.
|
||||
*
|
||||
* @example
|
||||
* cy.uiCreateChannel({prefix: 'private-channel-', isPrivate: true, purpose: 'my private channel', header: 'my private header', isNewSidebar: false});
|
||||
*/
|
||||
uiCreateChannel(options: Record<string, unknown>): Chainable;
|
||||
|
||||
/**
|
||||
* Add users to the current channel.
|
||||
* @param {string[]} usernameList - list of userids to add to the channel
|
||||
*
|
||||
* @example
|
||||
* cy.uiAddUsersToCurrentChannel(['user1', 'user2']);
|
||||
*/
|
||||
uiAddUsersToCurrentChannel(usernameList: string[]);
|
||||
|
||||
/**
|
||||
* Archive the current channel.
|
||||
*
|
||||
* @example
|
||||
* cy.uiArchiveChannel();
|
||||
*/
|
||||
uiArchiveChannel();
|
||||
|
||||
/**
|
||||
* Unarchive the current channel.
|
||||
*
|
||||
* @example
|
||||
* cy.uiUnarchiveChannel();
|
||||
*/
|
||||
uiUnarchiveChannel();
|
||||
|
||||
/**
|
||||
* Leave the current channel.
|
||||
* @param {boolean} isPrivate - is the channel private or public (default)?
|
||||
*
|
||||
* @example
|
||||
* cy.uiLeaveChannel(true);
|
||||
*/
|
||||
uiLeaveChannel(isPrivate?: boolean);
|
||||
}
|
||||
}
|
||||
93
e2e-tests/cypress/tests/support/ui/channel.js
Обычный файл
93
e2e-tests/cypress/tests/support/ui/channel.js
Обычный файл
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {getRandomId} from '../../utils';
|
||||
import * as TIMEOUTS from '../../fixtures/timeouts';
|
||||
|
||||
Cypress.Commands.add('uiCreateChannel', ({
|
||||
prefix = 'channel-',
|
||||
isPrivate = false,
|
||||
purpose = '',
|
||||
name = '',
|
||||
createBoard = false,
|
||||
}) => {
|
||||
cy.uiBrowseOrCreateChannel('Create New Channel').click();
|
||||
|
||||
cy.get('#new-channel-modal').should('be.visible');
|
||||
if (isPrivate) {
|
||||
cy.get('#public-private-selector-button-P').click().wait(TIMEOUTS.HALF_SEC);
|
||||
} else {
|
||||
cy.get('#public-private-selector-button-O').click().wait(TIMEOUTS.HALF_SEC);
|
||||
}
|
||||
const channelName = name || `${prefix}${getRandomId()}`;
|
||||
cy.get('#input_new-channel-modal-name').should('be.visible').clear().type(channelName);
|
||||
if (purpose) {
|
||||
cy.get('#new-channel-modal-purpose').clear().type(purpose);
|
||||
}
|
||||
|
||||
if (createBoard) {
|
||||
cy.get('#add-board-to-channel').should('be.visible');
|
||||
cy.findByTestId('add-board-to-channel-check').then((el) => {
|
||||
if (el && !el.hasClass('checked')) {
|
||||
el.click();
|
||||
cy.get('#input_select-board-template').should('be.visible').click();
|
||||
cy.get('.SelectTemplateMenu .MenuItem:contains(Roadmap) button').should('be.visible').click();
|
||||
}
|
||||
});
|
||||
}
|
||||
cy.findByText('Create channel').click();
|
||||
cy.get('#new-channel-modal').should('not.exist');
|
||||
cy.get('#channelIntro').should('be.visible');
|
||||
return cy.wrap({name: channelName});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiAddUsersToCurrentChannel', (usernameList) => {
|
||||
if (usernameList.length) {
|
||||
cy.get('#channelHeaderDropdownIcon').click();
|
||||
cy.get('#channelAddMembers').click();
|
||||
cy.get('#addUsersToChannelModal').should('be.visible');
|
||||
usernameList.forEach((username) => {
|
||||
cy.get('#selectItems input').typeWithForce(`@${username}{enter}`);
|
||||
});
|
||||
cy.get('#saveItems').click();
|
||||
cy.get('#addUsersToChannelModal').should('not.exist');
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiArchiveChannel', () => {
|
||||
cy.get('#channelHeaderDropdownIcon').click();
|
||||
cy.get('#channelArchiveChannel').click();
|
||||
return cy.get('#deleteChannelModalDeleteButton').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiUnarchiveChannel', () => {
|
||||
cy.get('#channelHeaderDropdownIcon').should('be.visible').click();
|
||||
cy.get('#channelUnarchiveChannel').should('be.visible').click();
|
||||
return cy.get('#unarchiveChannelModalDeleteButton').should('be.visible').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiLeaveChannel', (isPrivate = false) => {
|
||||
cy.get('#channelHeaderDropdownIcon').click();
|
||||
|
||||
if (isPrivate) {
|
||||
cy.get('#channelLeaveChannel').click();
|
||||
return cy.get('#confirmModalButton').click();
|
||||
}
|
||||
|
||||
return cy.get('#channelLeaveChannel').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('goToDm', (username) => {
|
||||
cy.uiAddDirectMessage().click({force: true});
|
||||
|
||||
// # Start typing part of a username that matches previously created users
|
||||
cy.get('#selectItems input').typeWithForce(username);
|
||||
cy.findByRole('dialog', {name: 'Direct Messages'}).should('be.visible').wait(TIMEOUTS.ONE_SEC);
|
||||
cy.findByRole('textbox', {name: 'Search for people'}).
|
||||
typeWithForce(username).
|
||||
wait(TIMEOUTS.ONE_SEC).
|
||||
typeWithForce('{enter}');
|
||||
|
||||
// # Save the selected item
|
||||
return cy.get('#saveItems').click().wait(TIMEOUTS.HALF_SEC);
|
||||
});
|
||||
86
e2e-tests/cypress/tests/support/ui/channel_header.d.ts
поставляемый
Обычный файл
86
e2e-tests/cypress/tests/support/ui/channel_header.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiGetChannelFavoriteButton`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Get channel header button.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetChannelHeaderButton().click();
|
||||
*/
|
||||
uiGetChannelHeaderButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get favorite button from channel header.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetChannelFavoriteButton().click();
|
||||
*/
|
||||
uiGetChannelFavoriteButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get mute button from channel header.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetMuteButton().click();
|
||||
*/
|
||||
uiGetMuteButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get member button from channel header.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetChannelMemberButton().click();
|
||||
*/
|
||||
uiGetChannelMemberButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get pin button from channel header.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetChannelPinButton().click();
|
||||
*/
|
||||
uiGetChannelPinButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get files button from channel header.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetChannelFileButton().click();
|
||||
*/
|
||||
uiGetChannelFileButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get channel menu
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetChannelMenu();
|
||||
*/
|
||||
uiGetChannelMenu(): Chainable;
|
||||
|
||||
/**
|
||||
* Open channel menu
|
||||
* @param {string} [menu] - such as `'View Info'`, `'Notification Preferences'`, `'Team Settings'` and other items in the main menu.
|
||||
* @return the channel menu
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenChannelMenu();
|
||||
*/
|
||||
uiOpenChannelMenu(menu?: string): Chainable;
|
||||
}
|
||||
}
|
||||
57
e2e-tests/cypress/tests/support/ui/channel_header.js
Обычный файл
57
e2e-tests/cypress/tests/support/ui/channel_header.js
Обычный файл
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// Buttons
|
||||
|
||||
Cypress.Commands.add('uiGetChannelHeaderButton', () => {
|
||||
return cy.get('#channelHeaderDropdownButton').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetChannelFavoriteButton', () => {
|
||||
return cy.get('#toggleFavorite').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetMuteButton', () => {
|
||||
return cy.get('#toggleMute').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetChannelMemberButton', () => {
|
||||
return cy.get('#member_rhs').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetChannelPinButton', () => {
|
||||
return cy.get('#channelHeaderPinButton').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetChannelFileButton', () => {
|
||||
return cy.get('#channelHeaderFilesButton').should('be.visible');
|
||||
});
|
||||
|
||||
// Menus
|
||||
|
||||
Cypress.Commands.add('uiGetChannelMenu', (options = {exist: true}) => {
|
||||
if (options.exist) {
|
||||
return cy.get('#channelHeaderDropdownMenu').
|
||||
find('.dropdown-menu').
|
||||
should('be.visible');
|
||||
}
|
||||
|
||||
return cy.get('#channelHeaderDropdownMenu').should('not.exist');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenChannelMenu', (item = '') => {
|
||||
// # Click on channel header button
|
||||
cy.uiGetChannelHeaderButton().click();
|
||||
|
||||
if (!item) {
|
||||
// # Return the menu if no item is passed
|
||||
return cy.uiGetChannelMenu();
|
||||
}
|
||||
|
||||
// # Click on a particular item
|
||||
return cy.uiGetChannelMenu().
|
||||
findByText(item).
|
||||
scrollIntoView().
|
||||
should('be.visible').
|
||||
click();
|
||||
});
|
||||
51
e2e-tests/cypress/tests/support/ui/channel_sidebar.js
Обычный файл
51
e2e-tests/cypress/tests/support/ui/channel_sidebar.js
Обычный файл
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {getRandomId} from '../../utils';
|
||||
|
||||
Cypress.Commands.add('uiCreateSidebarCategory', (categoryName = `category-${getRandomId()}`) => {
|
||||
// # Click the New Category/Channel Dropdown button
|
||||
cy.uiGetLHSAddChannelButton().click();
|
||||
|
||||
// # Click the Create New Category dropdown item
|
||||
cy.get('.AddChannelDropdown').should('be.visible').contains('.MenuItem', 'Create New Category').click();
|
||||
|
||||
cy.findByRole('dialog', {name: 'Rename Category'}).should('be.visible').within(() => {
|
||||
// # Fill in the category name and click 'Create'
|
||||
cy.findByRole('textbox').should('be.visible').typeWithForce(categoryName).
|
||||
invoke('val').should('equal', categoryName);
|
||||
cy.findByRole('button', {name: 'Create'}).should('be.enabled').click();
|
||||
});
|
||||
|
||||
// * Wait for the category to appear in the sidebar
|
||||
cy.contains('.SidebarChannelGroup', categoryName, {matchCase: false});
|
||||
|
||||
return cy.wrap({displayName: categoryName});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiMoveChannelToCategory', (channelName, categoryName, newCategory = false, isChannelId = false) => {
|
||||
// # Open the channel menu, select Move to
|
||||
cy.uiGetChannelSidebarMenu(channelName, isChannelId).within(() => {
|
||||
cy.findByText('Move to...').should('be.visible').trigger('mouseover');
|
||||
});
|
||||
|
||||
// # Select the move to category
|
||||
cy.findAllByRole('menu', {name: 'Move to submenu'}).should('be.visible').within(() => {
|
||||
if (newCategory) {
|
||||
cy.findByText('New Category').should('be.visible').click({force: true});
|
||||
} else {
|
||||
cy.findByText(categoryName).should('be.visible').click({force: true});
|
||||
}
|
||||
});
|
||||
|
||||
if (newCategory) {
|
||||
cy.findByRole('dialog', {name: 'Rename Category'}).should('be.visible').within(() => {
|
||||
// # Fill in the category name and click 'Create'
|
||||
cy.findByRole('textbox').should('be.visible').typeWithForce(categoryName).
|
||||
invoke('val').should('equal', categoryName);
|
||||
cy.findByRole('button', {name: 'Create'}).should('be.enabled').click();
|
||||
});
|
||||
}
|
||||
|
||||
return cy.wrap({displayName: categoryName});
|
||||
});
|
||||
27
e2e-tests/cypress/tests/support/ui/cloud_billing.d.ts
поставляемый
Обычный файл
27
e2e-tests/cypress/tests/support/ui/cloud_billing.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Iframe element in Stripe
|
||||
*
|
||||
* @example
|
||||
* cy.getIframeBody();
|
||||
*/
|
||||
uiGetPaymentCardInput(): Chainable;
|
||||
}
|
||||
}
|
||||
9
e2e-tests/cypress/tests/support/ui/cloud_billing.js
Обычный файл
9
e2e-tests/cypress/tests/support/ui/cloud_billing.js
Обычный файл
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiGetPaymentCardInput', () => {
|
||||
return cy.
|
||||
get('.__PrivateStripeElement > iframe').
|
||||
its('0.contentDocument.body').should('not.be.empty').
|
||||
then(cy.wrap);
|
||||
});
|
||||
114
e2e-tests/cypress/tests/support/ui/common.d.ts
поставляемый
Обычный файл
114
e2e-tests/cypress/tests/support/ui/common.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiSave`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Click 'Save' button
|
||||
*
|
||||
* @example
|
||||
* cy.uiSave();
|
||||
*/
|
||||
uiSave(): Chainable;
|
||||
|
||||
/**
|
||||
* Click 'Cancel' button
|
||||
*
|
||||
* @example
|
||||
* cy.uiCancel();
|
||||
*/
|
||||
uiCancel(): Chainable;
|
||||
|
||||
/**
|
||||
* Click 'Close' button
|
||||
*
|
||||
* @example
|
||||
* cy.uiClose();
|
||||
*/
|
||||
uiClose(): Chainable;
|
||||
|
||||
/**
|
||||
* Click Save then Close buttons
|
||||
*
|
||||
* @example
|
||||
* cy.uiSaveAndClose();
|
||||
*/
|
||||
uiSaveAndClose(): Chainable;
|
||||
|
||||
/**
|
||||
* Get a button by its text using "cy.findByRole"
|
||||
*
|
||||
* @param {String} label - Button text
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetButton('Save');
|
||||
*/
|
||||
uiGetButton(label: string): Chainable;
|
||||
|
||||
/**
|
||||
* Get save button
|
||||
*
|
||||
* @example
|
||||
* cy.uiSaveButton();
|
||||
*/
|
||||
uiSaveButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get cancel button
|
||||
*
|
||||
* @example
|
||||
* cy.uiCancelButton();
|
||||
*/
|
||||
uiCancelButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get close button
|
||||
*
|
||||
* @example
|
||||
* cy.uiCloseButton();
|
||||
*/
|
||||
uiCloseButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get a radio button by its text using "cy.findByRole"
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetRadioButton('Custom Theme');
|
||||
*/
|
||||
uiGetRadioButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get a heading by its text using "cy.findByRole"
|
||||
*
|
||||
* @param {string} headingText - Heading text
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetHeading('General Settings');
|
||||
*/
|
||||
uiGetHeading(headingText: string): Chainable;
|
||||
|
||||
/**
|
||||
* Get a textbox by its text using "cy.findByRole"
|
||||
*
|
||||
* @param {string} text - Textbox label
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetTextbox('Nickname');
|
||||
*/
|
||||
uiGetTextbox(text: string): Chainable;
|
||||
}
|
||||
}
|
||||
55
e2e-tests/cypress/tests/support/ui/common.js
Обычный файл
55
e2e-tests/cypress/tests/support/ui/common.js
Обычный файл
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiSave', () => {
|
||||
return cy.findByRole('button', {name: 'Save'}).scrollIntoView().click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiCancel', () => {
|
||||
return cy.findByRole('button', {name: 'Cancel'}).click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiClose', () => {
|
||||
return cy.findAllByRole('button', {name: 'Close'}).eq(0).click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiSaveAndClose', () => {
|
||||
cy.uiSave();
|
||||
cy.uiClose();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetButton', (name) => {
|
||||
return cy.findByRole('button', {name});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiSaveButton', () => {
|
||||
return cy.uiGetButton('Save');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiCancelButton', () => {
|
||||
return cy.uiGetButton('Cancel');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiCloseButton', () => {
|
||||
return cy.uiGetButton('Close');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetRadioButton', (name) => {
|
||||
return cy.findByRole('radio', {name}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetHeading', (name) => {
|
||||
return cy.findByRole('heading', {name}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetTextbox', (name) => {
|
||||
return cy.findByRole('textbox', {name}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiCloseOnboardingTaskList', () => {
|
||||
cy.get('[data-cy=onboarding-task-list-action-button]').then(($btn) => {
|
||||
if ($btn.find('i.icon-close').length) {
|
||||
$btn.trigger('click');
|
||||
}
|
||||
});
|
||||
});
|
||||
39
e2e-tests/cypress/tests/support/ui/compliance_export.d.ts
поставляемый
Обычный файл
39
e2e-tests/cypress/tests/support/ui/compliance_export.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Select compliance export format
|
||||
* @param {string} exportFormat - compliance export format
|
||||
*
|
||||
* @example
|
||||
* const EXPORTFORMAT = "Actiance XML";
|
||||
* cy.uiEnableComplianceExport(Compliance Export Format);
|
||||
*/
|
||||
uiEnableComplianceExport(exportFormat: string): Chainable;
|
||||
|
||||
/**
|
||||
* Go to Compliance Page
|
||||
*/
|
||||
uiGoToCompliancePage(): Chainable;
|
||||
|
||||
/**
|
||||
* Click Run Export Compliance and wait for Success status
|
||||
*/
|
||||
uiExportCompliance(): Chainable;
|
||||
}
|
||||
}
|
||||
48
e2e-tests/cypress/tests/support/ui/compliance_export.js
Обычный файл
48
e2e-tests/cypress/tests/support/ui/compliance_export.js
Обычный файл
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../fixtures/timeouts';
|
||||
|
||||
Cypress.Commands.add('uiEnableComplianceExport', (exportFormat = 'csv') => {
|
||||
// # Enable compliance export
|
||||
cy.findByRole('radio', {name: /false/i}).click();
|
||||
cy.findByRole('radio', {name: /true/i}).click();
|
||||
|
||||
// # Change export format
|
||||
cy.findByRole('combobox', {name: /export format:/i}).select(exportFormat);
|
||||
|
||||
// # Save settings
|
||||
cy.uiSaveConfig({confirm: true});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGoToCompliancePage', () => {
|
||||
cy.visit('/admin_console/compliance/export');
|
||||
cy.get('.admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Compliance Export');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiExportCompliance', () => {
|
||||
// # Click the export job button
|
||||
cy.findByRole('button', {name: /run compliance export job now/i}).click();
|
||||
|
||||
// # Small wait to ensure new row is add
|
||||
cy.wait(TIMEOUTS.THREE_SEC);
|
||||
|
||||
// # Get the first row
|
||||
cy.get('.job-table__table').find('tbody > tr').eq(0).as('firstRow');
|
||||
|
||||
// # Get the first table header
|
||||
cy.get('.job-table__table').find('thead > tr').as('firstheader');
|
||||
|
||||
// # Wait until export is finished
|
||||
cy.waitUntil(() => {
|
||||
return cy.get('@firstRow').find('td:eq(1)').then((el) => {
|
||||
return el[0].innerText.trim() === 'Success';
|
||||
});
|
||||
},
|
||||
{
|
||||
timeout: TIMEOUTS.FIVE_MIN,
|
||||
interval: TIMEOUTS.ONE_SEC,
|
||||
errorMsg: 'Compliance export did not finish in time',
|
||||
});
|
||||
});
|
||||
|
||||
86
e2e-tests/cypress/tests/support/ui/data_retention.d.ts
поставляемый
Обычный файл
86
e2e-tests/cypress/tests/support/ui/data_retention.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Go to Data Retention page
|
||||
*/
|
||||
uiGoToDataRetentionPage(): Chainable;
|
||||
|
||||
/**
|
||||
* Click create policy button
|
||||
*/
|
||||
uiClickCreatePolicy(): Chainable;
|
||||
|
||||
/**
|
||||
* Fill out custom policy form fields
|
||||
* @param {string} name - policy name
|
||||
* @param {string} durationDropdown - duration dropdown value (days, years, forever)
|
||||
* @param {string?} durationText - duration text
|
||||
*/
|
||||
uiFillOutCustomPolicyFields(name: string, durationDropdown: string, durationText?: string): Chainable;
|
||||
|
||||
/**
|
||||
* Search and add teams to custom policy
|
||||
* @param {string[]} teamNames - array of team names
|
||||
*/
|
||||
uiAddTeamsToCustomPolicy(teamNames: string[]): Chainable;
|
||||
|
||||
/**
|
||||
* Search and add channels to custom policy
|
||||
* @param {string[]} channelNames - array of channel names
|
||||
*/
|
||||
uiAddChannelsToCustomPolicy(channelNames: string[]): Chainable;
|
||||
|
||||
/**
|
||||
* Add teams to a custom policy
|
||||
* @param {number} numberOfTeams - number of teams to add to the policy
|
||||
*/
|
||||
uiAddRandomTeamToCustomPolicy(numberOfTeams?: number): Chainable;
|
||||
|
||||
/**
|
||||
* Add channels to a custom policy
|
||||
* @param {number} numberOfTeams - number of teams to add to the policy
|
||||
*/
|
||||
uiAddRandomChannelToCustomPolicy(numberOfChannels?: number): Chainable;
|
||||
|
||||
/**
|
||||
* Verify custom policy UI information
|
||||
* @param {string} policyId - Custom Policy ID
|
||||
* @param {string} description - The name of the policy
|
||||
* @param {string} duration - How long messages last in the policy
|
||||
* @param {string} appliedTo - Teams and channels the policy apples to
|
||||
*/
|
||||
uiVerifyCustomPolicyRow(policyId: string, description: string, duration: string, appliedTo: string): Chainable;
|
||||
|
||||
/**
|
||||
* Click edit custom policy
|
||||
* @param {string} policyId - Custom Policy ID
|
||||
*/
|
||||
uiClickEditCustomPolicyRow(policyId: string): Chainable;
|
||||
|
||||
/**
|
||||
* Verify custom create policy response
|
||||
* @param body - Response body
|
||||
* @param {number} teamCount - Number of teams the policy applies to
|
||||
* @param {number} channelCount - Number of channels the policy applies to
|
||||
* @param {number} duration - How long messages last in the policy
|
||||
* @param {string} displayName - The name of the policy
|
||||
*/
|
||||
uiVerifyPolicyResponse(body, teamCount: number, channelCount: number, duration: number, displayName: string): Chainable;
|
||||
}
|
||||
}
|
||||
105
e2e-tests/cypress/tests/support/ui/data_retention.js
Обычный файл
105
e2e-tests/cypress/tests/support/ui/data_retention.js
Обычный файл
@@ -0,0 +1,105 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../fixtures/timeouts';
|
||||
|
||||
Cypress.Commands.add('uiGoToDataRetentionPage', () => {
|
||||
cy.visit('/admin_console/compliance/data_retention_settings');
|
||||
cy.get('.DataRetentionSettings .admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Data Retention Policies');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiClickCreatePolicy', () => {
|
||||
cy.uiGetButton('Add policy').click();
|
||||
cy.get('.DataRetentionSettings .admin-console__header', {timeout: TIMEOUTS.TWO_MIN}).should('be.visible').invoke('text').should('include', 'Custom Retention Policy');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiFillOutCustomPolicyFields', (name, durationDropdown, durationText = '') => {
|
||||
// # Type policy name
|
||||
cy.uiGetTextbox('Policy name').clear().type(name);
|
||||
|
||||
// # Add message retention values
|
||||
cy.get('.CustomPolicy__fields #DropdownInput_message_retention').should('be.visible').click();
|
||||
cy.get(`.message_retention__menu .message_retention__option span.option_${durationDropdown}`).should('be.visible').click();
|
||||
if (durationText) {
|
||||
cy.get('.CustomPolicy__fields input#message_retention_input').clear().type(durationText);
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiAddTeamsToCustomPolicy', (teamNames) => {
|
||||
cy.uiGetButton('Add teams').click();
|
||||
teamNames.forEach((teamName) => {
|
||||
cy.findByRole('textbox', {name: 'Search and add teams'}).typeWithForce(teamName);
|
||||
cy.get('.team-info-block').then((el) => {
|
||||
el.click();
|
||||
});
|
||||
});
|
||||
cy.uiGetButton('Add').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiAddChannelsToCustomPolicy', (channelNames) => {
|
||||
cy.uiGetButton('Add channels').click();
|
||||
channelNames.forEach((channelName) => {
|
||||
cy.findByRole('textbox', {name: 'Search and add channels'}).typeWithForce(channelName);
|
||||
cy.wait(TIMEOUTS.ONE_SEC);
|
||||
cy.get('.channel-info-block').then((el) => {
|
||||
el.click();
|
||||
});
|
||||
});
|
||||
cy.uiGetButton('Add').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiAddRandomTeamToCustomPolicy', (numberOfTeams = 1) => {
|
||||
cy.uiGetButton('Add teams').click();
|
||||
for (let i = 0; i < numberOfTeams; i++) {
|
||||
cy.get('.team-info-block').first().then((el) => {
|
||||
el.click();
|
||||
});
|
||||
}
|
||||
cy.uiGetButton('Add').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiAddRandomChannelToCustomPolicy', (numberOfChannels = 1) => {
|
||||
cy.uiGetButton('Add channels').click();
|
||||
for (let i = 0; i < numberOfChannels; i++) {
|
||||
cy.get('.channel-info-block').first().then((el) => {
|
||||
el.click();
|
||||
});
|
||||
}
|
||||
cy.uiGetButton('Add').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiVerifyCustomPolicyRow', (policyId, description, duration, appliedTo) => {
|
||||
// * Assert row has correct description
|
||||
cy.get(`#customDescription-${policyId}`).should('include.text', description);
|
||||
|
||||
// * Assert row has correct duration
|
||||
cy.get(`#customDuration-${policyId}`).should('include.text', duration);
|
||||
|
||||
// * Assert row has correct team/channel counts
|
||||
cy.get(`#customAppliedTo-${policyId}`).should('include.text', appliedTo);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiClickEditCustomPolicyRow', (policyId) => {
|
||||
cy.get(`#customWrapper-${policyId}`).trigger('mouseover').click();
|
||||
cy.findByRole('button', {name: /edit/i}).should('be.visible').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiVerifyPolicyResponse', (body, teamCount, channelCount, duration, displayName) => {
|
||||
// * Assert response body exists
|
||||
assert.isNotNull(body);
|
||||
|
||||
// * Assert response body contains an ID
|
||||
assert.isNotNull(body.id);
|
||||
|
||||
// * Assert response body team_count matches supplied value
|
||||
expect(body.team_count).to.equal(teamCount);
|
||||
|
||||
// * Assert response body channel_count matches supplied value
|
||||
expect(body.channel_count).to.equal(channelCount);
|
||||
|
||||
// * Assert response body duration matches supplied value
|
||||
expect(body.post_duration).to.equal(duration);
|
||||
|
||||
// * Assert response body display_name matches supplied value
|
||||
expect(body.display_name).to.equal(displayName);
|
||||
});
|
||||
53
e2e-tests/cypress/tests/support/ui/emoji.ts
Обычный файл
53
e2e-tests/cypress/tests/support/ui/emoji.ts
Обычный файл
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChainableT} from 'tests/types';
|
||||
|
||||
Cypress.Commands.add('uiGetEmojiPicker', (): ChainableT<JQuery> => {
|
||||
return cy.get('#emojiPicker').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenEmojiPicker', (): ChainableT<JQuery> => {
|
||||
cy.findByRole('button', {name: 'select an emoji'}).click();
|
||||
return cy.get('#emojiPicker').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenCustomEmoji', () => {
|
||||
cy.uiOpenEmojiPicker();
|
||||
cy.findByText('Custom Emoji').should('be.visible').click();
|
||||
|
||||
cy.url().should('include', '/emoji');
|
||||
cy.get('.backstage-header').should('be.visible').and('contain', 'Custom Emoji');
|
||||
});
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Open custom emoji
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenCustomEmoji();
|
||||
*/
|
||||
uiGetEmojiPicker(): Chainable;
|
||||
|
||||
/**
|
||||
* Open custom emoji
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenCustomEmoji();
|
||||
*/
|
||||
uiOpenCustomEmoji(): Chainable;
|
||||
|
||||
/**
|
||||
* Open emoji picker
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenEmojiPicker();
|
||||
*/
|
||||
uiOpenEmojiPicker(): Chainable;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
e2e-tests/cypress/tests/support/ui/extend_testing_library.d.ts
поставляемый
Обычный файл
30
e2e-tests/cypress/tests/support/ui/extend_testing_library.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of the Testing Library commands
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Extends `findByRole` by matching case to `name` as insensitive but sensitive to `text` value
|
||||
* @param {string} role - button, input, textbox, etc.
|
||||
* @param {Object} option - text value of the target element
|
||||
*
|
||||
* @example
|
||||
* cy.findByRoleExtended('button', {name: 'Advanced'}).should('be.visible').click();
|
||||
*/
|
||||
findByRoleExtended(role: string, option: {name: string}): Chainable;
|
||||
}
|
||||
}
|
||||
7
e2e-tests/cypress/tests/support/ui/extend_testing_library.js
Обычный файл
7
e2e-tests/cypress/tests/support/ui/extend_testing_library.js
Обычный файл
@@ -0,0 +1,7 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('findByRoleExtended', (role, {name}) => {
|
||||
const re = RegExp(name, 'i');
|
||||
return cy.findByRole(role, {name: re}).should('have.text', name);
|
||||
});
|
||||
124
e2e-tests/cypress/tests/support/ui/file_preview.d.ts
поставляемый
Обычный файл
124
e2e-tests/cypress/tests/support/ui/file_preview.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiOpenFilePreviewModal`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Get file thumbnail from a post
|
||||
*
|
||||
* @param {string} filename
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetFileThumbnail('image.png');
|
||||
*/
|
||||
uiGetFileThumbnail(filename: string): Chainable;
|
||||
|
||||
/**
|
||||
* Get file upload preview located below post textbox
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetFileUploadPreview();
|
||||
*/
|
||||
uiGetFileUploadPreview(): Chainable;
|
||||
|
||||
/**
|
||||
* Wait for file upload preview located below post textbox
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetFileUploadPreview();
|
||||
*/
|
||||
uiGetFileUploadPreview(): Chainable;
|
||||
|
||||
/**
|
||||
* Get file preview modal
|
||||
*
|
||||
* @param {bool} option.exist - Set to false to not verify if the element exists. Otherwise, true (default) to check existence.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetFilePreviewModal();
|
||||
*/
|
||||
uiGetFilePreviewModal(option: Record<string, boolean>): Chainable;
|
||||
|
||||
/**
|
||||
* Get Public Link
|
||||
*
|
||||
* @param {bool} option.exist - Set to false to not verify if the element exists. Otherwise, true (default) to check existence.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetPublicLink();
|
||||
*/
|
||||
uiGetPublicLink(option: Record<string, boolean>): Chainable;
|
||||
|
||||
/**
|
||||
* Open file preview modal
|
||||
*
|
||||
* @param {string} filename
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenFilePreviewModal('image.png');
|
||||
*/
|
||||
uiOpenFilePreviewModal(filename: string): Chainable;
|
||||
|
||||
/**
|
||||
* Close file preview modal
|
||||
*
|
||||
* @example
|
||||
* cy.uiCloseFilePreviewModal();
|
||||
*/
|
||||
uiCloseFilePreviewModal(): Chainable;
|
||||
|
||||
/**
|
||||
* Get main content of file preview modal
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetContentFilePreviewModal();
|
||||
*/
|
||||
uiGetContentFilePreviewModal(): Chainable;
|
||||
|
||||
/**
|
||||
* Get download link button from file preview modal
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetDownloadLinkFilePreviewModal();
|
||||
*/
|
||||
uiGetDownloadLinkFilePreviewModal(): Chainable;
|
||||
|
||||
/**
|
||||
* Get download button from file preview modal
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetDownloadFilePreviewModal();
|
||||
*/
|
||||
uiGetDownloadFilePreviewModal(): Chainable;
|
||||
|
||||
/**
|
||||
* Get arrow left button from file preview modal
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetArrowLeftFilePreviewModal();
|
||||
*/
|
||||
uiGetArrowLeftFilePreviewModal(): Chainable;
|
||||
|
||||
/**
|
||||
* Get arrow right button from file preview modal
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetArrowRightFilePreviewModal();
|
||||
*/
|
||||
uiGetArrowRightFilePreviewModal(): Chainable;
|
||||
}
|
||||
}
|
||||
67
e2e-tests/cypress/tests/support/ui/file_preview.js
Обычный файл
67
e2e-tests/cypress/tests/support/ui/file_preview.js
Обычный файл
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiGetFileThumbnail', (filename) => {
|
||||
return cy.findByLabelText(`file thumbnail ${filename.toLowerCase()}`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetFileUploadPreview', () => {
|
||||
return cy.get('.file-preview__container');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiWaitForFileUploadPreview', () => {
|
||||
cy.waitUntil(() => cy.uiGetFileUploadPreview().then((el) => {
|
||||
return el.find('.post-image.normal').length > 0;
|
||||
}));
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetFilePreviewModal', (options = {exist: true}) => {
|
||||
if (options.exist) {
|
||||
return cy.get('.file-preview-modal').should('be.visible');
|
||||
}
|
||||
|
||||
return cy.get('.file-preview-modal').should('not.exist');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetPublicLink', (options = {exist: true}) => {
|
||||
if (options.exist) {
|
||||
return cy.get('.icon-link-variant').should('be.visible');
|
||||
}
|
||||
return cy.get('.icon-link-variant').should('not.exist');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetHeaderFilePreviewModal', () => {
|
||||
return cy.uiGetFilePreviewModal().find('.file-preview-modal-header').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenFilePreviewModal', (filename) => {
|
||||
if (filename) {
|
||||
cy.uiGetFileThumbnail(filename.toLowerCase()).click();
|
||||
} else {
|
||||
cy.findByTestId('fileAttachmentList').children().first().click();
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiCloseFilePreviewModal', () => {
|
||||
return cy.uiGetFilePreviewModal().find('.icon-close').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetContentFilePreviewModal', () => {
|
||||
return cy.uiGetFilePreviewModal().find('.file-preview-modal__content');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetDownloadLinkFilePreviewModal', () => {
|
||||
return cy.uiGetFilePreviewModal().find('.icon-link-variant').parent();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetDownloadFilePreviewModal', () => {
|
||||
return cy.uiGetFilePreviewModal().find('.icon-download-outline').parent();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetArrowLeftFilePreviewModal', () => {
|
||||
return cy.uiGetFilePreviewModal().find('.icon-chevron-left').parent();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetArrowRightFilePreviewModal', () => {
|
||||
return cy.uiGetFilePreviewModal().find('.icon-chevron-right').parent();
|
||||
});
|
||||
189
e2e-tests/cypress/tests/support/ui/global_header.d.ts
поставляемый
Обычный файл
189
e2e-tests/cypress/tests/support/ui/global_header.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,189 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiGetProductMenuButton`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Get product switch button
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetProductMenuButton().click();
|
||||
*/
|
||||
uiGetProductMenuButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get product switch menu
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetProductMenu().click();
|
||||
*/
|
||||
uiGetProductMenu(): Chainable;
|
||||
|
||||
/**
|
||||
* Open product switch menu
|
||||
*
|
||||
* @param {string} item - menu item ex. System Console, Integrations, etc.
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenProductMenu().click();
|
||||
*/
|
||||
uiOpenProductMenu(item: string): Chainable;
|
||||
|
||||
/**
|
||||
* Get set status button
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetSetStatusButton().click();
|
||||
*/
|
||||
uiGetSetStatusButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get profile header
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetProfileHeader();
|
||||
*/
|
||||
uiGetProfileHeader(): Chainable;
|
||||
|
||||
/**
|
||||
* Get status menu container
|
||||
*
|
||||
* @param {bool} option.exist - Set to false to not verify if the element exists. Otherwise, true (default) to check existence.
|
||||
* @example
|
||||
* cy.uiGetStatusMenuContainer({exist: false});
|
||||
*/
|
||||
uiGetStatusMenuContainer(option: Record<string, boolean>): Chainable;
|
||||
|
||||
/**
|
||||
* Get user menu
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetStatusMenu();
|
||||
*/
|
||||
uiGetStatusMenu(): Chainable;
|
||||
|
||||
/**
|
||||
* Open help menu
|
||||
*
|
||||
* @param {string} item - menu item ex. Ask the community, Help resources, etc.
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenHelpMenu();
|
||||
*/
|
||||
uiOpenHelpMenu(item: string): Chainable;
|
||||
|
||||
/**
|
||||
* Get help button
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetHelpButton();
|
||||
*/
|
||||
uiGetHelpButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get help menu
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetHelpMenu();
|
||||
*/
|
||||
uiGetHelpMenu(): Chainable;
|
||||
|
||||
/**
|
||||
* Open user menu
|
||||
*
|
||||
* @param {string} [item] - menu item ex. Profile, Logout, etc.
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenUserMenu();
|
||||
*/
|
||||
uiOpenUserMenu(item?: string): Chainable;
|
||||
|
||||
/**
|
||||
* Get search form container
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetSearchContainer();
|
||||
*/
|
||||
uiGetSearchContainer(): Chainable;
|
||||
|
||||
/**
|
||||
* Get search box
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetSearchBox();
|
||||
*/
|
||||
uiGetSearchBox(): Chainable;
|
||||
|
||||
/**
|
||||
* Get at-mention button
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetRecentMentionButton();
|
||||
*/
|
||||
uiGetRecentMentionButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get saved posts button
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetSavedPostButton();
|
||||
*/
|
||||
uiGetSavedPostButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get settings button
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetSettingsButton();
|
||||
*/
|
||||
uiGetSettingsButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get settings modal
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetSettingsModal();
|
||||
*/
|
||||
uiGetSettingsModal(): Chainable;
|
||||
|
||||
/**
|
||||
* Get channel info button
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetChannelInfoButton();
|
||||
*/
|
||||
uiGetChannelInfoButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Open settings modal
|
||||
*
|
||||
* @param {string} section - ex. Display, Sidebar, etc.
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenSettingsModal();
|
||||
*/
|
||||
uiOpenSettingsModal(section: string): Chainable;
|
||||
|
||||
/**
|
||||
* User log out via user menu
|
||||
*
|
||||
* @example
|
||||
* cy.uiLogout();
|
||||
*/
|
||||
uiLogout(): Chainable;
|
||||
}
|
||||
}
|
||||
155
e2e-tests/cypress/tests/support/ui/global_header.js
Обычный файл
155
e2e-tests/cypress/tests/support/ui/global_header.js
Обычный файл
@@ -0,0 +1,155 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiGetProductMenuButton', () => {
|
||||
return cy.findByRole('button', {name: 'Product switch menu'}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetProductMenu', () => {
|
||||
return cy.get('.product-switcher-menu').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenProductMenu', (item = '') => {
|
||||
// # Click on product switch button
|
||||
cy.uiGetProductMenuButton().click();
|
||||
|
||||
if (!item) {
|
||||
// # Return the menu if no item is passed
|
||||
return cy.uiGetProductMenu();
|
||||
}
|
||||
|
||||
// # Click on a particular item
|
||||
return cy.uiGetProductMenu().
|
||||
findByText(item).
|
||||
scrollIntoView().
|
||||
should('be.visible').
|
||||
click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetSetStatusButton', () => {
|
||||
return cy.findByRole('button', {name: /Select to open profile and status menu\./i}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetProfileHeader', () => {
|
||||
return cy.uiGetSetStatusButton().parent();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetStatusMenuContainer', (options = {exist: true}) => {
|
||||
if (options.exist) {
|
||||
return cy.findByRole('menu').should('exist');
|
||||
}
|
||||
|
||||
return cy.findByRole('menu').should('not.exist');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetStatusMenu', (options = {visible: true}) => {
|
||||
if (options.visible) {
|
||||
return cy.uiGetStatusMenuContainer().
|
||||
find('ul').
|
||||
should('be.visible');
|
||||
}
|
||||
|
||||
return cy.uiGetStatusMenuContainer().
|
||||
find('ul').
|
||||
should('not.be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenHelpMenu', (item = '') => {
|
||||
// # Click on help status button
|
||||
cy.uiGetHelpButton().click();
|
||||
|
||||
if (!item) {
|
||||
// # Return the menu if no item is passed
|
||||
return cy.uiGetHelpMenu();
|
||||
}
|
||||
|
||||
// # Click on a particular item
|
||||
return cy.uiGetHelpMenu().
|
||||
findByText(item).
|
||||
scrollIntoView().
|
||||
should('be.visible').
|
||||
click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetHelpButton', () => {
|
||||
return cy.findByRole('button', {name: 'Help'}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetHelpMenu', (options = {visible: true}) => {
|
||||
const dropdown = () => cy.get('#helpMenuPortal').find('.dropdown-menu');
|
||||
|
||||
if (options.visible) {
|
||||
return dropdown().should('be.visible');
|
||||
}
|
||||
|
||||
return dropdown().should('not.be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenUserMenu', (item = '') => {
|
||||
// # Click on user status button
|
||||
cy.uiGetSetStatusButton().click();
|
||||
|
||||
if (!item) {
|
||||
// # Return the menu if no item is passed
|
||||
return cy.uiGetStatusMenu();
|
||||
}
|
||||
|
||||
// # Click on a particular item
|
||||
return cy.uiGetStatusMenu().
|
||||
findByText(item).
|
||||
scrollIntoView().
|
||||
should('be.visible').
|
||||
click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetSearchContainer', () => {
|
||||
return cy.get('#searchFormContainer').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetSearchBox', () => {
|
||||
return cy.get('#searchBox').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetRecentMentionButton', () => {
|
||||
return cy.findByRole('button', {name: 'Recent mentions'}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetSavedPostButton', () => {
|
||||
return cy.findByRole('button', {name: 'Saved posts'}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetSettingsButton', () => {
|
||||
return cy.findByRole('button', {name: 'Settings'}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetChannelInfoButton', () => {
|
||||
return cy.findByRole('button', {name: 'View Info'}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetSettingsModal', () => {
|
||||
// # Get settings modal
|
||||
return cy.findByRole('dialog', {name: 'Settings'});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenSettingsModal', (section = '') => {
|
||||
// # Open settings modal
|
||||
cy.uiGetSettingsButton().click();
|
||||
|
||||
if (!section) {
|
||||
return cy.uiGetSettingsModal();
|
||||
}
|
||||
|
||||
// # Click on a particular section
|
||||
cy.findByRoleExtended('tab', {name: section}).should('be.visible').click();
|
||||
|
||||
return cy.uiGetSettingsModal();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiLogout', () => {
|
||||
// # Click logout via user menu
|
||||
cy.uiOpenUserMenu('Log Out');
|
||||
|
||||
cy.url().should('include', '/login');
|
||||
cy.get('.login-body-message').should('be.visible');
|
||||
cy.get('.login-body-card').should('be.visible');
|
||||
});
|
||||
31
e2e-tests/cypress/tests/support/ui/index.js
Обычный файл
31
e2e-tests/cypress/tests/support/ui/index.js
Обычный файл
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import './account_settings_modal';
|
||||
import './announcement_bar';
|
||||
import './boards';
|
||||
import './channel';
|
||||
import './channel_header';
|
||||
import './channel_sidebar';
|
||||
import './cloud_billing';
|
||||
import './common';
|
||||
import './compliance_export';
|
||||
import './data_retention';
|
||||
import './extend_testing_library';
|
||||
import './global_header';
|
||||
import './emoji';
|
||||
import './file_preview';
|
||||
import './login';
|
||||
import './menu';
|
||||
import './mfa';
|
||||
import './modal';
|
||||
import './playbooks';
|
||||
import './post';
|
||||
import './post_dropdown_menu';
|
||||
import './search';
|
||||
import './sidebar_left';
|
||||
import './sidebar_right';
|
||||
import './suggestion_list';
|
||||
import './system';
|
||||
import './team';
|
||||
import './tooltip';
|
||||
30
e2e-tests/cypress/tests/support/ui/login.d.ts
поставляемый
Обычный файл
30
e2e-tests/cypress/tests/support/ui/login.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiLogin`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Login vi UI at login page
|
||||
*
|
||||
* @param {UserProfile} user - user with username and password
|
||||
*
|
||||
* @example
|
||||
* cy.uiLogin(user);
|
||||
*/
|
||||
uiLogin(user: UserProfile): Chainable;
|
||||
}
|
||||
}
|
||||
11
e2e-tests/cypress/tests/support/ui/login.js
Обычный файл
11
e2e-tests/cypress/tests/support/ui/login.js
Обычный файл
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiLogin', (user = {}) => {
|
||||
cy.url().should('include', '/login');
|
||||
|
||||
// # Type email and password, then Sign in
|
||||
cy.get('#input_loginId').should('be.visible').type(user.email);
|
||||
cy.get('#input_password-input').should('be.visible').type(user.password);
|
||||
cy.get('#saveSetting').should('not.be.disabled').click();
|
||||
});
|
||||
46
e2e-tests/cypress/tests/support/ui/menu.d.ts
поставляемый
Обычный файл
46
e2e-tests/cypress/tests/support/ui/menu.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiOpenSystemConsoleMainMenu`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Open main menu at system console
|
||||
* @param {string} item - such as `'Switch to [Team Name]'`, `'Administrator's Guide'`, `'Troubleshooting Forum'`, `'Commercial Support'`, `'About Mattermost'` and `'Log Out'`.
|
||||
* @return the main menu
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenSystemConsoleMainMenu();
|
||||
*/
|
||||
uiOpenSystemConsoleMainMenu(): Chainable;
|
||||
|
||||
/**
|
||||
* Close main menu at system console
|
||||
*
|
||||
* @example
|
||||
* cy.uiCloseSystemConsoleMainMenu();
|
||||
*/
|
||||
uiCloseSystemConsoleMainMenu(): Chainable;
|
||||
|
||||
/**
|
||||
* Get main menu at system console
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetSystemConsoleMainMenu();
|
||||
*/
|
||||
uiGetSystemConsoleMainMenu(): Chainable;
|
||||
}
|
||||
}
|
||||
46
e2e-tests/cypress/tests/support/ui/menu.js
Обычный файл
46
e2e-tests/cypress/tests/support/ui/menu.js
Обычный файл
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
const SYSTEM_CONSOLE_MAIN_MENU = 'Menu Icon';
|
||||
|
||||
function openMenu(name, item) {
|
||||
const menu = () => cy.findByRole('button', {name}).should('be.visible');
|
||||
|
||||
// # Open the menu
|
||||
menu().should('be.visible').click();
|
||||
|
||||
if (!item) {
|
||||
return menu();
|
||||
}
|
||||
|
||||
// # Click on a particular item
|
||||
return cy.findByRole('menu').findByText(item).scrollIntoView().should('be.visible').click();
|
||||
}
|
||||
|
||||
function getMenu(name) {
|
||||
return cy.findByRole('button', {name}).should('be.visible');
|
||||
}
|
||||
|
||||
Cypress.Commands.add('uiOpenSystemConsoleMainMenu', (item = '') => {
|
||||
return openMenu(SYSTEM_CONSOLE_MAIN_MENU, item);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiCloseSystemConsoleMainMenu', () => {
|
||||
return cy.uiGetSystemConsoleMainMenu().click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetSystemConsoleMainMenu', () => {
|
||||
return getMenu(SYSTEM_CONSOLE_MAIN_MENU);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenDndStatusSubMenu', () => {
|
||||
cy.uiOpenUserMenu();
|
||||
|
||||
// # Wait for status menu to transition in
|
||||
cy.get('.MenuWrapper.status-dropdown-menu .Menu__content.dropdown-menu').should('be.visible');
|
||||
|
||||
// # Hover over Do Not Disturb option
|
||||
cy.get('.MenuWrapper.status-dropdown-menu .Menu__content.dropdown-menu li#status-menu-dnd_menuitem').trigger('mouseover');
|
||||
|
||||
return cy.get('#status-menu-dnd');
|
||||
});
|
||||
34
e2e-tests/cypress/tests/support/ui/mfa.d.ts
поставляемый
Обычный файл
34
e2e-tests/cypress/tests/support/ui/mfa.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiGetMFASecret`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Get MFA secret of a given user
|
||||
* @param {string} userId - ID of user
|
||||
*
|
||||
* @returns {string} `secret` - MFA secret
|
||||
*
|
||||
* @example
|
||||
* const headerLabel = 'What\'s New';
|
||||
* cy.uiGetMFASecret('user-id').then((secret) => {
|
||||
* // do something with the secret
|
||||
* });
|
||||
*/
|
||||
uiGetMFASecret(userId: string): Chainable<string>;
|
||||
}
|
||||
}
|
||||
32
e2e-tests/cypress/tests/support/ui/mfa.js
Обычный файл
32
e2e-tests/cypress/tests/support/ui/mfa.js
Обычный файл
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import authenticator from 'authenticator';
|
||||
|
||||
import * as TIMEOUTS from '../../fixtures/timeouts';
|
||||
|
||||
Cypress.Commands.add('uiGetMFASecret', (userId) => {
|
||||
return cy.url().then((url) => {
|
||||
if (url.includes('mfa/setup')) {
|
||||
// # Complete MFA setup if we are on token setup page /mfa/setup
|
||||
return 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.findByPlaceholderText('MFA Code').type(token);
|
||||
cy.findByText('Save').click();
|
||||
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
cy.findByText('Okay').click();
|
||||
|
||||
return cy.wrap(secret);
|
||||
});
|
||||
}
|
||||
|
||||
// # If the user already has MFA enabled, reset the secret.
|
||||
return cy.apiGenerateMfaSecret(userId).then((res) => {
|
||||
return cy.wrap(res.code.secret);
|
||||
});
|
||||
});
|
||||
});
|
||||
30
e2e-tests/cypress/tests/support/ui/modal.d.ts
поставляемый
Обычный файл
30
e2e-tests/cypress/tests/support/ui/modal.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiCloseModal`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Close modal with header label
|
||||
* @param {string} headerLabel - the header label
|
||||
*
|
||||
* @example
|
||||
* const headerLabel = 'What\'s New';
|
||||
* cy.uiCloseModal(headerLabel);
|
||||
*/
|
||||
uiCloseModal(headerLabel: string): Chainable;
|
||||
}
|
||||
}
|
||||
9
e2e-tests/cypress/tests/support/ui/modal.js
Обычный файл
9
e2e-tests/cypress/tests/support/ui/modal.js
Обычный файл
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../fixtures/timeouts';
|
||||
|
||||
Cypress.Commands.add('uiCloseModal', (headerLabel) => {
|
||||
// # Close modal with modal label
|
||||
cy.get('#genericModalLabel', {timeout: TIMEOUTS.HALF_MIN}).should('have.text', headerLabel).parents().find('.modal-dialog').findByLabelText('Close').click();
|
||||
});
|
||||
324
e2e-tests/cypress/tests/support/ui/playbooks.js
Обычный файл
324
e2e-tests/cypress/tests/support/ui/playbooks.js
Обычный файл
@@ -0,0 +1,324 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../fixtures/timeouts';
|
||||
const playbookRunStartCommand = '/playbook run';
|
||||
|
||||
Cypress.Commands.add('startPlaybookRun', (playbookName, playbookRunName) => {
|
||||
cy.get('#interactiveDialogModal').should('exist').within(() => {
|
||||
// # Select playbook
|
||||
cy.selectPlaybookFromDropdown(playbookName);
|
||||
|
||||
// # Type playbook run name
|
||||
cy.findByTestId('playbookRunNameinput').type(playbookRunName, {force: true});
|
||||
|
||||
// # Submit
|
||||
cy.get('#interactiveDialogSubmit').click();
|
||||
});
|
||||
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
});
|
||||
|
||||
// Opens playbook run dialog using the `/playbook run` slash command
|
||||
Cypress.Commands.add('openPlaybookRunDialogFromSlashCommand', () => {
|
||||
cy.uiPostMessageQuickly(playbookRunStartCommand);
|
||||
});
|
||||
|
||||
// Starts playbook run with the `/playbook run` slash command
|
||||
Cypress.Commands.add('startPlaybookRunWithSlashCommand', (playbookName, playbookRunName) => {
|
||||
cy.openPlaybookRunDialogFromSlashCommand();
|
||||
|
||||
cy.startPlaybookRun(playbookName, playbookRunName);
|
||||
});
|
||||
|
||||
// Selects Playbooks icon in the App Bar
|
||||
Cypress.Commands.add('getPlaybooksAppBarIcon', () => {
|
||||
cy.get('#channel_view').should('be.visible');
|
||||
|
||||
return cy.get('.app-bar').find('#app-bar-icon-playbooks .app-bar__icon-inner');
|
||||
});
|
||||
|
||||
// Starts playbook run from the playbook run RHS
|
||||
Cypress.Commands.add('startPlaybookRunFromRHS', (playbookName, playbookRunName) => {
|
||||
cy.get('#channel-header').within(() => {
|
||||
// open flagged posts to ensure playbook run RHS is closed
|
||||
cy.get('#channelHeaderFlagButton').click();
|
||||
|
||||
// open the playbook run RHS
|
||||
cy.getPlaybooksAppBarIcon().should('exist').click();
|
||||
});
|
||||
|
||||
cy.get('#rhsContainer').should('exist').within(() => {
|
||||
cy.findByText('Run playbook').click();
|
||||
});
|
||||
|
||||
cy.startPlaybookRun(playbookName, playbookRunName);
|
||||
});
|
||||
|
||||
// Create a new task from the RHS
|
||||
Cypress.Commands.add('addNewTaskFromRHS', (taskname) => {
|
||||
// Click add new task
|
||||
cy.findByTestId('add-new-task-0').click();
|
||||
|
||||
// Type a name
|
||||
cy.findByTestId('checklist-item-textarea-title').type(taskname);
|
||||
|
||||
// Save task
|
||||
cy.findByTestId('checklist-item-save-button').click();
|
||||
});
|
||||
|
||||
// Starts playbook run from the post menu
|
||||
Cypress.Commands.add('startPlaybookRunFromPostMenu', (playbookName, playbookRunName) => {
|
||||
// post a message as user to avoid system message
|
||||
cy.findByTestId('post_textbox').clear().type('new message here{enter}');
|
||||
|
||||
// post a second message because cypress has trouble finding latest post when there's only one message
|
||||
cy.findByTestId('post_textbox').clear().type('another new message here{enter}');
|
||||
cy.clickPostActionsMenu();
|
||||
cy.findByTestId('playbookRunPostMenuIcon').click();
|
||||
cy.startPlaybookRun(playbookName, playbookRunName);
|
||||
});
|
||||
|
||||
// Create playbook
|
||||
Cypress.Commands.add('createPlaybook', (teamName, playbookName) => {
|
||||
cy.visit('/playbooks/playbooks/new');
|
||||
|
||||
cy.findByTestId('save_playbook', {timeout: TIMEOUTS.HALF_MIN}).should('exist');
|
||||
|
||||
// # Type playbook name
|
||||
cy.get('#playbook-name .editable-trigger').click();
|
||||
cy.get('#playbook-name .editable-input').type(playbookName);
|
||||
cy.get('#playbook-name .editable-input').type('{enter}');
|
||||
|
||||
// # Save playbook
|
||||
cy.findByTestId('save_playbook', {timeout: TIMEOUTS.HALF_MIN}).should('not.be.disabled').click();
|
||||
cy.wait(TIMEOUTS.TWO_SEC);
|
||||
cy.findByTestId('save_playbook', {timeout: TIMEOUTS.HALF_MIN}).should('not.be.disabled').click();
|
||||
});
|
||||
|
||||
// Select the playbook from the dropdown menu
|
||||
Cypress.Commands.add('selectPlaybookFromDropdown', (playbookName) => {
|
||||
cy.findByTestId('autoCompleteSelector').should('exist').within(() => {
|
||||
cy.get('input').click().type(playbookName.toLowerCase());
|
||||
cy.get('#suggestionList').contains(playbookName).click({force: true});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('createPost', (message) => {
|
||||
// post a message as user to avoid system message
|
||||
cy.findByTestId('post_textbox').clear().type(`${message}{enter}`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('addPostToTimelineUsingPostMenu', (playbookRunName, summary, postId) => {
|
||||
cy.clickPostDotMenu(postId);
|
||||
cy.findByTestId('playbookRunAddToTimeline').click();
|
||||
|
||||
cy.get('#interactiveDialogModal').should('exist').within(() => {
|
||||
// # Select playbook run
|
||||
cy.findByTestId('autoCompleteSelector').should('exist').within(() => {
|
||||
cy.get('input').click().type(playbookRunName);
|
||||
cy.get('#suggestionList').contains(playbookRunName).click({force: true});
|
||||
});
|
||||
|
||||
// # Type playbook run name
|
||||
cy.findByTestId('summaryinput').clear().type(summary, {force: true});
|
||||
|
||||
// # Submit
|
||||
cy.get('#interactiveDialogSubmit').click();
|
||||
});
|
||||
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openSelector', () => {
|
||||
cy.findByText('Search for people').click({force: true});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('addInvitedUser', (userName) => {
|
||||
cy.get('.invite-users-selector__menu').within(() => {
|
||||
cy.findByText(userName).click({force: true});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('selectOwner', (userName) => {
|
||||
cy.get('.assign-owner-selector__menu').within(() => {
|
||||
cy.findByText(userName).click({force: true});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('selectChannel', (channelName) => {
|
||||
cy.get('#playbook-automation-broadcast .playbooks-rselect__menu').within(() => {
|
||||
cy.findByText(channelName).click({force: true});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openReminderSelector', () => {
|
||||
cy.get('#reminder_timer_datetime input').click({force: true});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('selectReminderTime', (timeText) => {
|
||||
cy.get('#reminder_timer_datetime .playbooks-rselect__menu').within(() => {
|
||||
cy.findByText(timeText).click({force: true});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Update the status of the current playbook run through the slash command.
|
||||
*/
|
||||
Cypress.Commands.add('updateStatus', (message, reminderQuery) => {
|
||||
// # Run the slash command to update status.
|
||||
cy.uiPostMessageQuickly('/playbook update');
|
||||
|
||||
// # Get the interactive dialog modal.
|
||||
cy.getStatusUpdateDialog().within(() => {
|
||||
// # remove what's there if applicable, and type the new update in the textbox.
|
||||
cy.findByTestId('update_run_status_textbox').clear().type(message);
|
||||
|
||||
if (reminderQuery) {
|
||||
cy.get('#reminder_timer_datetime').within(() => {
|
||||
cy.get('input').type(reminderQuery, {delay: TIMEOUTS.TWO_HUNDRED_MILLIS, force: true}).type('{enter}', {force: true});
|
||||
});
|
||||
}
|
||||
|
||||
// # Submit the dialog.
|
||||
cy.get('button.confirm').click();
|
||||
});
|
||||
|
||||
// * Verify that the interactive dialog has gone.
|
||||
cy.getStatusUpdateDialog().should('not.exist');
|
||||
|
||||
// # Return the post ID of the status update.
|
||||
return cy.getLastPostId();
|
||||
});
|
||||
|
||||
/**
|
||||
* Edit a post through the post dot menu.
|
||||
* @param {String} postId - ID of the post to delete.
|
||||
* @param {String} newMessage - New content of the post.
|
||||
*/
|
||||
Cypress.Commands.add('editPost', (postId, newMessage) => {
|
||||
// # Open the post dot menu.
|
||||
cy.clickPostDotMenu(postId);
|
||||
|
||||
// # Click on the Edit menu option.
|
||||
cy.get(`#edit_post_${postId}`).click();
|
||||
|
||||
// # Overwrite the post content with the new message provided.
|
||||
cy.get('#edit_textbox').clear().type(newMessage);
|
||||
|
||||
// # Confirm the edit in the dialog.
|
||||
cy.get('#editButton').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('getStatusUpdateDialog', () => {
|
||||
return cy.findByRole('dialog', {name: /post update/i});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('getStyledComponent', (className) => {
|
||||
cy.get(`[class^="${className}-"]`);
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the provided pseudo-class from the previous element and return the property passed as argument
|
||||
* @param {String} pseudoClass - CSS pseudo class to get.
|
||||
* @param {String} property - Property that will be returned.
|
||||
*
|
||||
* Stolen from https://stackoverflow.com/questions/55516990/cypress-testing-pseudo-css-class-before
|
||||
*/
|
||||
Cypress.Commands.add('cssPseudoClass', {prevSubject: 'element'}, (el, pseudoClass, property) => {
|
||||
const win = el[0].ownerDocument.defaultView;
|
||||
const pseudoElem = win.getComputedStyle(el[0], pseudoClass);
|
||||
return pseudoElem.getPropertyValue(property).replace(/(^")|("$)/g, '');
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the :before pseudo-class from the previous element and return the property passed as argument
|
||||
* @param {String} property - Property that will be returned.
|
||||
*/
|
||||
Cypress.Commands.add('before', {prevSubject: 'element'}, (el, property) => {
|
||||
return cy.wrap(el).cssPseudoClass('before', property);
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the :after pseudo-class from the previous element and return the property passed as argument
|
||||
* @param {String} property - Property that will be returned.
|
||||
*/
|
||||
Cypress.Commands.add('after', {prevSubject: 'element'}, (el, property) => {
|
||||
return cy.wrap(el).cssPseudoClass('after', property);
|
||||
});
|
||||
|
||||
function waitUntilPermanentPost() {
|
||||
cy.get('#postListContent').should('exist');
|
||||
cy.waitUntil(() => cy.findAllByTestId('postView').last().then((el) => !(el[0].id.includes(':'))));
|
||||
}
|
||||
|
||||
Cypress.Commands.add('getFirstPostId', () => {
|
||||
waitUntilPermanentPost();
|
||||
|
||||
cy.findAllByTestId('postView').first().should('have.attr', 'id').and('not.include', ':').
|
||||
invoke('replace', 'post_', '');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('assertRunDetailsPageRenderComplete', (expectedRunOwner) => {
|
||||
cy.findByTestId('lhs-navigation').should('be.visible').within(() => {
|
||||
cy.contains('Playbooks').should('be.visible');
|
||||
cy.contains('Runs').should('be.visible');
|
||||
});
|
||||
cy.get('#playbooks-sidebar-right').should('be.visible').within(() => {
|
||||
cy.findByTestId('assignee-profile-selector').should('contain', expectedRunOwner);
|
||||
cy.findAllByTestId('timeline-item', {exact: false}).should('have.length.of.at.least', 1);
|
||||
cy.findAllByTestId('profile-option', {exact: false}).should('have.length.of.at.least', 1);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('interceptTelemetry', () => {
|
||||
cy.intercept('/plugins/playbooks/api/v0/telemetry').as('telemetry');
|
||||
});
|
||||
|
||||
const defaultExpectTelemetryToContainOptions = {
|
||||
waitForCalls: 'auto',
|
||||
};
|
||||
|
||||
// cy.expectTelemetryToContain expects to find the given telemetry events in the order given among the
|
||||
// recorded telemetry. It doesn't fail if other telemetry events happen to occur in between.
|
||||
Cypress.Commands.add('expectTelemetryToContain', (items, opts) => {
|
||||
const options = {...defaultExpectTelemetryToContainOptions, ...opts};
|
||||
|
||||
// Wait for at least as many telemetry events as requested if auto, or explicit number if passed.
|
||||
if (options.waitForCalls === 'auto') {
|
||||
items.forEach(() => cy.wait('@telemetry'));
|
||||
} else {
|
||||
for (let i = 0; i < options.waitForCalls; i++) {
|
||||
cy.wait('@telemetry');
|
||||
}
|
||||
}
|
||||
|
||||
// When additional telemetry events are emitted than what is expected, the ones we want may
|
||||
// still be be pending, so wait a bit more to try to let requests settle.
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
cy.get('@telemetry.all').then((xhrs) => {
|
||||
let xhrIndex = 0;
|
||||
items.forEach((item) => {
|
||||
while (xhrIndex < xhrs.length) {
|
||||
const xhr = xhrs[xhrIndex];
|
||||
|
||||
// Advance to the next xhr element regardless of whether or not we find a match.
|
||||
xhrIndex++;
|
||||
|
||||
if (xhr.request.body.name === item.name && xhr.request.body.type === item.type) {
|
||||
// Validate only passed properties
|
||||
if (item.properties) {
|
||||
for (const [key, value] of Object.entries(item.properties)) {
|
||||
expect(xhr.request.body.properties[key]).to.eq(value, `Property ${key} does not match for event ${item.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`failed to find telemetry event '${item.type}' '${item.name}'`);
|
||||
});
|
||||
});
|
||||
});
|
||||
254
e2e-tests/cypress/tests/support/ui/post.ts
Обычный файл
254
e2e-tests/cypress/tests/support/ui/post.ts
Обычный файл
@@ -0,0 +1,254 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChainableT} from '../../types';
|
||||
|
||||
function uiGetPostTextBox(option = {exist: true}): ChainableT<JQuery> {
|
||||
if (option.exist) {
|
||||
return cy.get('#post_textbox').should('be.visible');
|
||||
}
|
||||
|
||||
return cy.get('#post_textbox').should('not.exist');
|
||||
}
|
||||
Cypress.Commands.add('uiGetPostTextBox', uiGetPostTextBox);
|
||||
|
||||
function uiGetReplyTextBox(option = {exist: true}): ChainableT<JQuery> {
|
||||
if (option.exist) {
|
||||
return cy.get('#reply_textbox').should('be.visible');
|
||||
}
|
||||
|
||||
return cy.get('#reply_textbox').should('not.exist');
|
||||
}
|
||||
Cypress.Commands.add('uiGetReplyTextBox', uiGetReplyTextBox);
|
||||
|
||||
function uiGetPostProfileImage(postId: string): ChainableT<JQuery> {
|
||||
return getPost(postId).within(() => {
|
||||
return cy.get('.post__img').should('be.visible');
|
||||
});
|
||||
}
|
||||
Cypress.Commands.add('uiGetPostProfileImage', uiGetPostProfileImage);
|
||||
|
||||
function uiGetPostHeader(postId: string): ChainableT<JQuery> {
|
||||
return getPost(postId).within(() => {
|
||||
return cy.get('.post__header').should('be.visible');
|
||||
});
|
||||
}
|
||||
Cypress.Commands.add('uiGetPostHeader', uiGetPostHeader);
|
||||
|
||||
function uiGetPostBody(postId: string): ChainableT<JQuery> {
|
||||
return getPost(postId).within(() => {
|
||||
return cy.get('.post__body').should('be.visible');
|
||||
});
|
||||
}
|
||||
Cypress.Commands.add('uiGetPostBody', uiGetPostBody);
|
||||
|
||||
function uiGetPostThreadFooter(postId: string): ChainableT<JQuery> {
|
||||
return getPost(postId).find('.ThreadFooter');
|
||||
}
|
||||
Cypress.Commands.add('uiGetPostThreadFooter', uiGetPostThreadFooter);
|
||||
|
||||
function uiGetPostEmbedContainer(postId: string): ChainableT<JQuery> {
|
||||
return cy.uiGetPostBody(postId).
|
||||
find('.file-preview__button').
|
||||
should('be.visible');
|
||||
}
|
||||
Cypress.Commands.add('uiGetPostEmbedContainer', uiGetPostEmbedContainer);
|
||||
|
||||
function getPost(postId: string): ChainableT<JQuery> {
|
||||
if (postId) {
|
||||
return cy.get(`#post_${postId}`).should('be.visible');
|
||||
}
|
||||
|
||||
return cy.getLastPost();
|
||||
}
|
||||
Cypress.Commands.add('getPost', getPost);
|
||||
|
||||
export function verifySavedPost(postId, message) {
|
||||
// * Check that the center save icon has been updated correctly
|
||||
cy.get(`#post_${postId}`).trigger('mouseover', {force: true});
|
||||
cy.get(`#CENTER_flagIcon_${postId}`).
|
||||
should('have.class', 'post-menu__item').
|
||||
and('have.attr', 'aria-label', 'remove from saved');
|
||||
|
||||
// # Open the post-dotmenu
|
||||
cy.clickPostDotMenu(postId, 'CENTER');
|
||||
|
||||
// * Check that the dotmenu item is changed accordingly
|
||||
cy.findAllByTestId(`post-menu-${postId}`).eq(0).should('be.visible');
|
||||
cy.findByText('Remove from Saved').scrollIntoView().should('be.visible');
|
||||
cy.get(`#CENTER_dropdown_${postId}`).should('be.visible').type('{esc}');
|
||||
|
||||
// * Check that the post is highlighted
|
||||
cy.get(`#post_${postId}`).should('have.class', 'post--pinned-or-flagged');
|
||||
|
||||
// * Check that the post pre-header is visible
|
||||
cy.get('div.post-pre-header').should('be.visible');
|
||||
|
||||
// * Check that the post pre-header has the saved icon
|
||||
cy.get('span.icon--post-pre-header').
|
||||
should('be.visible').
|
||||
within(() => {
|
||||
cy.get('svg').should('have.attr', 'aria-label', 'Saved Icon');
|
||||
});
|
||||
|
||||
// * Check that the post pre-header has the saved post link
|
||||
cy.get('div.post-pre-header__text-container').
|
||||
should('be.visible').
|
||||
and('have.text', 'Saved').
|
||||
within(() => {
|
||||
cy.get('a').as('savedLink').should('be.visible');
|
||||
});
|
||||
|
||||
// * Check that the saved posts list is not open in RHS before clicking the link in the post pre-header
|
||||
cy.get('#searchContainer').should('not.exist');
|
||||
|
||||
// # Click the link
|
||||
cy.get('@savedLink').click();
|
||||
|
||||
// * Check that the saved posts list is open in RHS
|
||||
cy.get('#searchContainer').should('be.visible').within(() => {
|
||||
cy.get('.sidebar--right__title').
|
||||
should('be.visible').
|
||||
and('have.text', 'Saved Posts');
|
||||
|
||||
// * Check that the post pre-header is not shown for the saved message in RHS
|
||||
cy.get('#search-items-container').within(() => {
|
||||
cy.get(`#rhsPostMessageText_${postId}`).contains(message);
|
||||
cy.get('div.post-pre-header').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
// # Close the RHS
|
||||
cy.get('#searchResultsCloseButton').should('be.visible').click();
|
||||
}
|
||||
|
||||
export function verifyUnsavedPost(postId) {
|
||||
// * Check that the center save icon has been updated correctly
|
||||
cy.get(`#post_${postId}`).trigger('mouseover', {force: true});
|
||||
cy.get(`#CENTER_flagIcon_${postId}`).
|
||||
should('have.class', 'post-menu__item').
|
||||
and('have.attr', 'aria-label', 'save');
|
||||
|
||||
// # Open the post-dotmenu
|
||||
cy.clickPostDotMenu(postId, 'CENTER');
|
||||
|
||||
// * Check that the dotmenu item is changed accordingly
|
||||
cy.findAllByTestId(`post-menu-${postId}`).eq(0).should('be.visible');
|
||||
cy.findByText('Save').scrollIntoView().should('be.visible');
|
||||
cy.get(`#CENTER_dropdown_${postId}`).should('be.visible').type('{esc}');
|
||||
|
||||
// * Check that the post is highlighted
|
||||
cy.get(`#post_${postId}`).should('not.have.class', 'post--pinned-or-flagged');
|
||||
|
||||
// * Check that the post pre-header is visible
|
||||
cy.get('div.post-pre-header').should('not.exist');
|
||||
|
||||
// * Check that the post pre-header has the saved icon
|
||||
cy.get('span.icon--post-pre-header').
|
||||
should('not.exist');
|
||||
|
||||
// * Check that the post pre-header has the saved post link
|
||||
cy.get('div.post-pre-header__text-container').
|
||||
should('not.exist');
|
||||
|
||||
// * Check that the saved posts list is not open in RHS before clicking the link in the post pre-header
|
||||
cy.get('#searchContainer').should('not.exist');
|
||||
|
||||
// # Click the link
|
||||
cy.uiGetSavedPostButton().click();
|
||||
|
||||
// * Check that the saved posts list is open in RHS
|
||||
cy.get('#searchContainer').should('be.visible').within(() => {
|
||||
cy.get('.sidebar--right__title').
|
||||
should('be.visible').
|
||||
and('have.text', 'Saved Posts');
|
||||
|
||||
// * Check that the post pre-header is not shown for the saved message in RHS
|
||||
cy.get('#search-items-container').within(() => {
|
||||
cy.get(`#rhsPostMessageText_${postId}`).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
// # Close the RHS
|
||||
cy.get('#searchResultsCloseButton').should('be.visible').click();
|
||||
}
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Get post profile image of a given post ID or the last post if post ID is not given
|
||||
*
|
||||
* @param {string} - postId (optional)
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetPostProfileImage();
|
||||
*/
|
||||
uiGetPostProfileImage: typeof uiGetPostProfileImage;
|
||||
|
||||
/**
|
||||
* Get post header of a given post ID or the last post if post ID is not given
|
||||
*
|
||||
* @param {string} - postId (optional)
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetPostHeader();
|
||||
*/
|
||||
uiGetPostHeader: typeof uiGetPostHeader;
|
||||
|
||||
/**
|
||||
* Get post body of a given post ID or the last post if post ID is not given
|
||||
*
|
||||
* @param {string} - postId (optional)
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetPostBody();
|
||||
*/
|
||||
uiGetPostBody: typeof uiGetPostBody;
|
||||
|
||||
/**
|
||||
* Get post thread footer of a given post ID or the last post if post ID is not given
|
||||
*
|
||||
* @param {string} - postId (optional)
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetPostThreadFooter();
|
||||
*/
|
||||
uiGetPostThreadFooter: typeof uiGetPostThreadFooter;
|
||||
|
||||
/**
|
||||
* Get post embed container of a given post ID or the last post if post ID is not given
|
||||
*
|
||||
* @param {string} - postId (optional)
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetPostEmbedContainer();
|
||||
*/
|
||||
uiGetPostEmbedContainer: typeof uiGetPostEmbedContainer;
|
||||
|
||||
/**
|
||||
* Get post textbox
|
||||
*
|
||||
* @param {bool} option.exist - Set to false to check whether element should not exist. Otherwise, true (default) to check visibility.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetPostTextBox();
|
||||
*/
|
||||
uiGetPostTextBox: typeof uiGetPostTextBox;
|
||||
|
||||
/**
|
||||
* Get reply textbox
|
||||
*
|
||||
* @param {bool} option.exist - Set to false to check whether element should not exist. Otherwise, true (default) to check visibility.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetReplyTextBox();
|
||||
*/
|
||||
uiGetReplyTextBox: typeof uiGetReplyTextBox;
|
||||
|
||||
getPost: typeof getPost;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
e2e-tests/cypress/tests/support/ui/post_dropdown_menu.d.ts
поставляемый
Обычный файл
39
e2e-tests/cypress/tests/support/ui/post_dropdown_menu.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiClickCopyLink`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Click on "Copy Link" of post dropdown menu and verifies if the link is copied into the clipboard
|
||||
* Created user has an option to log in after all are setup.
|
||||
* @param {string} permalink - permalink to verify if copied into the clipboard
|
||||
*
|
||||
* @example
|
||||
* const permalink = 'http://localhost:8065/team-name/pl/post-id';
|
||||
* cy.uiClickCopyLink(permalink);
|
||||
*/
|
||||
uiClickCopyLink(permalink: string, postId: string): Chainable;
|
||||
|
||||
/**
|
||||
* Click dropdown menu of a post by post ID.
|
||||
* @param {String} postId - post ID
|
||||
* @param {String} menuItem - e.g. "Pin to channel"
|
||||
* @param {String} location - 'CENTER' (default), 'SEARCH', RHS_ROOT, RHS_COMMENT
|
||||
*/
|
||||
uiClickPostDropdownMenu(postId: string, menuItem: string, location?: string): Chainable;
|
||||
}
|
||||
}
|
||||
32
e2e-tests/cypress/tests/support/ui/post_dropdown_menu.js
Обычный файл
32
e2e-tests/cypress/tests/support/ui/post_dropdown_menu.js
Обычный файл
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {stubClipboard} from '../../utils';
|
||||
|
||||
Cypress.Commands.add('uiClickCopyLink', (permalink, postId) => {
|
||||
stubClipboard().as('clipboard');
|
||||
|
||||
// * Verify initial state
|
||||
cy.get('@clipboard').its('contents').should('eq', '');
|
||||
|
||||
// # Click on "Copy Link"
|
||||
cy.get(`#CENTER_dropdown_${postId}`).should('be.visible').within(() => {
|
||||
cy.findByText('Copy Link').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify if it's called with correct link value
|
||||
cy.get('@clipboard').its('wasCalled').should('eq', true);
|
||||
cy.get('@clipboard').its('contents').should('eq', permalink);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiClickPostDropdownMenu', (postId, menuItem, location = 'CENTER') => {
|
||||
cy.clickPostDotMenu(postId, location);
|
||||
cy.findAllByTestId(`post-menu-${postId}`).eq(0).should('be.visible');
|
||||
cy.findByText(menuItem).scrollIntoView().should('be.visible').click({force: true});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiPostDropdownMenuShortcut', (postId, menuText, shortcutKey, location = 'CENTER') => {
|
||||
cy.clickPostDotMenu(postId, location);
|
||||
cy.findByText(menuText).scrollIntoView().should('be.visible');
|
||||
cy.get('body').type(shortcutKey);
|
||||
});
|
||||
22
e2e-tests/cypress/tests/support/ui/search.js
Обычный файл
22
e2e-tests/cypress/tests/support/ui/search.js
Обычный файл
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiSearchPosts', (searchTerm) => {
|
||||
// # Enter the search terms and hit enter to start the search
|
||||
cy.get('#searchBox').clear().type(searchTerm).type('{enter}');
|
||||
|
||||
// * Wait for the RHS to open and the search results to appear
|
||||
cy.contains('.sidebar--right__header', 'Search Results').should('be.visible');
|
||||
cy.get('#searchContainer .LoadingSpinner').should('not.exist');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiJumpToSearchResult', (postId) => {
|
||||
// # Find the post in the search results and click Jump
|
||||
cy.get(`#searchResult_${postId}`).contains('a', 'Jump').click();
|
||||
|
||||
// * Verify the URL changes to the permalink URL
|
||||
cy.url().should((url) => url.endsWith(`/${postId}`));
|
||||
|
||||
// * Verify that the permalinked post is highlighted in the center channel
|
||||
cy.get(`#post_${postId}.post--highlight`).should('be.visible');
|
||||
});
|
||||
280
e2e-tests/cypress/tests/support/ui/sidebar_left.ts
Обычный файл
280
e2e-tests/cypress/tests/support/ui/sidebar_left.ts
Обычный файл
@@ -0,0 +1,280 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChainableT} from '../../types';
|
||||
|
||||
Cypress.Commands.add('uiGetLHS', () => {
|
||||
return cy.get('#SidebarContainer').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetLHSHeader', () => {
|
||||
return cy.uiGetLHS().
|
||||
find('.SidebarHeaderMenuWrapper').
|
||||
should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenTeamMenu', (item = '') => {
|
||||
// # Click on LHS header
|
||||
cy.uiGetLHSHeader().click();
|
||||
|
||||
if (!item) {
|
||||
// # Return the menu if no item is passed
|
||||
return cy.uiGetLHSTeamMenu();
|
||||
}
|
||||
|
||||
// # Click on a particular item
|
||||
return cy.uiGetLHSTeamMenu().
|
||||
findByText(item).
|
||||
scrollIntoView().
|
||||
should('be.visible').
|
||||
click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetLHSAddChannelButton', () => {
|
||||
return cy.uiGetLHS().
|
||||
findByRole('button', {name: 'Add Channel Dropdown'});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetLHSTeamMenu', () => {
|
||||
return cy.uiGetLHS().find('#sidebarDropdownMenu');
|
||||
});
|
||||
|
||||
function uiOpenSystemConsoleMenu(item = ''): ChainableT<JQuery> {
|
||||
// # Click on LHS header button
|
||||
cy.uiGetSystemConsoleButton().click();
|
||||
|
||||
if (!item) {
|
||||
// # Return the menu if no item is passed
|
||||
return cy.uiGetSystemConsoleMenu();
|
||||
}
|
||||
|
||||
// # Click on a particular item
|
||||
return cy.uiGetSystemConsoleMenu().
|
||||
findByText(item).
|
||||
scrollIntoView().
|
||||
should('be.visible').
|
||||
click();
|
||||
}
|
||||
|
||||
Cypress.Commands.add('uiOpenSystemConsoleMenu', uiOpenSystemConsoleMenu);
|
||||
|
||||
function uiGetSystemConsoleButton(): ChainableT<JQuery> {
|
||||
return cy.get('.admin-sidebar').
|
||||
findByRole('button', {name: 'Menu Icon'});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('uiGetSystemConsoleButton', uiGetSystemConsoleButton);
|
||||
|
||||
function uiGetSystemConsoleMenu(): ChainableT<JQuery> {
|
||||
return cy.get('.admin-sidebar').
|
||||
find('.dropdown-menu').
|
||||
should('be.visible');
|
||||
}
|
||||
|
||||
Cypress.Commands.add('uiGetSystemConsoleMenu', uiGetSystemConsoleMenu);
|
||||
|
||||
Cypress.Commands.add('uiGetLhsSection', (section) => {
|
||||
if (section === 'UNREADS') {
|
||||
return cy.findByText(section).
|
||||
parent().
|
||||
parent().
|
||||
parent();
|
||||
}
|
||||
|
||||
return cy.findAllByRole('button', {name: section}).
|
||||
first().
|
||||
parent().
|
||||
parent().
|
||||
parent();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiBrowseOrCreateChannel', (item) => {
|
||||
cy.findByRole('button', {name: 'Add Channel Dropdown'}).
|
||||
should('be.visible').
|
||||
click();
|
||||
cy.get('.dropdown-menu').should('be.visible');
|
||||
|
||||
if (item) {
|
||||
cy.findByRole('menuitem', {name: item});
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiAddDirectMessage', () => {
|
||||
return cy.findByRole('button', {name: 'Write a direct message'});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetFindChannels', () => {
|
||||
return cy.get('#lhsNavigator').findByRole('button', {name: 'Find Channels'});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenFindChannels', () => {
|
||||
cy.uiGetFindChannels().click();
|
||||
});
|
||||
|
||||
function uiGetSidebarThreadsButton(): ChainableT<JQuery> {
|
||||
return cy.get('#sidebar-threads-button').should('be.visible');
|
||||
}
|
||||
Cypress.Commands.add('uiGetSidebarThreadsButton', uiGetSidebarThreadsButton);
|
||||
|
||||
function uiGetSidebarInsightsButton(): ChainableT<JQuery> {
|
||||
return cy.get('#sidebar-insights-button').should('be.visible');
|
||||
}
|
||||
Cypress.Commands.add('uiGetSidebarInsightsButton', uiGetSidebarInsightsButton);
|
||||
|
||||
Cypress.Commands.add('uiGetChannelSidebarMenu', (channelName, isChannelId = false) => {
|
||||
cy.uiGetLHS().within(() => {
|
||||
if (isChannelId) {
|
||||
cy.get(`#sidebarItem_${channelName}`).should('be.visible').find('button').should('exist').click({force: true});
|
||||
} else {
|
||||
cy.findByText(channelName).should('be.visible').parents('a').find('button').should('exist').click({force: true});
|
||||
}
|
||||
});
|
||||
|
||||
return cy.findByRole('menu', {name: 'Edit channel menu'}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiClickSidebarItem', (name) => {
|
||||
cy.uiGetSidebarItem(name).click({force: true});
|
||||
|
||||
if (name === 'threads') {
|
||||
cy.get('body').then((body) => {
|
||||
if (body.find('#genericModalLabel').length > 0) {
|
||||
cy.uiCloseModal('A new way to view and follow threads');
|
||||
}
|
||||
});
|
||||
cy.findByRole('heading', {name: 'Followed threads'});
|
||||
} else {
|
||||
cy.findAllByTestId('postView').should('be.visible');
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetSidebarItem', (channelName) => {
|
||||
return cy.get(`#sidebarItem_${channelName}`);
|
||||
});
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Get LHS
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetLHS();
|
||||
*/
|
||||
uiGetLHS(): Chainable;
|
||||
|
||||
/**
|
||||
* Get LHS header
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetLHSHeader().click();
|
||||
*/
|
||||
uiGetLHSHeader(): Chainable;
|
||||
|
||||
/**
|
||||
* Open team menu
|
||||
*
|
||||
* @param {string} item - ex. 'Invite People', 'Team Settings', etc.
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenTeamMenu();
|
||||
*/
|
||||
uiOpenTeamMenu(item?: string): Chainable;
|
||||
|
||||
/**
|
||||
* Get LHS add channel button
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetLHSAddChannelButton().click();
|
||||
*/
|
||||
uiGetLHSAddChannelButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get LHS team menu
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetLHSTeamMenu().should('not.exist);
|
||||
*/
|
||||
uiGetLHSTeamMenu(): Chainable;
|
||||
|
||||
/**
|
||||
* Get LHS section
|
||||
* @param {string} section - section such as UNREADS, CHANNELS, FAVORITES, DIRECT MESSAGES and other custom category
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetLhsSection('CHANNELS');
|
||||
*/
|
||||
uiGetLhsSection(section: string): Chainable;
|
||||
|
||||
/**
|
||||
* Open menu to browse or create channel
|
||||
* @param {string} item - dropdown menu. If set, it will do click action.
|
||||
*
|
||||
* @example
|
||||
* cy.uiBrowseOrCreateChannel('Browse Channels');
|
||||
*/
|
||||
uiBrowseOrCreateChannel(item: string): Chainable;
|
||||
|
||||
/**
|
||||
* Get "+" button to write a direct message
|
||||
* @example
|
||||
* cy.uiAddDirectMessage();
|
||||
*/
|
||||
uiAddDirectMessage(): Chainable;
|
||||
|
||||
/**
|
||||
* Get find channels button
|
||||
* @example
|
||||
* cy.uiGetFindChannels();
|
||||
*/
|
||||
uiGetFindChannels(): Chainable;
|
||||
|
||||
/**
|
||||
* Open find channels
|
||||
* @example
|
||||
* cy.uiOpenFindChannels();
|
||||
*/
|
||||
uiOpenFindChannels(): Chainable;
|
||||
|
||||
/**
|
||||
* Open menu of a channel in the sidebar
|
||||
* @param {string} channelName - name of channel, ex. 'town-square'
|
||||
* @param {boolean} isChannelId - default false. If true, it will use channel id instead of channel name
|
||||
* @example
|
||||
* cy.uiGetChannelSidebarMenu('Town Square');
|
||||
* cy.uiGetChannelSidebarMenu('user1212__user333', true);
|
||||
*/
|
||||
uiGetChannelSidebarMenu(channelName: string, isChannelId?: boolean): Chainable;
|
||||
|
||||
/**
|
||||
* Click sidebar item by channel or thread name
|
||||
* @param {string} name - channel name for channels, and threads for Global Threads
|
||||
*
|
||||
* @example
|
||||
* cy.uiClickSidebarItem('town-square');
|
||||
*/
|
||||
uiClickSidebarItem(name: string): Chainable;
|
||||
|
||||
/**
|
||||
* Get sidebar item by channel or thread name
|
||||
* @param {string} name - channel name for channels, and threads for Global Threads
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetSidebarItem('town-square').find('.badge').should('be.visible');
|
||||
*/
|
||||
uiGetSidebarItem(name: string): Chainable;
|
||||
|
||||
uiOpenSystemConsoleMenu: typeof uiOpenSystemConsoleMenu;
|
||||
|
||||
uiGetSystemConsoleButton: typeof uiGetSystemConsoleButton;
|
||||
|
||||
uiGetSystemConsoleMenu: typeof uiGetSystemConsoleMenu;
|
||||
|
||||
uiGetSidebarThreadsButton: typeof uiGetSidebarThreadsButton;
|
||||
|
||||
uiGetSidebarInsightsButton: typeof uiGetSidebarInsightsButton;
|
||||
}
|
||||
}
|
||||
}
|
||||
108
e2e-tests/cypress/tests/support/ui/sidebar_right.d.ts
поставляемый
Обычный файл
108
e2e-tests/cypress/tests/support/ui/sidebar_right.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiGetRHS`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Get RHS container
|
||||
*
|
||||
* @param {bool} option.visible - Set to false to check whether RHS is not visible. Otherwise, true (default) to check visibility.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetRHS();
|
||||
*/
|
||||
uiGetRHS(option?: Record<string, boolean>): Chainable;
|
||||
|
||||
/**
|
||||
* Close RHS
|
||||
*
|
||||
* @example
|
||||
* cy.uiCloseRHS();
|
||||
*/
|
||||
uiCloseRHS(): Chainable;
|
||||
|
||||
/**
|
||||
* Expand RHS
|
||||
*
|
||||
* @example
|
||||
* cy.uiExpandRHS();
|
||||
*/
|
||||
uiExpandRHS(): Chainable;
|
||||
|
||||
/**
|
||||
* Verify if RHS is expanded
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetRHS().isExpanded();
|
||||
*/
|
||||
isExpanded(): Chainable;
|
||||
|
||||
/**
|
||||
* Get "Reply" button
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetReply();
|
||||
*/
|
||||
uiGetReply(): Chainable;
|
||||
|
||||
/**
|
||||
* Reply by clicking "Reply" button
|
||||
*
|
||||
* @example
|
||||
* cy.uiReply();
|
||||
*/
|
||||
uiReply(): Chainable;
|
||||
|
||||
/**
|
||||
* Get RHS container
|
||||
*
|
||||
* @param {bool} option.visible - Set to false to check whether Search container at RHS is not visible. Otherwise, true (default) to check visibility.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetRHSSearchContainer();
|
||||
*/
|
||||
uiGetRHSSearchContainer(option: Record<string, boolean>): Chainable;
|
||||
|
||||
/**
|
||||
* Get file filter button from RHS.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetFileFilterButton().click();
|
||||
*/
|
||||
uiGetFileFilterButton(): Chainable;
|
||||
|
||||
/**
|
||||
* Get file filter menu from RHS
|
||||
*
|
||||
* @param {bool} option.exist - Set to false to check whether file filter menu should not exist at RHS. Otherwise, true (default) to check visibility.
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetFileFilterMenu();
|
||||
*/
|
||||
uiGetFileFilterMenu(): Chainable;
|
||||
|
||||
/**
|
||||
* Open file filter menu from RHS
|
||||
* @param {string} item - such as `'Documents'`, `'Spreadsheets'`, `'Presentations'`, `'Code'`, `'Images'`, `'Audio'` and `'Videos'`.
|
||||
* @return the file filter menu
|
||||
*
|
||||
* @example
|
||||
* cy.uiOpenFileFilterMenu();
|
||||
*/
|
||||
uiOpenFileFilterMenu(): Chainable;
|
||||
}
|
||||
}
|
||||
74
e2e-tests/cypress/tests/support/ui/sidebar_right.js
Обычный файл
74
e2e-tests/cypress/tests/support/ui/sidebar_right.js
Обычный файл
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiGetRHS', (options = {visible: true}) => {
|
||||
if (options.visible) {
|
||||
return cy.get('#sidebar-right').should('be.visible');
|
||||
}
|
||||
|
||||
return cy.get('#sidebar-right').should('not.be.exist');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiCloseRHS', () => {
|
||||
cy.findByLabelText('Close Sidebar Icon').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiExpandRHS', () => {
|
||||
cy.findByLabelText('Expand').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('isExpanded', {prevSubject: true}, (subject) => {
|
||||
return cy.get(subject).should('have.class', 'sidebar--right--expanded');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetReply', () => {
|
||||
return cy.get('#sidebar-right').findByTestId('SendMessageButton');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiReply', () => {
|
||||
cy.uiGetReply().click();
|
||||
});
|
||||
|
||||
// Sidebar search container
|
||||
|
||||
Cypress.Commands.add('uiGetRHSSearchContainer', (options = {visible: true}) => {
|
||||
if (options.visible) {
|
||||
return cy.get('#searchContainer').should('be.visible');
|
||||
}
|
||||
|
||||
return cy.get('#searchContainer').should('not.exist');
|
||||
});
|
||||
|
||||
// Sidebar files search
|
||||
|
||||
Cypress.Commands.add('uiGetFileFilterButton', () => {
|
||||
return cy.get('.FilesFilterMenu').should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiGetFileFilterMenu', (option = {exist: true}) => {
|
||||
if (option.exist) {
|
||||
return cy.get('.FilesFilterMenu').
|
||||
find('.dropdown-menu').
|
||||
should('be.visible');
|
||||
}
|
||||
|
||||
return cy.get('.FilesFilterMenu').
|
||||
find('.dropdown-menu').
|
||||
should('not.exist');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiOpenFileFilterMenu', (item = '') => {
|
||||
// # Click on file filter button
|
||||
cy.uiGetFileFilterButton().click();
|
||||
|
||||
if (!item) {
|
||||
// # Return the menu if no item is passed
|
||||
return cy.uiGetFileFilterMenu();
|
||||
}
|
||||
|
||||
// # Click on a particular item
|
||||
return cy.uiGetFileFilterMenu().
|
||||
findByText(item).
|
||||
should('be.visible').
|
||||
click();
|
||||
});
|
||||
41
e2e-tests/cypress/tests/support/ui/suggestion_list.d.ts
поставляемый
Обычный файл
41
e2e-tests/cypress/tests/support/ui/suggestion_list.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiCheckLicenseExists`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Verify user's at-mention in the suggestion list
|
||||
* @param {UserProfile} user - user object
|
||||
* @param {boolean} isSelected - check if user is selected with false as default
|
||||
* @param {string} sectionDividerName - name of the section in suggestion list, ex. "Channel Members"
|
||||
*
|
||||
* @example
|
||||
* cy.uiVerifyAtMentionInSuggestionList(user, true, 'Channel Members');
|
||||
*/
|
||||
uiVerifyAtMentionInSuggestionList(user: UserProfile, isSelected: boolean, sectionDividerName?: string): Chainable;
|
||||
|
||||
/**
|
||||
* Verify user's at-mention suggestion
|
||||
* @param {UserProfile} user - user object
|
||||
* @param {boolean} isSelected - check if user is selected with false as default
|
||||
*
|
||||
* @example
|
||||
* cy.uiVerifyAtMentionSuggestion(user, true);
|
||||
*/
|
||||
uiVerifyAtMentionSuggestion(user: UserProfile, isSelected?: boolean): Chainable;
|
||||
}
|
||||
}
|
||||
36
e2e-tests/cypress/tests/support/ui/suggestion_list.js
Обычный файл
36
e2e-tests/cypress/tests/support/ui/suggestion_list.js
Обычный файл
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiVerifyAtMentionInSuggestionList', (user, isSelected = false, sectionDividerName = null) => {
|
||||
// * Verify that the suggestion list is open and visible
|
||||
return cy.get('#suggestionList').should('be.visible').within(() => {
|
||||
if (sectionDividerName) {
|
||||
// * Verify the section name is as expected
|
||||
cy.get('.suggestion-list__divider').findByText(sectionDividerName).should('be.visible');
|
||||
cy.get('.suggestion-list__divider').next().findByTestId(`mentionSuggestion_${user.username}`).should('be.visible');
|
||||
}
|
||||
|
||||
// * Verify that the user is selected
|
||||
return cy.uiVerifyAtMentionSuggestion(user, isSelected);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiVerifyAtMentionSuggestion', (user, isSelected = false) => {
|
||||
const {
|
||||
username,
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
nickname,
|
||||
} = user;
|
||||
|
||||
// * Verify that the user is selected
|
||||
cy.findByTestId(`mentionSuggestion_${username}`).as('selectedMentionSuggestion').should('be.visible');
|
||||
if (isSelected) {
|
||||
cy.get('@selectedMentionSuggestion').should('have.class', 'suggestion--selected');
|
||||
}
|
||||
|
||||
cy.get('@selectedMentionSuggestion').findByText(`@${username}`).should('be.visible');
|
||||
cy.get('@selectedMentionSuggestion').findByText(`${firstName} ${lastName} (${nickname})`).should('be.visible');
|
||||
|
||||
return cy.findByTestId(`mentionSuggestion_${username}`);
|
||||
});
|
||||
44
e2e-tests/cypress/tests/support/ui/system.d.ts
поставляемый
Обычный файл
44
e2e-tests/cypress/tests/support/ui/system.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiCheckLicenseExists`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Verify license exists via admin console.
|
||||
*
|
||||
* @example
|
||||
* cy.uiCheckLicenseExists();
|
||||
*/
|
||||
uiCheckLicenseExists(): Chainable;
|
||||
|
||||
/**
|
||||
* Reset system scheme permissions via System Console
|
||||
*
|
||||
* @example
|
||||
* cy.uiResetPermissionsToDefault();
|
||||
*/
|
||||
uiResetPermissionsToDefault(): Chainable;
|
||||
|
||||
/**
|
||||
* Save settings located in System Console
|
||||
*
|
||||
* @example
|
||||
* cy.uiSaveConfig();
|
||||
*/
|
||||
uiSaveConfig(): Chainable;
|
||||
}
|
||||
}
|
||||
40
e2e-tests/cypress/tests/support/ui/system.js
Обычный файл
40
e2e-tests/cypress/tests/support/ui/system.js
Обычный файл
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../fixtures/timeouts';
|
||||
|
||||
Cypress.Commands.add('uiCheckLicenseExists', () => {
|
||||
// # Go to system admin then verify admin console URL, header, and content
|
||||
cy.visit('/admin_console/about/license');
|
||||
cy.url().should('include', '/admin_console/about/license');
|
||||
cy.get('.admin-console', {timeout: TIMEOUTS.HALF_MIN}).should('be.visible').within(() => {
|
||||
cy.get('.admin-console__header').should('be.visible').and('have.text', 'Edition and License');
|
||||
cy.get('.admin-console__content').should('be.visible').and('not.contain', 'undefined').and('not.contain', 'Invalid');
|
||||
cy.get('#remove-button').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiResetPermissionsToDefault', () => {
|
||||
// # Navigate to system scheme page
|
||||
cy.visit('/admin_console/user_management/permissions/system_scheme');
|
||||
|
||||
// # Click reset to defaults and confirm
|
||||
cy.findByTestId('resetPermissionsToDefault', {timeout: TIMEOUTS.HALF_MIN}).click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
cy.uiSaveConfig();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('uiSaveConfig', ({confirm = true} = {}) => {
|
||||
// # Save settings
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
if (confirm) {
|
||||
// # Wait until the UI shows the saving is done and revert the text to "Save"
|
||||
cy.waitUntil(() => cy.get('#saveSetting').then((el) => {
|
||||
return el[0].innerText === 'Save';
|
||||
}));
|
||||
} else {
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
}
|
||||
});
|
||||
26
e2e-tests/cypress/tests/support/ui/team.js
Обычный файл
26
e2e-tests/cypress/tests/support/ui/team.js
Обычный файл
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiInviteMemberToCurrentTeam', (username) => {
|
||||
// # Open member invite screen
|
||||
cy.uiOpenTeamMenu('Invite People');
|
||||
|
||||
// # Open members section if licensed for guest accounts
|
||||
cy.findByTestId('invitationModal').
|
||||
then((container) => container.find('[data-testid="inviteMembersLink"]')).
|
||||
then((link) => link && link.click());
|
||||
|
||||
// # Enter bot username and submit
|
||||
cy.get('.users-emails-input__control input').typeWithForce(username).as('input');
|
||||
cy.get('.users-emails-input__option ').contains(`@${username}`);
|
||||
cy.get('@input').typeWithForce('{enter}');
|
||||
cy.get('#inviteMembersButton').click();
|
||||
|
||||
// * Verify user invited to team
|
||||
cy.get('.invitation-modal-confirm--sent .InviteResultRow').
|
||||
should('contain.text', `@${username}`).
|
||||
and('contain.text', 'This member has been added to the team.');
|
||||
|
||||
// # Close, return
|
||||
cy.findByTestId('confirm-done').click();
|
||||
});
|
||||
30
e2e-tests/cypress/tests/support/ui/tooltip.d.ts
поставляемый
Обычный файл
30
e2e-tests/cypress/tests/support/ui/tooltip.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `ui` prefix, e.g. `uiGetToolTip`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Get tooltip
|
||||
*
|
||||
* @param {string} text of the tooltip
|
||||
*
|
||||
* @example
|
||||
* cy.uiGetToolTip('text');
|
||||
*/
|
||||
uiGetToolTip(text: string): Chainable;
|
||||
}
|
||||
}
|
||||
6
e2e-tests/cypress/tests/support/ui/tooltip.js
Обычный файл
6
e2e-tests/cypress/tests/support/ui/tooltip.js
Обычный файл
@@ -0,0 +1,6 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
Cypress.Commands.add('uiGetToolTip', (text) => {
|
||||
cy.findByRole('tooltip').should('contain', text);
|
||||
});
|
||||
Ссылка в новой задаче
Block a user