Support E2E stress tests in run_tests.js (#29682)

* [skip ci] Adapt run_tests.js for stress testing
* [skip ci] Make channel_read_after_permalink_spec.js retry-able
* [skip ci] Fix ui_commands.ts fix
* [skip ci] Improve postMessageAndWait
* [skip ci] Fix unread_on_public_channel_spec.js
* [skip ci] Demote unread_on_public_channel_spec.js
* Update e2e-tests/README.md

Co-authored-by: Saturnino Abril <5334504+saturninoabril@users.noreply.github.com>

* [skip ci] Fix mesage_reply_bot_post_spec.js

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Saturnino Abril <5334504+saturninoabril@users.noreply.github.com>
Этот коммит содержится в:
Mario Vitale
2025-01-23 14:07:38 +01:00
коммит произвёл GitHub
родитель 7fb6901ad1
Коммит d3bd91843f
8 изменённых файлов: 51 добавлений и 15 удалений

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

@@ -32,6 +32,8 @@
* Exclude spec files with matching directory or filename pattern. Uses `find` command under the hood. It can be of multiple values separated by comma.
* E.g. "--exclude-file='channel'" will exclude files recursively under `channel` directory/s.
* E.g. "--exclude-file='*channel*'" will exclude files and files under directory/s recursively that matches the name with `*channel*`.
* --stress-test-count=[number of repeated executions]
* The amount of times to run each spec file for. If greater than 1, report how the percentage of successes over total runs for each spec.
*
* Environment:
@@ -83,8 +85,11 @@ async function runTests() {
const browser = BROWSER || 'chrome';
const headless = typeof HEADLESS === 'undefined' ? true : HEADLESS === 'true';
const platform = os.platform();
const stressTestCount = argv.stressTestCount > 1 ? argv.stressTestCount : 1;
const testPasses = {};
const {sortedFiles} = getSortedTestFiles(platform, browser, headless);
const sortedFilesObject = getSortedTestFiles(platform, browser, headless);
const sortedFiles = sortedFilesObject.sortedFiles.flatMap((el) => Array(stressTestCount).fill(el));
const numberOfTestFiles = sortedFiles.length;
if (!numberOfTestFiles) {
@@ -102,6 +107,13 @@ async function runTests() {
printMessage(sortedFiles, i, j + 1, count);
const testFile = sortedFiles[i];
var testFileAttempt = 1;
if (testFile in testPasses === false) {
testPasses[testFile] = {attempt: 1};
} else {
testPasses[testFile].attempt += 1;
testFileAttempt = testPasses[testFile].attempt;
}
const result = await cypress.run({
browser,
@@ -111,6 +123,7 @@ async function runTests() {
screenshotsFolder: `${MOCHAWESOME_REPORT_DIR}/screenshots`,
videosFolder: `${MOCHAWESOME_REPORT_DIR}/videos`,
trashAssetsBeforeRuns: false,
retries: stressTestCount > 1 ? 0 : 2,
},
env: {
firstTest: j === 0,
@@ -135,11 +148,22 @@ async function runTests() {
headless,
branch: BRANCH,
buildId: BUILD_ID,
testFileAttempt,
},
},
},
});
for (var testCase of result.runs[0].tests) {
var testCaseTitle = testCase.title.join(' - ');
if (testCaseTitle in testPasses[testFile] === false) {
testPasses[testFile][testCaseTitle] = 0;
}
if (testCase.state === 'passed') {
testPasses[testFile][testCaseTitle] += 1;
}
}
// Write test environment details once only
if (i === 0) {
const environment = {
@@ -155,6 +179,7 @@ async function runTests() {
writeJsonToFile(environment, 'environment.json', RESULTS_DIR);
}
}
writeJsonToFile(testPasses, 'testPasses.json', RESULTS_DIR);
}
function printMessage(testFiles, overallIndex, currentItem, lastItem) {

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

@@ -18,7 +18,7 @@ describe('Messaging', () => {
let testUser;
let otherUser;
before(() => {
beforeEach(() => {
cy.apiInitSetup().then(({team, channel, user}) => {
testTeam = team;
testChannel = channel;

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

@@ -144,7 +144,7 @@ describe('Messaging', () => {
cy.uiCloseRHS();
// * Verify that the reply is in the channel view with matching text
cy.get(`#post_${replyId}`).within(() => {
cy.get(`#post_${replyId}`).scrollIntoView().within(() => {
cy.findByTestId('post-link').should('be.visible').and('have.text', 'Commented on ' + bot.username + 'BOT\'s message: Hello message from ' + bot.username);
cy.get(`#postMessageText_${replyId}`).should('be.visible').and('have.text', replyMessage);
});

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

@@ -7,7 +7,6 @@
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @notifications
import * as TIMEOUTS from '../../../fixtures/timeouts';
@@ -18,7 +17,7 @@ describe('Notifications', () => {
let testTeam;
beforeEach(() => {
cy.apiInitSetup().then(({team, user}) => {
cy.apiAdminLogin().apiInitSetup().then(({team, user}) => {
testUser = user;
testTeam = team;
@@ -48,11 +47,6 @@ describe('Notifications', () => {
// # Go to test channel
cy.visit(`/${team.name}/channels/${channel.name}`);
// # Scroll above the last few messages
cy.get('div.post-list__dynamic', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').
scrollTo(0, '70%', {duration: TIMEOUTS.ONE_SEC}).
wait(TIMEOUTS.ONE_SEC);
// # scroll to the last channel
cy.get('#sidebar-left li').last().scrollIntoView();
});
@@ -66,7 +60,11 @@ describe('Notifications', () => {
// # Get last post and reply a message
cy.getLastPostId().then((postId) => {
// # Open the RHS reply form, then scroll above the last few messages
cy.clickPostCommentIcon(postId);
cy.get('div.post-list__dynamic', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').
scrollTo(0, '70%', {duration: TIMEOUTS.ONE_SEC}).
wait(TIMEOUTS.ONE_SEC);
const replyMessage = 'A reply to an older post';
cy.postMessageReplyInRHS(replyMessage);
});

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

@@ -98,7 +98,7 @@ function postMessageAndWait(textboxSelector: string, message: string, isComment
waitForCommentDraft(message);
}
cy.get(textboxSelector).should('have.value', message).type('{enter}').wait(TIMEOUTS.HALF_SEC);
cy.get(textboxSelector).should('have.value', message).focus().type('{enter}').wait(TIMEOUTS.HALF_SEC);
cy.get(textboxSelector).invoke('val').then((value: string) => {
if (value.length > 0 && value === message) {
@@ -325,12 +325,12 @@ function clickPostHeaderItem(postId: string, location: string, item: string) {
}
if (postId) {
cy.get(`#${idPrefix}_${postId}`).trigger('mouseover', {force: true});
cy.wait(TIMEOUTS.HALF_SEC).get(`#${location}_${item}_${postId}`).click({force: true});
cy.get(`#${idPrefix}_${postId}`).trigger('mouseover', {force: true}).
get(`#${location}_${item}_${postId}`).scrollIntoView().trigger('mouseover', {force: true}).click({force: true});
} else {
cy.getLastPostId().then((lastPostId) => {
cy.get(`#${idPrefix}_${lastPostId}`).trigger('mouseover', {force: true});
cy.wait(TIMEOUTS.HALF_SEC).get(`#${location}_${item}_${lastPostId}`).click({force: true});
cy.get(`#${idPrefix}_${lastPostId}`).trigger('mouseover', {force: true}).
get(`#${location}_${item}_${lastPostId}`).scrollIntoView().trigger('mouseover', {force: true}).click({force: true});
});
}
}