Enable Cypress and Playwright retries (#29056)

* Enable Cypress and Playwright retries
* Improve E2E commit status messages
* Demote unstable testcases, increase task timeout
Этот коммит содержится в:
Mario Vitale
2024-11-05 11:46:06 +01:00
коммит произвёл GitHub
родитель 4b9eb73bd2
Коммит 2975e529d5
12 изменённых файлов: 82 добавлений и 81 удалений

6
.github/workflows/e2e-tests-ci-template.yml поставляемый
Просмотреть файл

@@ -453,7 +453,11 @@ jobs:
fi fi
export TOTAL_SPECS=$(( PASSED + FAILED )) export TOTAL_SPECS=$(( PASSED + FAILED ))
export PASS_RATE=$(jq -r '100 * (env.PASSED | tonumber) / (env.TOTAL_SPECS | tonumber)' <<<'{}' | xargs -l printf '%.2f') export PASS_RATE=$(jq -r '100 * (env.PASSED | tonumber) / (env.TOTAL_SPECS | tonumber)' <<<'{}' | xargs -l printf '%.2f')
export COMMIT_STATUS_MESSAGE="Completed with pass rate: ${PASS_RATE}% (plus ${FAILED_EXPECTED} unrelated failures)" if [ "$FAILED" = "0" ]; then
export COMMIT_STATUS_MESSAGE="All test cases passed"
else
export COMMIT_STATUS_MESSAGE="${FAILED} test cases failed. Please check the workflow logs"
fi
echo "passed=${PASSED:?}" >> $GITHUB_OUTPUT echo "passed=${PASSED:?}" >> $GITHUB_OUTPUT
echo "failed=${FAILED:?}" >> $GITHUB_OUTPUT echo "failed=${FAILED:?}" >> $GITHUB_OUTPUT
echo "failed_expected=${FAILED_EXPECTED:?}" >> $GITHUB_OUTPUT echo "failed_expected=${FAILED_EXPECTED:?}" >> $GITHUB_OUTPUT

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

@@ -43,7 +43,7 @@ ${MME2E_DC_SERVER} exec -i -u "$MME2E_UID" -- playwright bash -c "cd e2e-tests/p
# Documentation on the results.json file: https://playwright.dev/docs/api/class-testcase#test-case-expected-status # Documentation on the results.json file: https://playwright.dev/docs/api/class-testcase#test-case-expected-status
# NB: the following line is needed only for compatibility reasons, to support RollingRelease tests for versions prior to v10.1.0 # NB: the following line is needed only for compatibility reasons, to support RollingRelease tests for versions prior to v10.1.0
# It can be removed after releases <=v10.0.x are phased out # It can be removed after releases <=v10.0.x are phased out
mv -v ../playwright/playwright-report/results.json ../playwright/results/results.json || true mv -v ../playwright/playwright-report/results.json ../playwright/results/results.json 2>/dev/null || true
jq -f /dev/stdin ../playwright/results/results.json > ../playwright/results/summary.json <<EOF jq -f /dev/stdin ../playwright/results/results.json > ../playwright/results/summary.json <<EOF
{ {
passed: .stats.expected, passed: .stats.expected,

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

@@ -9,8 +9,9 @@ export default defineConfig({
downloadsFolder: 'tests/downloads', downloadsFolder: 'tests/downloads',
fixturesFolder: 'tests/fixtures', fixturesFolder: 'tests/fixtures',
numTestsKeptInMemory: 0, numTestsKeptInMemory: 0,
retries: 2,
screenshotsFolder: 'tests/screenshots', screenshotsFolder: 'tests/screenshots',
taskTimeout: 20000, taskTimeout: 60000,
video: true, video: true,
videoCompression: true, videoCompression: true,
videosFolder: 'tests/videos', videosFolder: 'tests/videos',

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

@@ -7,7 +7,6 @@
// - Use element ID when selecting an element. Create one if none. // - Use element ID when selecting an element. Create one if none.
// *************************************************************** // ***************************************************************
// Stage: @prod
// Group: @channels @notifications // Group: @channels @notifications
describe('Notifications', () => { describe('Notifications', () => {

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

@@ -7,7 +7,6 @@
// - Use element ID when selecting an element. Create one if none. // - Use element ID when selecting an element. Create one if none.
// *************************************************************** // ***************************************************************
// Stage: @prod
// Group: @channels @channel // Group: @channels @channel
import {measurePerformance} from './utils.js'; import {measurePerformance} from './utils.js';

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

@@ -6,7 +6,6 @@
// - [*] indicates an assertion (e.g. * Check the title) // - [*] indicates an assertion (e.g. * Check the title)
// *************************************************************** // ***************************************************************
// Stage: @prod
// Group: @playbooks // Group: @playbooks
/* eslint-disable no-only-tests/no-only-tests */ /* eslint-disable no-only-tests/no-only-tests */

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

@@ -6,7 +6,6 @@
// - [*] indicates an assertion (e.g. * Check the title) // - [*] indicates an assertion (e.g. * Check the title)
// *************************************************************** // ***************************************************************
// Stage: @prod
// Group: @playbooks // Group: @playbooks
import {switchToChannel} from '../../../channels/mark_as_unread/helpers'; import {switchToChannel} from '../../../channels/mark_as_unread/helpers';

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

@@ -6,7 +6,6 @@
// - [*] indicates an assertion (e.g. * Check the title) // - [*] indicates an assertion (e.g. * Check the title)
// *************************************************************** // ***************************************************************
// Stage: @prod
// Group: @playbooks // Group: @playbooks
describe('channels > slash command > todo', {testIsolation: true}, () => { describe('channels > slash command > todo', {testIsolation: true}, () => {

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

@@ -12,6 +12,7 @@ export default defineConfig({
globalSetup: require.resolve('./global_setup'), globalSetup: require.resolve('./global_setup'),
forbidOnly: testConfig.isCI, forbidOnly: testConfig.isCI,
outputDir: './results/tests', outputDir: './results/tests',
retries: testConfig.isCI ? 2 : 0,
testDir: 'tests', testDir: 'tests',
timeout: duration.one_min, timeout: duration.one_min,
workers: testConfig.workers, workers: testConfig.workers,

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

@@ -3,7 +3,7 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
test('Base channel accessibility', async ({pw, pages, axe}) => { test.fixme('Base channel accessibility', async ({pw, pages, axe}) => {
// # Create and sign in a new user // # Create and sign in a new user
const {user} = await pw.initSetup(); const {user} = await pw.initSetup();

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

@@ -3,95 +3,95 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
test('MM-T5445 Should search, select and post correct Gif when Gif picker is opened from center textbox', async ({ test.fixme(
pw, 'MM-T5445 Should search, select and post correct Gif when Gif picker is opened from center textbox',
pages, async ({pw, pages}) => {
}) => { const {user} = await pw.initSetup();
const {user} = await pw.initSetup();
// # Log in as a user in new browser context // # Log in as a user in new browser context
const {page} = await pw.testBrowser.login(user); const {page} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); const channelPage = new pages.ChannelsPage(page);
await channelPage.goto(); await channelPage.goto();
await channelPage.toBeVisible(); await channelPage.toBeVisible();
// # Open emoji/gif picker // # Open emoji/gif picker
await channelPage.centerView.postCreate.openEmojiPicker(); await channelPage.centerView.postCreate.openEmojiPicker();
await channelPage.emojiGifPickerPopup.toBeVisible(); await channelPage.emojiGifPickerPopup.toBeVisible();
// # Open gif tab // # Open gif tab
await channelPage.emojiGifPickerPopup.openGifTab(); await channelPage.emojiGifPickerPopup.openGifTab();
// # Search for gif // # Search for gif
await channelPage.emojiGifPickerPopup.searchGif('hello'); await channelPage.emojiGifPickerPopup.searchGif('hello');
// # Select the first gif // # Select the first gif
const {img: firstSearchGifResult, alt: altOfFirstSearchGifResult} = const {img: firstSearchGifResult, alt: altOfFirstSearchGifResult} =
await channelPage.emojiGifPickerPopup.getNthGif(0); await channelPage.emojiGifPickerPopup.getNthGif(0);
await firstSearchGifResult.click(); await firstSearchGifResult.click();
// # Send the selected gif as a message // # Send the selected gif as a message
await channelPage.centerView.postCreate.sendMessage(); await channelPage.centerView.postCreate.sendMessage();
// * Verify that last message has the gif // * Verify that last message has the gif
const lastPost = await channelPage.centerView.getLastPost(); const lastPost = await channelPage.centerView.getLastPost();
await lastPost.toBeVisible(); await lastPost.toBeVisible();
await expect(lastPost.body.getByLabel('file thumbnail')).toHaveAttribute('alt', altOfFirstSearchGifResult); await expect(lastPost.body.getByLabel('file thumbnail')).toHaveAttribute('alt', altOfFirstSearchGifResult);
}); },
);
test('MM-T5446 Should search, select and post correct Gif when Gif picker is opened from RHS textbox', async ({ test.fixme(
pw, 'MM-T5446 Should search, select and post correct Gif when Gif picker is opened from RHS textbox',
pages, async ({pw, pages}) => {
}) => { const {user} = await pw.initSetup();
const {user} = await pw.initSetup();
// # Log in as a user in new browser context // # Log in as a user in new browser context
const {page} = await pw.testBrowser.login(user); const {page} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); const channelPage = new pages.ChannelsPage(page);
await channelPage.goto(); await channelPage.goto();
await channelPage.toBeVisible(); await channelPage.toBeVisible();
// # Send a message // # Send a message
await channelPage.centerView.postCreate.postMessage('Message to open RHS'); await channelPage.centerView.postCreate.postMessage('Message to open RHS');
// # Open the last post sent in RHS // # Open the last post sent in RHS
const lastPost = await channelPage.centerView.getLastPost(); const lastPost = await channelPage.centerView.getLastPost();
await lastPost.hover(); await lastPost.hover();
await lastPost.postMenu.toBeVisible(); await lastPost.postMenu.toBeVisible();
await lastPost.postMenu.reply(); await lastPost.postMenu.reply();
const sidebarRight = channelPage.sidebarRight; const sidebarRight = channelPage.sidebarRight;
await sidebarRight.toBeVisible(); await sidebarRight.toBeVisible();
// # Send a message in the thread // # Send a message in the thread
await sidebarRight.postCreate.toBeVisible(); await sidebarRight.postCreate.toBeVisible();
await sidebarRight.postCreate.writeMessage('Replying to a thread'); await sidebarRight.postCreate.writeMessage('Replying to a thread');
await sidebarRight.postCreate.sendMessage(); await sidebarRight.postCreate.sendMessage();
// # Open emoji/gif picker // # Open emoji/gif picker
await sidebarRight.postCreate.openEmojiPicker(); await sidebarRight.postCreate.openEmojiPicker();
await channelPage.emojiGifPickerPopup.toBeVisible(); await channelPage.emojiGifPickerPopup.toBeVisible();
// # Open gif tab // # Open gif tab
await channelPage.emojiGifPickerPopup.openGifTab(); await channelPage.emojiGifPickerPopup.openGifTab();
// # Search for gif // # Search for gif
await channelPage.emojiGifPickerPopup.searchGif('hello'); await channelPage.emojiGifPickerPopup.searchGif('hello');
// # Select the first gif // # Select the first gif
const {img: firstSearchGifResult, alt: altOfFirstSearchGifResult} = const {img: firstSearchGifResult, alt: altOfFirstSearchGifResult} =
await channelPage.emojiGifPickerPopup.getNthGif(0); await channelPage.emojiGifPickerPopup.getNthGif(0);
await firstSearchGifResult.click(); await firstSearchGifResult.click();
// # Send the selected gif as a message in the thread // # Send the selected gif as a message in the thread
await sidebarRight.postCreate.sendMessage(); await sidebarRight.postCreate.sendMessage();
// * Verify that last message has the gif // * Verify that last message has the gif
const lastPostInRHS = await sidebarRight.getLastPost(); const lastPostInRHS = await sidebarRight.getLastPost();
await lastPostInRHS.toBeVisible(); await lastPostInRHS.toBeVisible();
await expect(lastPostInRHS.body.getByLabel('file thumbnail')).toHaveAttribute('alt', altOfFirstSearchGifResult); await expect(lastPostInRHS.body.getByLabel('file thumbnail')).toHaveAttribute('alt', altOfFirstSearchGifResult);
}); },
);

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

@@ -3,7 +3,7 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
test('Intro to channel as regular user', async ({pw, pages, browserName, viewport}, testInfo) => { test.fixme('Intro to channel as regular user', async ({pw, pages, browserName, viewport}, testInfo) => {
// Create and sign in a new user // Create and sign in a new user
const {user} = await pw.initSetup(); const {user} = await pw.initSetup();