E2E/Playwright: Instantiate page in pw (#29765)

* instantiate page in pw

* update spec

* fix storage key and require user when logging in via API

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Saturnino Abril
2025-01-14 12:30:42 +08:00
коммит произвёл GitHub
родитель 20e9c6aa3e
Коммит 90e3d2833e
35 изменённых файлов: 554 добавлений и 591 удалений

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

@@ -41,15 +41,6 @@ export default defineConfig({
trace: 'off', trace: 'off',
video: 'retain-on-failure', video: 'retain-on-failure',
actionTimeout: duration.half_min, actionTimeout: duration.half_min,
storageState: {
cookies: [],
origins: [
{
origin: testConfig.baseURL,
localStorage: [{name: '__landingPageSeen__', value: 'true'}],
},
],
},
}, },
projects: [ projects: [
{ {
@@ -57,14 +48,14 @@ export default defineConfig({
use: { use: {
browserName: 'chromium', browserName: 'chromium',
...devices['iPad Pro 11'], ...devices['iPad Pro 11'],
permissions: ['notifications'], permissions: ['notifications', 'clipboard-read', 'clipboard-write'],
}, },
}, },
{ {
name: 'chrome', name: 'chrome',
use: { use: {
browserName: 'chromium', browserName: 'chromium',
permissions: ['notifications'], permissions: ['notifications', 'clipboard-read', 'clipboard-write'],
viewport: {width: 1280, height: 1024}, viewport: {width: 1280, height: 1024},
}, },
}, },

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

@@ -7,6 +7,7 @@ import {request, Browser, BrowserContext} from '@playwright/test';
import {UserProfile} from '@mattermost/types/users'; import {UserProfile} from '@mattermost/types/users';
import testConfig from '@e2e-test.config'; import testConfig from '@e2e-test.config';
import pages from '@e2e-support/ui/pages';
export class TestBrowser { export class TestBrowser {
readonly browser: Browser; readonly browser: Browser;
@@ -17,7 +18,7 @@ export class TestBrowser {
this.context = null; this.context = null;
} }
async login(user: UserProfile | null) { async login(user: UserProfile) {
const options = {storageState: ''}; const options = {storageState: ''};
if (user) { if (user) {
// Log in via API request and save user storage // Log in via API request and save user storage
@@ -29,9 +30,14 @@ export class TestBrowser {
const context = await this.browser.newContext(options); const context = await this.browser.newContext(options);
const page = await context.newPage(); const page = await context.newPage();
const channelsPage = new pages.ChannelsPage(page);
const systemConsolePage = new pages.SystemConsolePage(page);
const scheduledDraftPage = new pages.ScheduledDraftPage(page);
const draftPage = new pages.DraftPage(page);
this.context = context; this.context = context;
return {context, page}; return {context, page, channelsPage, systemConsolePage, scheduledDraftPage, draftPage};
} }
async close() { async close() {

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

@@ -20,6 +20,9 @@ export async function initSetup({
try { try {
// Login the admin user via API // Login the admin user via API
const {adminClient, adminUser} = await getAdminClient(); const {adminClient, adminUser} = await getAdminClient();
if (!adminUser) {
throw new Error('Failed to setup admin: Admin user not found.');
}
if (!adminClient) { if (!adminClient) {
throw new Error( throw new Error(
"Failed to setup admin: Check that you're able to access the server using the same admin credential.", "Failed to setup admin: Check that you're able to access the server using the same admin credential.",

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

@@ -6,16 +6,16 @@ import {TestBrowser} from './browser_context';
import {shouldHaveCallsEnabled, shouldHaveFeatureFlag, shouldRunInLinux, ensureLicense, skipIfNoLicense} from './flag'; import {shouldHaveCallsEnabled, shouldHaveFeatureFlag, shouldRunInLinux, ensureLicense, skipIfNoLicense} from './flag';
import {initSetup, getAdminClient} from './server'; import {initSetup, getAdminClient} from './server';
import {hideDynamicChannelsContent, waitForAnimationEnd, waitUntil} from './test_action'; import {hideDynamicChannelsContent, waitForAnimationEnd, waitUntil} from './test_action';
import {pages} from './ui/pages'; import pages from './ui/pages';
import {matchSnapshot} from './visual'; import {matchSnapshot} from './visual';
import {stubNotification, waitForNotification} from './mock_browser_api'; import {stubNotification, waitForNotification} from './mock_browser_api';
import {duration} from './util';
export {expect} from '@playwright/test'; export {expect} from '@playwright/test';
type ExtendedFixtures = { type ExtendedFixtures = {
axe: AxeBuilderExtended; axe: AxeBuilderExtended;
pw: PlaywrightExtended; pw: PlaywrightExtended;
pages: typeof pages;
}; };
type AxeBuilderOptions = { type AxeBuilderOptions = {
@@ -29,15 +29,11 @@ export const test = base.extend<ExtendedFixtures>({
const ab = new AxeBuilderExtended(); const ab = new AxeBuilderExtended();
await use(ab); await use(ab);
}, },
pw: async ({browser}, use) => { pw: async ({browser, page, isMobile}, use) => {
const pw = new PlaywrightExtended(browser); const pw = new PlaywrightExtended(browser, page, isMobile);
await use(pw); await use(pw);
await pw.testBrowser.close(); await pw.testBrowser.close();
}, },
// eslint-disable-next-line no-empty-pattern
pages: async ({}, use) => {
await use(pages);
},
}); });
class PlaywrightExtended { class PlaywrightExtended {
@@ -60,8 +56,11 @@ class PlaywrightExtended {
readonly waitForAnimationEnd; readonly waitForAnimationEnd;
readonly waitUntil; readonly waitUntil;
// ./ui/pages // unauthenticated page
readonly pages; readonly loginPage;
readonly landingLoginPage;
readonly signupPage;
readonly resetPasswordPage;
// ./visual // ./visual
readonly matchSnapshot; readonly matchSnapshot;
@@ -70,7 +69,9 @@ class PlaywrightExtended {
readonly stubNotification; readonly stubNotification;
readonly waitForNotification; readonly waitForNotification;
constructor(browser: Browser) { readonly hasSeenLandingPage;
constructor(browser: Browser, page: Page, isMobile: boolean) {
// ./browser_context // ./browser_context
this.testBrowser = new TestBrowser(browser); this.testBrowser = new TestBrowser(browser);
@@ -90,8 +91,11 @@ class PlaywrightExtended {
this.waitForAnimationEnd = waitForAnimationEnd; this.waitForAnimationEnd = waitForAnimationEnd;
this.waitUntil = waitUntil; this.waitUntil = waitUntil;
// ./ui/pages // unauthenticated page
this.pages = pages; this.loginPage = new pages.LoginPage(page);
this.landingLoginPage = new pages.LandingLoginPage(page, isMobile);
this.signupPage = new pages.SignupPage(page);
this.resetPasswordPage = new pages.ResetPasswordPage(page);
// ./visual // ./visual
this.matchSnapshot = matchSnapshot; this.matchSnapshot = matchSnapshot;
@@ -99,6 +103,12 @@ class PlaywrightExtended {
// ./mock_browser_api // ./mock_browser_api
this.stubNotification = stubNotification; this.stubNotification = stubNotification;
this.waitForNotification = waitForNotification; this.waitForNotification = waitForNotification;
this.hasSeenLandingPage = async () => {
// Visit the base URL to be able to set the localStorage
await page.goto('/');
return await waitUntilLocalStorageIsSet(page, '__landingPageSeen__', 'true');
};
} }
} }
@@ -142,3 +152,20 @@ class AxeBuilderExtended {
return JSON.stringify(fingerprints, null, 2); return JSON.stringify(fingerprints, null, 2);
} }
} }
async function waitUntilLocalStorageIsSet(page: Page, key: string, value: string, timeout = duration.ten_sec) {
await waitUntil(
() =>
page.evaluate(
({key, value}) => {
if (localStorage.getItem(key) === value) {
return true;
}
localStorage.setItem(key, value);
return false;
},
{key, value},
),
{timeout},
);
}

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

@@ -13,7 +13,7 @@ export default class ChannelsCenterView {
readonly header; readonly header;
readonly postCreate; readonly postCreate;
readonly scheduledDraftOptions; readonly scheduledDraftOptions;
readonly scheduledDraftChannelInfo; readonly postBoxIndicator;
readonly scheduledDraftChannelIcon; readonly scheduledDraftChannelIcon;
readonly scheduledDraftChannelInfoMessage; readonly scheduledDraftChannelInfoMessage;
readonly scheduledDraftChannelInfoMessageText; readonly scheduledDraftChannelInfoMessageText;
@@ -27,7 +27,7 @@ export default class ChannelsCenterView {
this.scheduledDraftOptions = new components.ChannelsPostCreate( this.scheduledDraftOptions = new components.ChannelsPostCreate(
container.locator('#dropdown_send_post_options'), container.locator('#dropdown_send_post_options'),
); );
this.scheduledDraftChannelInfo = container.locator('div.postBoxIndicator'); this.postBoxIndicator = container.locator('div.postBoxIndicator');
this.scheduledDraftChannelIcon = container.locator('#create_post i.icon-draft-indicator'); this.scheduledDraftChannelIcon = container.locator('#create_post i.icon-draft-indicator');
this.scheduledDraftChannelInfoMessage = container.locator('div.ScheduledPostIndicator span'); this.scheduledDraftChannelInfoMessage = container.locator('div.ScheduledPostIndicator span');
this.scheduledDraftChannelInfoMessageText = container.locator('span:has-text("Message scheduled for")'); this.scheduledDraftChannelInfoMessageText = container.locator('span:has-text("Message scheduled for")');
@@ -110,7 +110,7 @@ export default class ChannelsCenterView {
} }
async verifyscheduledDraftChannelInfo() { async verifyscheduledDraftChannelInfo() {
await this.scheduledDraftChannelInfo.isVisible(); await this.postBoxIndicator.isVisible();
await this.scheduledDraftChannelIcon.isVisible(); await this.scheduledDraftChannelIcon.isVisible();
const messageLocator = this.scheduledDraftChannelInfoMessage.first(); const messageLocator = this.scheduledDraftChannelInfoMessage.first();
await expect(messageLocator).toContainText('Message scheduled for'); await expect(messageLocator).toContainText('Message scheduled for');

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

@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {expect, Locator, Page} from '@playwright/test'; import {expect, Locator} from '@playwright/test';
/** /**
* This is the generic confirm modal that is used in the app. * This is the generic confirm modal that is used in the app.
@@ -15,11 +15,10 @@ export default class GenericConfirmModal {
readonly confirmButton: Locator; readonly confirmButton: Locator;
readonly cancelButton: Locator; readonly cancelButton: Locator;
constructor(page: Page, id?: string) { constructor(container: Locator) {
const modalId = `#confirmModal ${id}`.trim(); this.container = container;
this.container = page.locator(modalId); this.confirmButton = container.locator('#confirmModalButton');
this.confirmButton = page.locator('#confirmModalButton'); this.cancelButton = container.locator('#cancelModalButton');
this.cancelButton = page.locator('#cancelModalButton');
} }
async toBeVisible() { async toBeVisible() {

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

@@ -11,7 +11,7 @@ export default class ChannelsSidebarRight {
readonly closeButton; readonly closeButton;
readonly postCreate; readonly postCreate;
readonly rhsPostBody; readonly rhsPostBody;
readonly scheduledDraftChannelInfo; readonly postBoxIndicator;
readonly scheduledDraftChannelInfoMessage; readonly scheduledDraftChannelInfoMessage;
readonly scheduledDraftSeeAllLink; readonly scheduledDraftSeeAllLink;
readonly scheduledDraftChannelInfoMessageText; readonly scheduledDraftChannelInfoMessageText;
@@ -19,7 +19,7 @@ export default class ChannelsSidebarRight {
constructor(container: Locator) { constructor(container: Locator) {
this.container = container; this.container = container;
this.scheduledDraftChannelInfo = container.locator('div.postBoxIndicator'); this.postBoxIndicator = container.locator('div.postBoxIndicator');
this.scheduledDraftChannelInfoMessage = container.locator('div.ScheduledPostIndicator span'); this.scheduledDraftChannelInfoMessage = container.locator('div.ScheduledPostIndicator span');
this.scheduledDraftSeeAllLink = container.locator('a:has-text("See all scheduled messages")'); this.scheduledDraftSeeAllLink = container.locator('a:has-text("See all scheduled messages")');
this.scheduledDraftChannelInfoMessageText = container.locator('span:has-text("Message scheduled for")'); this.scheduledDraftChannelInfoMessageText = container.locator('span:has-text("Message scheduled for")');

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

@@ -21,4 +21,5 @@ const pages = {
DraftPage, DraftPage,
}; };
export {pages, ChannelsPage, LandingLoginPage, LoginPage, SignupPage, ScheduledDraftPage, DraftPage}; export {ChannelsPage, LandingLoginPage, LoginPage, SignupPage, ScheduledDraftPage, DraftPage};
export default pages;

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

@@ -3,14 +3,11 @@
import {expect, Page} from '@playwright/test'; import {expect, Page} from '@playwright/test';
import {AdminConfig} from '@mattermost/types/config';
import {UserProfile} from '@mattermost/types/users'; import {UserProfile} from '@mattermost/types/users';
import {components} from '@e2e-support/ui/components'; import {components} from '@e2e-support/ui/components';
export default class LoginPage { export default class LoginPage {
readonly adminConfig: AdminConfig;
readonly page: Page; readonly page: Page;
readonly title; readonly title;
@@ -18,6 +15,7 @@ export default class LoginPage {
readonly bodyCard; readonly bodyCard;
readonly loginInput; readonly loginInput;
readonly loginPlaceholder; readonly loginPlaceholder;
readonly loginWithAdLdapPlaceholder;
readonly passwordInput; readonly passwordInput;
readonly passwordToggleButton; readonly passwordToggleButton;
readonly signInButton; readonly signInButton;
@@ -30,19 +28,15 @@ export default class LoginPage {
readonly header; readonly header;
readonly footer; readonly footer;
constructor(page: Page, adminConfig: AdminConfig) { constructor(page: Page) {
this.page = page; this.page = page;
this.adminConfig = adminConfig;
const loginInputPlaceholder = adminConfig.LdapSettings.Enable
? 'Email, Username or AD/LDAP Username'
: 'Email or Username';
this.title = page.locator('h1:has-text("Log in to your account")'); this.title = page.locator('h1:has-text("Log in to your account")');
this.subtitle = page.locator('text=Collaborate with your team in real-time'); this.subtitle = page.locator('text=Collaborate with your team in real-time');
this.bodyCard = page.locator('.login-body-card-content'); this.bodyCard = page.locator('.login-body-card-content');
this.loginInput = page.locator('#input_loginId'); this.loginInput = page.locator('#input_loginId');
this.loginPlaceholder = page.locator(`[placeholder="${loginInputPlaceholder}"]`); this.loginPlaceholder = page.locator(`[placeholder="Email or Username"]`);
this.loginWithAdLdapPlaceholder = page.locator(`[placeholder="Email, Username or AD/LDAP Username"]`);
this.passwordInput = page.locator('#input_password-input'); this.passwordInput = page.locator('#input_password-input');
this.passwordToggleButton = page.getByRole('button', {name: 'Show or hide password'}); this.passwordToggleButton = page.getByRole('button', {name: 'Show or hide password'});
this.signInButton = page.locator('button:has-text("Log in")'); this.signInButton = page.locator('button:has-text("Log in")');

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

@@ -20,6 +20,10 @@ class SystemConsolePage {
readonly systemUsersDateRangeMenu; readonly systemUsersDateRangeMenu;
readonly systemUsersColumnToggleMenu; readonly systemUsersColumnToggleMenu;
readonly systemUsersActionMenus; readonly systemUsersActionMenus;
// modal
readonly confirmModal;
readonly exportModal;
readonly saveChangesModal; readonly saveChangesModal;
constructor(page: Page) { constructor(page: Page) {
@@ -47,6 +51,9 @@ class SystemConsolePage {
this.systemUsersActionMenus = Array.from(Array(10).keys()).map( this.systemUsersActionMenus = Array.from(Array(10).keys()).map(
(index) => new components.SystemUsersFilterMenu(page.locator(`#actionMenu-systemUsersTable-${index}`)), (index) => new components.SystemUsersFilterMenu(page.locator(`#actionMenu-systemUsersTable-${index}`)),
); );
this.confirmModal = new components.GenericConfirmModal(page.locator('#confirmModal'));
this.exportModal = new components.GenericConfirmModal(page.getByRole('dialog', {name: 'Export user data'}));
this.saveChangesModal = new components.SystemUsers(page.locator('div.modal-content')); this.saveChangesModal = new components.SystemUsers(page.locator('div.modal-content'));
} }

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

@@ -3,15 +3,14 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
test.fixme('Base channel accessibility', async ({pw, pages, axe}) => { test.fixme('Base channel accessibility', async ({pw, 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();
// # Log in a user in new browser context // # Log in a user in new browser context
const {page} = await pw.testBrowser.login(user); const {page, channelsPage} = await pw.testBrowser.login(user);
// # Visit a default channel page // # Visit a default channel page
const channelsPage = new pages.ChannelsPage(page);
await channelsPage.goto(); await channelsPage.goto();
await channelsPage.toBeVisible(); await channelsPage.toBeVisible();
await channelsPage.centerView.postCreate.postMessage('hello'); await channelsPage.centerView.postCreate.postMessage('hello');
@@ -24,17 +23,16 @@ test.fixme('Base channel accessibility', async ({pw, pages, axe}) => {
expect(accessibilityScanResults.violations).toHaveLength(0); expect(accessibilityScanResults.violations).toHaveLength(0);
}); });
test('Post actions tab support', async ({pw, pages, axe}) => { test('Post actions tab support', async ({pw, axe}) => {
// # Create and sign in a new user // # Create and sign in a new user
const {user, adminClient} = await pw.initSetup(); const {user, adminClient} = await pw.initSetup();
const config = await adminClient.getConfig(); const config = await adminClient.getConfig();
const license = await adminClient.getClientLicenseOld(); const license = await adminClient.getClientLicenseOld();
// # Log in a user in new browser context // # Log in a user in new browser context
const {page} = await pw.testBrowser.login(user); const {page, channelsPage} = await pw.testBrowser.login(user);
// # Visit a default channel page // # Visit a default channel page
const channelsPage = new pages.ChannelsPage(page);
await channelsPage.goto(); await channelsPage.goto();
await channelsPage.toBeVisible(); await channelsPage.toBeVisible();
await channelsPage.centerView.postCreate.postMessage('hello'); await channelsPage.centerView.postCreate.postMessage('hello');

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

@@ -3,77 +3,77 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
test('/login accessibility quick check', async ({pw, pages, page, axe}) => { test('/login accessibility quick check', async ({pw, axe}) => {
// Set up the page not to redirect to the landing page
await pw.hasSeenLandingPage();
// # Go to login page // # Go to login page
const {adminClient} = await pw.getAdminClient(); await pw.loginPage.goto();
const adminConfig = await adminClient.getConfig(); await pw.loginPage.toBeVisible();
const loginPage = new pages.LoginPage(page, adminConfig);
await loginPage.goto();
await loginPage.toBeVisible();
// # Analyze the page // # Analyze the page
const accessibilityScanResults = await axe.builder(loginPage.page).analyze(); const accessibilityScanResults = await axe.builder(pw.loginPage.page).analyze();
// * Should have no violation // * Should have no violation
expect(accessibilityScanResults.violations).toHaveLength(0); expect(accessibilityScanResults.violations).toHaveLength(0);
}); });
test('/login accessibility tab support', async ({pw, pages, page}) => { test('/login accessibility tab support', async ({pw}) => {
// Set up the page not to redirect to the landing page
await pw.hasSeenLandingPage();
// # Go to login page // # Go to login page
const {adminClient} = await pw.getAdminClient(); await pw.loginPage.goto();
const adminConfig = await adminClient.getConfig(); await pw.loginPage.toBeVisible();
const loginPage = new pages.LoginPage(page, adminConfig);
await loginPage.goto();
await loginPage.toBeVisible();
// * Should have focused at login input on page load // * Should have focused at login input on page load
expect(await loginPage.loginInput).toBeFocused(); expect(await pw.loginPage.loginInput).toBeFocused();
// * Should move focus to password input after tab // * Should move focus to password input after tab
await loginPage.loginInput.press('Tab'); await pw.loginPage.loginInput.press('Tab');
expect(await loginPage.passwordInput).toBeFocused(); expect(await pw.loginPage.passwordInput).toBeFocused();
// * Should move focus to password toggle button after tab // * Should move focus to password toggle button after tab
await loginPage.passwordInput.press('Tab'); await pw.loginPage.passwordInput.press('Tab');
expect(await loginPage.passwordToggleButton).toBeFocused(); expect(await pw.loginPage.passwordToggleButton).toBeFocused();
// * Should move focus to forgot password link after tab // * Should move focus to forgot password link after tab
await loginPage.passwordToggleButton.press('Tab'); await pw.loginPage.passwordToggleButton.press('Tab');
expect(await loginPage.forgotPasswordLink).toBeFocused(); expect(await pw.loginPage.forgotPasswordLink).toBeFocused();
// * Should move focus to forgot password link after tab // * Should move focus to forgot password link after tab
await loginPage.forgotPasswordLink.press('Tab'); await pw.loginPage.forgotPasswordLink.press('Tab');
expect(await loginPage.signInButton).toBeFocused(); expect(await pw.loginPage.signInButton).toBeFocused();
// * Should move focus to about link after tab // * Should move focus to about link after tab
await loginPage.signInButton.press('Tab'); await pw.loginPage.signInButton.press('Tab');
expect(await loginPage.footer.aboutLink).toBeFocused(); expect(await pw.loginPage.footer.aboutLink).toBeFocused();
// * Should move focus to privacy policy link after tab // * Should move focus to privacy policy link after tab
await loginPage.footer.aboutLink.press('Tab'); await pw.loginPage.footer.aboutLink.press('Tab');
expect(await loginPage.footer.privacyPolicyLink).toBeFocused(); expect(await pw.loginPage.footer.privacyPolicyLink).toBeFocused();
// * Should move focus to terms link after tab // * Should move focus to terms link after tab
await loginPage.footer.privacyPolicyLink.press('Tab'); await pw.loginPage.footer.privacyPolicyLink.press('Tab');
expect(await loginPage.footer.termsLink).toBeFocused(); expect(await pw.loginPage.footer.termsLink).toBeFocused();
// * Should move focus to help link after tab // * Should move focus to help link after tab
await loginPage.footer.termsLink.press('Tab'); await pw.loginPage.footer.termsLink.press('Tab');
expect(await loginPage.footer.helpLink).toBeFocused(); expect(await pw.loginPage.footer.helpLink).toBeFocused();
// # Move focus to login input // # Move focus to login input
await loginPage.loginInput.focus(); await pw.loginPage.loginInput.focus();
expect(await loginPage.loginInput).toBeFocused(); expect(await pw.loginPage.loginInput).toBeFocused();
// * Should move focus to login body after shift+tab // * Should move focus to login body after shift+tab
await loginPage.loginInput.press('Shift+Tab'); await pw.loginPage.loginInput.press('Shift+Tab');
expect(await loginPage.bodyCard).toBeFocused(); expect(await pw.loginPage.bodyCard).toBeFocused();
// * Should move focus to create account link after shift+tab // * Should move focus to create account link after shift+tab
await loginPage.bodyCard.press('Shift+Tab'); await pw.loginPage.bodyCard.press('Shift+Tab');
expect(await loginPage.createAccountLink).toBeFocused(); expect(await pw.loginPage.createAccountLink).toBeFocused();
// * Should move focus to login body after tab // * Should move focus to login body after tab
await loginPage.createAccountLink.press('Shift+Tab'); await pw.loginPage.createAccountLink.press('Shift+Tab');
expect(await loginPage.header.logo).toBeFocused(); expect(await pw.loginPage.header.logo).toBeFocused();
}); });

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

@@ -3,53 +3,59 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
test('/reset_password accessibility quick check', async ({pages, page, axe}) => { test('/reset_password accessibility quick check', async ({pw, axe}) => {
// Set up the page not to redirect to the landing page
await pw.hasSeenLandingPage();
// # Go to reset password page // # Go to reset password page
const resetPasswordPage = new pages.ResetPasswordPage(page); await pw.resetPasswordPage.goto();
await resetPasswordPage.goto(); await pw.resetPasswordPage.toBeVisible();
await resetPasswordPage.toBeVisible();
// # Analyze the page // # Analyze the page
const accessibilityScanResults = await axe.builder(resetPasswordPage.page, {disableColorContrast: true}).analyze(); const accessibilityScanResults = await axe
.builder(pw.resetPasswordPage.page, {disableColorContrast: true})
.analyze();
// * Should have no violation // * Should have no violation
expect(accessibilityScanResults.violations).toHaveLength(0); expect(accessibilityScanResults.violations).toHaveLength(0);
}); });
test('/reset_password accessibility tab support', async ({pages, page}) => { test('/reset_password accessibility tab support', async ({pw}) => {
// Set up the page not to redirect to the landing page
await pw.hasSeenLandingPage();
// # Go to reset password page // # Go to reset password page
const resetPasswordPage = new pages.ResetPasswordPage(page); await pw.resetPasswordPage.goto();
await resetPasswordPage.goto(); await pw.resetPasswordPage.toBeVisible();
await resetPasswordPage.toBeVisible();
// * Should have focused at email input on page load // * Should have focused at email input on page load
expect(await resetPasswordPage.emailInput).toBeFocused(); expect(await pw.resetPasswordPage.emailInput).toBeFocused();
// * Should move focus to reset button after tab // * Should move focus to reset button after tab
await resetPasswordPage.emailInput.press('Tab'); await pw.resetPasswordPage.emailInput.press('Tab');
expect(await resetPasswordPage.resetButton).toBeFocused(); expect(await pw.resetPasswordPage.resetButton).toBeFocused();
// * Should move focus to about link after tab // * Should move focus to about link after tab
await resetPasswordPage.resetButton.press('Tab'); await pw.resetPasswordPage.resetButton.press('Tab');
expect(await resetPasswordPage.footer.aboutLink).toBeFocused(); expect(await pw.resetPasswordPage.footer.aboutLink).toBeFocused();
// * Should move focus to privacy policy link after tab // * Should move focus to privacy policy link after tab
await resetPasswordPage.footer.aboutLink.press('Tab'); await pw.resetPasswordPage.footer.aboutLink.press('Tab');
expect(await resetPasswordPage.footer.privacyPolicyLink).toBeFocused(); expect(await pw.resetPasswordPage.footer.privacyPolicyLink).toBeFocused();
// * Should move focus to terms link after tab // * Should move focus to terms link after tab
await resetPasswordPage.footer.privacyPolicyLink.press('Tab'); await pw.resetPasswordPage.footer.privacyPolicyLink.press('Tab');
expect(await resetPasswordPage.footer.termsLink).toBeFocused(); expect(await pw.resetPasswordPage.footer.termsLink).toBeFocused();
// * Should move focus to help link after tab // * Should move focus to help link after tab
await resetPasswordPage.footer.termsLink.press('Tab'); await pw.resetPasswordPage.footer.termsLink.press('Tab');
expect(await resetPasswordPage.footer.helpLink).toBeFocused(); expect(await pw.resetPasswordPage.footer.helpLink).toBeFocused();
// # Move focus to email input // # Move focus to email input
await resetPasswordPage.emailInput.focus(); await pw.resetPasswordPage.emailInput.focus();
expect(await resetPasswordPage.emailInput).toBeFocused(); expect(await pw.resetPasswordPage.emailInput).toBeFocused();
// * Should move focus to back button after shift+tab // * Should move focus to back button after shift+tab
await resetPasswordPage.emailInput.press('Shift+Tab'); await pw.resetPasswordPage.emailInput.press('Shift+Tab');
expect(await resetPasswordPage.header.backButton).toBeFocused(); expect(await pw.resetPasswordPage.header.backButton).toBeFocused();
}); });

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

@@ -3,109 +3,113 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
test('/signup_user_complete accessibility quick check', async ({pages, page, axe}) => { test('/signup_user_complete accessibility quick check', async ({pw, axe}) => {
// Set up the page not to redirect to the landing page
await pw.hasSeenLandingPage();
// # Go to reset password page // # Go to reset password page
const signupPage = new pages.SignupPage(page); await pw.signupPage.goto();
await signupPage.goto(); await pw.signupPage.toBeVisible();
await signupPage.toBeVisible();
// # Analyze the page // # Analyze the page
const accessibilityScanResults = await axe const accessibilityScanResults = await axe
.builder(signupPage.page, {disableColorContrast: true, disableLinkInTextBlock: true}) .builder(pw.signupPage.page, {disableColorContrast: true, disableLinkInTextBlock: true})
.analyze(); .analyze();
// * Should have no violation // * Should have no violation
expect(accessibilityScanResults.violations).toHaveLength(0); expect(accessibilityScanResults.violations).toHaveLength(0);
}); });
test('/signup_user_complete accessibility tab support', async ({pages, page}, testInfo) => { test('/signup_user_complete accessibility tab support', async ({pw}, testInfo) => {
// Set up the page not to redirect to the landing page
await pw.hasSeenLandingPage();
// # Go to reset password page // # Go to reset password page
const signupPage = new pages.SignupPage(page); await pw.signupPage.goto();
await signupPage.goto(); await pw.signupPage.toBeVisible();
await signupPage.toBeVisible();
// * Should have focused at email input on page load // * Should have focused at email input on page load
expect(await signupPage.emailInput).toBeFocused(); expect(await pw.signupPage.emailInput).toBeFocused();
// * Should move focus to username input after tab // * Should move focus to username input after tab
await signupPage.emailInput.press('Tab'); await pw.signupPage.emailInput.press('Tab');
expect(await signupPage.usernameInput).toBeFocused(); expect(await pw.signupPage.usernameInput).toBeFocused();
// * Should move focus to password input after tab // * Should move focus to password input after tab
await signupPage.usernameInput.press('Tab'); await pw.signupPage.usernameInput.press('Tab');
expect(await signupPage.passwordInput).toBeFocused(); expect(await pw.signupPage.passwordInput).toBeFocused();
// * Should move focus to password toggle button after tab // * Should move focus to password toggle button after tab
await signupPage.passwordInput.press('Tab'); await pw.signupPage.passwordInput.press('Tab');
expect(await signupPage.passwordToggleButton).toBeFocused(); expect(await pw.signupPage.passwordToggleButton).toBeFocused();
// * Should move focus to newsletter checkbox after tab // * Should move focus to newsletter checkbox after tab
await signupPage.passwordToggleButton.press('Tab'); await pw.signupPage.passwordToggleButton.press('Tab');
expect(await signupPage.newsLetterCheckBox).toBeFocused(); expect(await pw.signupPage.newsLetterCheckBox).toBeFocused();
// * Should move focus to newsletter privacy policy link after tab // * Should move focus to newsletter privacy policy link after tab
await signupPage.newsLetterCheckBox.press('Tab'); await pw.signupPage.newsLetterCheckBox.press('Tab');
expect(await signupPage.newsLetterPrivacyPolicyLink).toBeFocused(); expect(await pw.signupPage.newsLetterPrivacyPolicyLink).toBeFocused();
// * Should move focus to newsletter unsubscribe link after tab // * Should move focus to newsletter unsubscribe link after tab
await signupPage.newsLetterPrivacyPolicyLink.press('Tab'); await pw.signupPage.newsLetterPrivacyPolicyLink.press('Tab');
expect(await signupPage.newsLetterUnsubscribeLink).toBeFocused(); expect(await pw.signupPage.newsLetterUnsubscribeLink).toBeFocused();
// * Should move focus to agreement terms of use link after tab // * Should move focus to agreement terms of use link after tab
await signupPage.newsLetterUnsubscribeLink.press('Tab'); await pw.signupPage.newsLetterUnsubscribeLink.press('Tab');
expect(await signupPage.agreementTermsOfUseLink).toBeFocused(); expect(await pw.signupPage.agreementTermsOfUseLink).toBeFocused();
// * Should move focus to agreement privacy policy link after tab // * Should move focus to agreement privacy policy link after tab
await signupPage.agreementTermsOfUseLink.press('Tab'); await pw.signupPage.agreementTermsOfUseLink.press('Tab');
expect(await signupPage.agreementPrivacyPolicyLink).toBeFocused(); expect(await pw.signupPage.agreementPrivacyPolicyLink).toBeFocused();
// * Should move focus to privacy policy link after tab // * Should move focus to privacy policy link after tab
await signupPage.footer.aboutLink.press('Tab'); await pw.signupPage.footer.aboutLink.press('Tab');
expect(await signupPage.footer.privacyPolicyLink).toBeFocused(); expect(await pw.signupPage.footer.privacyPolicyLink).toBeFocused();
// * Should move focus to terms link after tab // * Should move focus to terms link after tab
await signupPage.footer.privacyPolicyLink.press('Tab'); await pw.signupPage.footer.privacyPolicyLink.press('Tab');
expect(await signupPage.footer.termsLink).toBeFocused(); expect(await pw.signupPage.footer.termsLink).toBeFocused();
// * Should move focus to help link after tab // * Should move focus to help link after tab
await signupPage.footer.termsLink.press('Tab'); await pw.signupPage.footer.termsLink.press('Tab');
expect(await signupPage.footer.helpLink).toBeFocused(); expect(await pw.signupPage.footer.helpLink).toBeFocused();
// # Move focus to email input // # Move focus to email input
await signupPage.emailInput.focus(); await pw.signupPage.emailInput.focus();
expect(await signupPage.emailInput).toBeFocused(); expect(await pw.signupPage.emailInput).toBeFocused();
// * Should move focus to sign up body after shift+tab // * Should move focus to sign up body after shift+tab
await signupPage.emailInput.press('Shift+Tab'); await pw.signupPage.emailInput.press('Shift+Tab');
expect(await signupPage.bodyCard).toBeFocused(); expect(await pw.signupPage.bodyCard).toBeFocused();
// * Should move focus to sign up body after shift+tab // * Should move focus to sign up body after shift+tab
await signupPage.emailInput.press('Shift+Tab'); await pw.signupPage.emailInput.press('Shift+Tab');
expect(await signupPage.bodyCard).toBeFocused(); expect(await pw.signupPage.bodyCard).toBeFocused();
if (testInfo.project.name === 'ipad') { if (testInfo.project.name === 'ipad') {
// * Should move focus to header back button after shift+tab // * Should move focus to header back button after shift+tab
await signupPage.bodyCard.press('Shift+Tab'); await pw.signupPage.bodyCard.press('Shift+Tab');
expect(await signupPage.header.backButton).toBeFocused(); expect(await pw.signupPage.header.backButton).toBeFocused();
// * Should move focus to log in link after shift+tab // * Should move focus to log in link after shift+tab
await signupPage.header.backButton.press('Shift+Tab'); await pw.signupPage.header.backButton.press('Shift+Tab');
expect(await signupPage.loginLink).toBeFocused(); expect(await pw.signupPage.loginLink).toBeFocused();
// * Should move focus to header logo after shift+tab // * Should move focus to header logo after shift+tab
await signupPage.loginLink.press('Shift+Tab'); await pw.signupPage.loginLink.press('Shift+Tab');
expect(await signupPage.header.logo).toBeFocused(); expect(await pw.signupPage.header.logo).toBeFocused();
} else { } else {
// * Should move focus to log in link after shift+tab // * Should move focus to log in link after shift+tab
await signupPage.bodyCard.press('Shift+Tab'); await pw.signupPage.bodyCard.press('Shift+Tab');
expect(await signupPage.loginLink).toBeFocused(); expect(await pw.signupPage.loginLink).toBeFocused();
// * Should move focus to header back button after shift+tab // * Should move focus to header back button after shift+tab
await signupPage.loginLink.press('Shift+Tab'); await pw.signupPage.loginLink.press('Shift+Tab');
expect(await signupPage.header.backButton).toBeFocused(); expect(await pw.signupPage.header.backButton).toBeFocused();
// * Should move focus to header logo after shift+tab // * Should move focus to header logo after shift+tab
await signupPage.header.backButton.press('Shift+Tab'); await pw.signupPage.header.backButton.press('Shift+Tab');
expect(await signupPage.header.logo).toBeFocused(); expect(await pw.signupPage.header.logo).toBeFocused();
} }
}); });

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

@@ -22,7 +22,7 @@ const mimeType = 'image/png';
const {file} = getFileDataFromAsset(filename, mimeType); const {file} = getFileDataFromAsset(filename, mimeType);
const {blob} = getBlobDataFromAsset(filename, mimeType); const {blob} = getBlobDataFromAsset(filename, mimeType);
test.beforeAll(async ({pw}) => { test.beforeEach(async ({pw}) => {
({userClient, user, team} = await pw.initSetup()); ({userClient, user, team} = await pw.initSetup());
townSquareChannel = await userClient.getChannelByName(team.id, 'town-square'); townSquareChannel = await userClient.getChannelByName(team.id, 'town-square');
}); });

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

@@ -4,7 +4,7 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
import {createRandomUser} from '@e2e-support/server'; import {createRandomUser} from '@e2e-support/server';
test('MM-T53377 Profile popover should show correct fields after at-mention autocomplete', async ({pw, pages}) => { test('MM-T53377 Profile popover should show correct fields after at-mention autocomplete', async ({pw}) => {
// # Initialize with specific config and get admin client // # Initialize with specific config and get admin client
const {user, adminClient, team} = await pw.initSetup(); const {user, adminClient, team} = await pw.initSetup();
@@ -20,22 +20,21 @@ test('MM-T53377 Profile popover should show correct fields after at-mention auto
await adminClient.addToTeam(team.id, testUser2.id); await adminClient.addToTeam(team.id, testUser2.id);
// # Log in as user in new browser context // # Log in as user in new browser context
const {page} = await pw.testBrowser.login(user); const {channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
// # Send mentions quickly // # Send mentions quickly
await channelPage.centerView.postCreate.postMessage(`@${user.username} @${testUser2.username}`); await channelsPage.centerView.postCreate.postMessage(`@${user.username} @${testUser2.username}`);
// # Open profile popover for current user // # Open profile popover for current user
const firstMention = channelPage.centerView.container.getByText(`@${user.username}`, {exact: true}); const firstMention = channelsPage.centerView.container.getByText(`@${user.username}`, {exact: true});
await firstMention.click(); await firstMention.click();
// * Verify all fields are visible for current user // * Verify all fields are visible for current user
const popover = channelPage.userProfilePopover; const popover = channelsPage.userProfilePopover;
await expect(popover.container.getByText(`@${user.username}`)).toBeVisible(); await expect(popover.container.getByText(`@${user.username}`)).toBeVisible();
await expect(popover.container.getByText(`${user.first_name} ${user.last_name}`)).toBeVisible(); await expect(popover.container.getByText(`${user.first_name} ${user.last_name}`)).toBeVisible();
await expect(popover.container.getByText(user.email)).toBeVisible(); await expect(popover.container.getByText(user.email)).toBeVisible();
@@ -44,7 +43,7 @@ test('MM-T53377 Profile popover should show correct fields after at-mention auto
await popover.close(); await popover.close();
// # Open profile popover for other user // # Open profile popover for other user
const secondMention = channelPage.centerView.container.getByText(`@${testUser2.username}`, {exact: true}); const secondMention = channelsPage.centerView.container.getByText(`@${testUser2.username}`, {exact: true});
await secondMention.click(); await secondMention.click();
// * Verify only username is visible for other user // * Verify only username is visible for other user
@@ -55,14 +54,14 @@ test('MM-T53377 Profile popover should show correct fields after at-mention auto
await popover.close(); await popover.close();
// # Trigger autocomplete // # Trigger autocomplete
await channelPage.centerView.postCreate.writeMessage(`@${user.username}`); await channelsPage.centerView.postCreate.writeMessage(`@${user.username}`);
// # Wait for autocomplete // # Wait for autocomplete
const suggestionList = channelPage.centerView.postCreate.suggestionList; const suggestionList = channelsPage.centerView.postCreate.suggestionList;
await expect(suggestionList.getByText(`@${user.username}`)).toBeVisible(); await expect(suggestionList.getByText(`@${user.username}`)).toBeVisible();
// # Clear textbox // # Clear textbox
await channelPage.centerView.postCreate.writeMessage(''); await channelsPage.centerView.postCreate.writeMessage('');
// # Open profile popover for current user again // # Open profile popover for current user again
await firstMention.click(); await firstMention.click();

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

@@ -6,7 +6,6 @@ import {createRandomPost} from '@e2e-support/server/post';
test('MM-T5435_1 Global Drafts link in sidebar should be hidden when another user deleted root post and user removes the deleted post ', async ({ test('MM-T5435_1 Global Drafts link in sidebar should be hidden when another user deleted root post and user removes the deleted post ', async ({
pw, pw,
pages,
}) => { }) => {
const {adminClient, team, adminUser, user} = await pw.initSetup(); const {adminClient, team, adminUser, user} = await pw.initSetup();
@@ -26,14 +25,13 @@ test('MM-T5435_1 Global Drafts link in sidebar should be hidden when another use
); );
// # Log in as user in new browser context // # Log in as user in new browser context
const {page} = await pw.testBrowser.login(user); const {channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
const lastPostByAdmin = await channelPage.centerView.getLastPost(); const lastPostByAdmin = await channelsPage.centerView.getLastPost();
await lastPostByAdmin.toBeVisible(); await lastPostByAdmin.toBeVisible();
// # Open the last post sent by admin in RHS // # Open the last post sent by admin in RHS
@@ -42,7 +40,7 @@ test('MM-T5435_1 Global Drafts link in sidebar should be hidden when another use
await lastPostByAdmin.postMenu.reply(); await lastPostByAdmin.postMenu.reply();
// # Post a message as a user // # Post a message as a user
const sidebarRight = channelPage.sidebarRight; const sidebarRight = channelsPage.sidebarRight;
await sidebarRight.toBeVisible(); await sidebarRight.toBeVisible();
await sidebarRight.postCreate.postMessage('Replying to a thread'); await sidebarRight.postCreate.postMessage('Replying to a thread');
@@ -54,7 +52,7 @@ test('MM-T5435_1 Global Drafts link in sidebar should be hidden when another use
await sidebarRight.close(); await sidebarRight.close();
// * Verify drafts link in channel sidebar is visible // * Verify drafts link in channel sidebar is visible
await channelPage.sidebarLeft.draftsVisible(); await channelsPage.sidebarLeft.draftsVisible();
// # Delete the last post by admin // # Delete the last post by admin
try { try {
@@ -75,30 +73,29 @@ test('MM-T5435_1 Global Drafts link in sidebar should be hidden when another use
await deletedPostByAdminInRHS.remove(); await deletedPostByAdminInRHS.remove();
// * Verify the drafts links should also be removed from sidebar // * Verify the drafts links should also be removed from sidebar
await channelPage.sidebarLeft.draftsNotVisible(); await channelsPage.sidebarLeft.draftsNotVisible();
}); });
test('MM-T5435_2 Global Drafts link in sidebar should be hidden when user deletes root post ', async ({pw, pages}) => { test('MM-T5435_2 Global Drafts link in sidebar should be hidden when user deletes root post ', async ({pw}) => {
const {user} = await pw.initSetup(); const {user} = await pw.initSetup();
// # Log in as user in new browser context // # Log in as user in new browser context
const {page} = await pw.testBrowser.login(user); const {channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
// # Post a message in the channel // # Post a message in the channel
await channelPage.centerView.postCreate.postMessage('Message which will be deleted'); await channelsPage.centerView.postCreate.postMessage('Message which will be deleted');
// # Start a thread by clicking on reply menuitem from post options menu // # Start a thread by clicking on reply menuitem from post options menu
const post = await channelPage.centerView.getLastPost(); const post = await channelsPage.centerView.getLastPost();
await post.hover(); await post.hover();
await post.postMenu.toBeVisible(); await post.postMenu.toBeVisible();
await post.postMenu.reply(); await post.postMenu.reply();
const sidebarRight = channelPage.sidebarRight; const sidebarRight = channelsPage.sidebarRight;
await sidebarRight.toBeVisible(); await sidebarRight.toBeVisible();
// # Post a message in the thread // # Post a message in the thread
@@ -111,19 +108,19 @@ test('MM-T5435_2 Global Drafts link in sidebar should be hidden when user delete
await sidebarRight.close(); await sidebarRight.close();
// * Verify drafts link in channel sidebar is visible // * Verify drafts link in channel sidebar is visible
await channelPage.sidebarLeft.draftsVisible(); await channelsPage.sidebarLeft.draftsVisible();
// # Click on the dot menu of the post and select delete // # Click on the dot menu of the post and select delete
await post.hover(); await post.hover();
await post.postMenu.toBeVisible(); await post.postMenu.toBeVisible();
await post.postMenu.openDotMenu(); await post.postMenu.openDotMenu();
await channelPage.postDotMenu.toBeVisible(); await channelsPage.postDotMenu.toBeVisible();
await channelPage.postDotMenu.deleteMenuItem.click(); await channelsPage.postDotMenu.deleteMenuItem.click();
// # Confirm the delete from the modal // # Confirm the delete from the modal
await channelPage.deletePostModal.toBeVisible(); await channelsPage.deletePostModal.toBeVisible();
await channelPage.deletePostModal.confirm(); await channelsPage.deletePostModal.confirm();
// * Verify drafts link in channel sidebar is visible // * Verify drafts link in channel sidebar is visible
await channelPage.sidebarLeft.draftsNotVisible(); await channelsPage.sidebarLeft.draftsNotVisible();
}); });

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

@@ -5,37 +5,36 @@ import {expect, test} from '@e2e-support/test_fixture';
test.fixme( test.fixme(
'MM-T5445 Should search, select and post correct Gif when Gif picker is opened from center textbox', 'MM-T5445 Should search, select and post correct Gif when Gif picker is opened from center textbox',
async ({pw, pages}) => { async ({pw}) => {
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 {channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
// # Open emoji/gif picker // # Open emoji/gif picker
await channelPage.centerView.postCreate.openEmojiPicker(); await channelsPage.centerView.postCreate.openEmojiPicker();
await channelPage.emojiGifPickerPopup.toBeVisible(); await channelsPage.emojiGifPickerPopup.toBeVisible();
// # Open gif tab // # Open gif tab
await channelPage.emojiGifPickerPopup.openGifTab(); await channelsPage.emojiGifPickerPopup.openGifTab();
// # Search for gif // # Search for gif
await channelPage.emojiGifPickerPopup.searchGif('hello'); await channelsPage.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 channelsPage.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 channelsPage.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 channelsPage.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);
}, },
@@ -43,27 +42,26 @@ test.fixme(
test.fixme( test.fixme(
'MM-T5446 Should search, select and post correct Gif when Gif picker is opened from RHS textbox', 'MM-T5446 Should search, select and post correct Gif when Gif picker is opened from RHS textbox',
async ({pw, pages}) => { async ({pw}) => {
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 {channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
// # Send a message // # Send a message
await channelPage.centerView.postCreate.postMessage('Message to open RHS'); await channelsPage.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 channelsPage.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 = channelsPage.sidebarRight;
await sidebarRight.toBeVisible(); await sidebarRight.toBeVisible();
// # Send a message in the thread // # Send a message in the thread
@@ -73,17 +71,17 @@ test.fixme(
// # Open emoji/gif picker // # Open emoji/gif picker
await sidebarRight.postCreate.openEmojiPicker(); await sidebarRight.postCreate.openEmojiPicker();
await channelPage.emojiGifPickerPopup.toBeVisible(); await channelsPage.emojiGifPickerPopup.toBeVisible();
// # Open gif tab // # Open gif tab
await channelPage.emojiGifPickerPopup.openGifTab(); await channelsPage.emojiGifPickerPopup.openGifTab();
// # Search for gif // # Search for gif
await channelPage.emojiGifPickerPopup.searchGif('hello'); await channelsPage.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 channelsPage.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

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

@@ -4,48 +4,47 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
import MessagePriority from '@e2e-support/ui/components/channels/message_priority'; import MessagePriority from '@e2e-support/ui/components/channels/message_priority';
test('MM-T5139: Message Priority - Standard message priority and system setting', async ({pw, pages}) => { test('MM-T5139: Message Priority - Standard message priority and system setting', async ({pw}) => {
// # Setup test environment // # Setup test environment
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, channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
const messagePriority = new MessagePriority(page.locator('body')); const messagePriority = new MessagePriority(page.locator('body'));
// Open menu // Open menu
await channelPage.centerView.postCreate.openPriorityMenu(); await channelsPage.centerView.postCreate.openPriorityMenu();
// Use messagePriority for dialog interactions // Use messagePriority for dialog interactions
await messagePriority.verifyPriorityDialog(); await messagePriority.verifyPriorityDialog();
await messagePriority.verifyStandardOptionSelected(); await messagePriority.verifyStandardOptionSelected();
// # Close menu and post message // # Close menu and post message
await channelPage.centerView.postCreate.priorityButton.click(); await channelsPage.centerView.postCreate.priorityButton.click();
const testMessage = 'This is just a test message'; const testMessage = 'This is just a test message';
await channelPage.postMessage(testMessage); await channelsPage.postMessage(testMessage);
// # Verify message posts without priority label // # Verify message posts without priority label
const lastPost = await channelPage.centerView.getLastPost(); const lastPost = await channelsPage.centerView.getLastPost();
await lastPost.toBeVisible(); await lastPost.toBeVisible();
await lastPost.toContainText(testMessage); await lastPost.toContainText(testMessage);
await expect(lastPost.container.locator('.post-priority')).not.toBeVisible(); await expect(lastPost.container.locator('.post-priority')).not.toBeVisible();
// # Open post in RHS and verify // # Open post in RHS and verify
await lastPost.container.click(); await lastPost.container.click();
await channelPage.sidebarRight.toBeVisible(); await channelsPage.sidebarRight.toBeVisible();
// # Get RHS post and verify content // # Get RHS post and verify content
const rhsPost = await channelPage.sidebarRight.getLastPost(); const rhsPost = await channelsPage.sidebarRight.getLastPost();
await rhsPost.toBeVisible(); await rhsPost.toBeVisible();
await rhsPost.toContainText(testMessage); await rhsPost.toContainText(testMessage);
await expect(rhsPost.container.locator('.post-priority')).not.toBeVisible(); await expect(rhsPost.container.locator('.post-priority')).not.toBeVisible();
// # Verify RHS formatting bar doesn't have priority button // # Verify RHS formatting bar doesn't have priority button
await expect(channelPage.sidebarRight.postCreate.priorityButton).not.toBeVisible(); await expect(channelsPage.sidebarRight.postCreate.priorityButton).not.toBeVisible();
}); });

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

@@ -3,7 +3,7 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
test('MM-T483 Channel-wide mentions with uppercase letters', async ({pw, pages, headless, browserName}) => { test('MM-T483 Channel-wide mentions with uppercase letters', async ({pw, headless, browserName}) => {
test.skip( test.skip(
headless && browserName !== 'firefox', headless && browserName !== 'firefox',
'Works across browsers and devices, except in headless mode, where stubbing the Notification API is supported only in Firefox and WebKit.', 'Works across browsers and devices, except in headless mode, where stubbing the Notification API is supported only in Firefox and WebKit.',
@@ -13,23 +13,21 @@ test('MM-T483 Channel-wide mentions with uppercase letters', async ({pw, pages,
const {team, adminUser, user} = await pw.initSetup(); const {team, adminUser, user} = await pw.initSetup();
// Log in as the admin in one browser session and navigate to the "town-square" channel // Log in as the admin in one browser session and navigate to the "town-square" channel
const {page: adminPage} = await pw.testBrowser.login(adminUser); const {page: adminPage, channelsPage: adminChannelsPage} = await pw.testBrowser.login(adminUser);
const adminChannelPage = new pages.ChannelsPage(adminPage); await adminChannelsPage.goto(team.name, 'town-square');
await adminChannelPage.goto(team.name, 'town-square'); await adminChannelsPage.toBeVisible();
await adminChannelPage.toBeVisible();
// Stub the Notification in the admin's browser to capture notifications // Stub the Notification in the admin's browser to capture notifications
await pw.stubNotification(adminPage, 'granted'); await pw.stubNotification(adminPage, 'granted');
// Log in as the regular user in a separate browser and navigate to the "off-topic" channel // Log in as the regular user in a separate browser and navigate to the "off-topic" channel
const {page: otherPage} = await pw.testBrowser.login(user); const {channelsPage: otherChannelsPage} = await pw.testBrowser.login(user);
const otherChannelPage = new pages.ChannelsPage(otherPage); await otherChannelsPage.goto(team.name, 'off-topic');
await otherChannelPage.goto(team.name, 'off-topic'); await otherChannelsPage.toBeVisible();
await otherChannelPage.toBeVisible();
// Post a channel-wide mention message "@ALL" in uppercase from the user's browser // Post a channel-wide mention message "@ALL" in uppercase from the user's browser
const message = `@ALL good morning, ${team.name}!`; const message = `@ALL good morning, ${team.name}!`;
await otherChannelPage.postMessage(message); await otherChannelsPage.postMessage(message);
// Wait for a notification to be received in the admin's browser and verify its content // Wait for a notification to be received in the admin's browser and verify its content
const notifications = await pw.waitForNotification(adminPage); const notifications = await pw.waitForNotification(adminPage);
@@ -44,14 +42,14 @@ test('MM-T483 Channel-wide mentions with uppercase letters', async ({pw, pages,
expect(notification.silent).toBe(false); expect(notification.silent).toBe(false);
// Verify the last post as viewed by the regular user in the "off-topic" channel contains the message and is highlighted // Verify the last post as viewed by the regular user in the "off-topic" channel contains the message and is highlighted
const otherLastPost = await otherChannelPage.centerView.getLastPost(); const otherLastPost = await otherChannelsPage.centerView.getLastPost();
await otherLastPost.toContainText(message); await otherLastPost.toContainText(message);
await expect(otherLastPost.container.locator('.mention--highlight')).toBeVisible(); await expect(otherLastPost.container.locator('.mention--highlight')).toBeVisible();
await expect(otherLastPost.container.locator('.mention--highlight').getByText('@ALL')).toBeVisible(); await expect(otherLastPost.container.locator('.mention--highlight').getByText('@ALL')).toBeVisible();
// Admin navigates to the "off-topic" channel and verifies the message is posted and highlighted correctly // Admin navigates to the "off-topic" channel and verifies the message is posted and highlighted correctly
await adminChannelPage.goto(team.name, 'off-topic'); await adminChannelsPage.goto(team.name, 'off-topic');
const adminLastPost = await adminChannelPage.centerView.getLastPost(); const adminLastPost = await adminChannelsPage.centerView.getLastPost();
await adminLastPost.toContainText(message); await adminLastPost.toContainText(message);
await expect(adminLastPost.container.locator('.mention--highlight')).toBeVisible(); await expect(adminLastPost.container.locator('.mention--highlight')).toBeVisible();
await expect(adminLastPost.container.locator('.mention--highlight').getByText('@ALL')).toBeVisible(); await expect(adminLastPost.container.locator('.mention--highlight').getByText('@ALL')).toBeVisible();

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

@@ -3,7 +3,7 @@ import {test} from '@e2e-support/test_fixture';
import {ChannelsPage, ScheduledDraftPage} from '@e2e-support/ui/pages'; import {ChannelsPage, ScheduledDraftPage} from '@e2e-support/ui/pages';
import {duration, wait} from '@e2e-support/util'; import {duration, wait} from '@e2e-support/util';
test.fixme('MM-T5643_1 should create a scheduled message from a channel', async ({pw, pages}) => { test.fixme('MM-T5643_1 should create a scheduled message from a channel', async ({pw}) => {
test.setTimeout(120000); test.setTimeout(120000);
const draftMessage = 'Scheduled Draft'; const draftMessage = 'Scheduled Draft';
@@ -11,18 +11,16 @@ test.fixme('MM-T5643_1 should create a scheduled message from a channel', async
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
const {user, team} = await pw.initSetup(); const {user, team} = await pw.initSetup();
const {page} = await pw.testBrowser.login(user); const {page, channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
const channelPage = new pages.ChannelsPage(page);
const scheduledDraftPage = new pages.ScheduledDraftPage(page);
await setupChannelPage(channelPage, draftMessage); await setupChannelPage(channelsPage, draftMessage);
await scheduleMessage(channelPage); await scheduleMessage(channelsPage);
await channelPage.centerView.verifyscheduledDraftChannelInfo(); await channelsPage.centerView.verifyscheduledDraftChannelInfo();
const scheduledDraftChannelInfo = await channelPage.centerView.scheduledDraftChannelInfoMessageText.innerText(); const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
await verifyscheduledDrafts(channelPage, pages, draftMessage, scheduledDraftChannelInfo); await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
// # Hover and verify options // # Hover and verify options
await scheduledDraftPage.verifyOnHoverActionItems(draftMessage); await scheduledDraftPage.verifyOnHoverActionItems(draftMessage);
@@ -31,14 +29,14 @@ test.fixme('MM-T5643_1 should create a scheduled message from a channel', async
await goBackToChannelAndWaitForMessageToArrive(page); await goBackToChannelAndWaitForMessageToArrive(page);
// * Verify the message has been sent and there's no more scheduled messages // * Verify the message has been sent and there's no more scheduled messages
await expect(channelPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible(); await expect(channelsPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible();
await expect(channelPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible(); await expect(channelsPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible();
await expect(await channelPage.getLastPost()).toHaveText(draftMessage); await expect(await channelsPage.getLastPost()).toHaveText(draftMessage);
await verifyNoscheduledDraftsPending(channelPage, team, scheduledDraftPage, draftMessage); await verifyNoscheduledDraftsPending(channelsPage, team, scheduledDraftPage, draftMessage);
}); });
test.fixme('MM-T5643_6 should create a scheduled message under a thread post ', async ({pw, pages}) => { test.fixme('MM-T5643_6 should create a scheduled message under a thread post ', async ({pw}) => {
test.setTimeout(120000); test.setTimeout(120000);
const draftMessage = 'Scheduled Threaded Message'; const draftMessage = 'Scheduled Threaded Message';
@@ -48,20 +46,19 @@ test.fixme('MM-T5643_6 should create a scheduled message under a thread post ',
const {user, team} = await pw.initSetup(); const {user, team} = 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, channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
await channelPage.centerView.postCreate.postMessage('Root Message'); await channelsPage.centerView.postCreate.postMessage('Root Message');
// # Start a thread by clicking on reply menuitem from post options menu // # Start a thread by clicking on reply menuitem from post options menu
const post = await channelPage.centerView.getLastPost(); const post = await channelsPage.centerView.getLastPost();
await replyToLastPost(post); await replyToLastPost(post);
const sidebarRight = channelPage.sidebarRight; const sidebarRight = channelsPage.sidebarRight;
await sidebarRight.toBeVisible(); await sidebarRight.toBeVisible();
// # Post a message in the thread // # Post a message in the thread
@@ -74,19 +71,18 @@ test.fixme('MM-T5643_6 should create a scheduled message under a thread post ',
await sidebarRight.postCreate.scheduleDraftMessageButton.isVisible(); await sidebarRight.postCreate.scheduleDraftMessageButton.isVisible();
await sidebarRight.postCreate.scheduleDraftMessageButton.click(); await sidebarRight.postCreate.scheduleDraftMessageButton.click();
await scheduleMessage(channelPage); await scheduleMessage(channelsPage);
await sidebarRight.scheduledDraftChannelInfo.isVisible(); await sidebarRight.postBoxIndicator.isVisible();
const messageLocator = sidebarRight.scheduledDraftChannelInfoMessage.first(); const messageLocator = sidebarRight.scheduledDraftChannelInfoMessage.first();
await expect(messageLocator).toContainText('Message scheduled for'); await expect(messageLocator).toContainText('Message scheduled for');
// Save the time displayed in the thread // Save the time displayed in the thread
const scheduledDraftThreadedPanelInfo = await sidebarRight.scheduledDraftChannelInfo.innerText(); const scheduledDraftThreadedPanelInfo = await sidebarRight.postBoxIndicator.innerText();
const scheduledDraftPage = new pages.ScheduledDraftPage(page);
await channelPage.sidebarRight.clickOnSeeAllscheduledDrafts(); await channelsPage.sidebarRight.clickOnSeeAllscheduledDrafts();
const scheduledDraftPageInfo = await scheduledDraftPage.scheduledDraftPageInfo.innerHTML(); const scheduledDraftPageInfo = await scheduledDraftPage.scheduledDraftPageInfo.innerHTML();
await channelPage.sidebarLeft.assertscheduledDraftCountLHS('1'); await channelsPage.sidebarLeft.assertscheduledDraftCountLHS('1');
await scheduledDraftPage.toBeVisible(); await scheduledDraftPage.toBeVisible();
await scheduledDraftPage.assertBadgeCountOnTab('1'); await scheduledDraftPage.assertBadgeCountOnTab('1');
@@ -103,64 +99,60 @@ test.fixme('MM-T5643_6 should create a scheduled message under a thread post ',
await replyToLastPost(post); await replyToLastPost(post);
// * Verify the message has been sent and there's no more scheduled messages // * Verify the message has been sent and there's no more scheduled messages
await expect(channelPage.sidebarRight.scheduledDraftChannelInfoMessage).not.toBeVisible(); await expect(channelsPage.sidebarRight.scheduledDraftChannelInfoMessage).not.toBeVisible();
await expect(channelPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible(); await expect(channelsPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible();
const lastPost = channelPage.sidebarRight.rhsPostBody.last(); const lastPost = channelsPage.sidebarRight.rhsPostBody.last();
await expect(lastPost).toHaveText(draftMessage); await expect(lastPost).toHaveText(draftMessage);
await expect(scheduledDraftPage.scheduledDraftPanel(draftMessage)).not.toBeVisible(); await expect(scheduledDraftPage.scheduledDraftPanel(draftMessage)).not.toBeVisible();
await verifyNoscheduledDraftsPending(channelPage, team, scheduledDraftPage, draftMessage); await verifyNoscheduledDraftsPending(channelsPage, team, scheduledDraftPage, draftMessage);
}); });
test.fixme('MM-T5644 should rechedule a scheduled message', async ({pw, pages}) => { test.fixme('MM-T5644 should reschedule a scheduled message', async ({pw}) => {
const draftMessage = 'Scheduled Draft'; const draftMessage = 'Scheduled Draft';
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
const {user} = await pw.initSetup(); const {user} = await pw.initSetup();
const {page} = await pw.testBrowser.login(user); const {channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
const channelPage = new pages.ChannelsPage(page);
const scheduledDraftPage = new pages.ScheduledDraftPage(page);
await setupChannelPage(channelPage, draftMessage); await setupChannelPage(channelsPage, draftMessage);
await scheduleMessage(channelPage); await scheduleMessage(channelsPage);
// * Verify the Initial Date and time of scheduled Draft // * Verify the Initial Date and time of scheduled Draft
await channelPage.centerView.verifyscheduledDraftChannelInfo(); await channelsPage.centerView.verifyscheduledDraftChannelInfo();
const scheduledDraftChannelInfo = await channelPage.centerView.scheduledDraftChannelInfoMessageText.innerText(); const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
await verifyscheduledDrafts(channelPage, pages, draftMessage, scheduledDraftChannelInfo); await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
await scheduledDraftPage.openRescheduleModal(draftMessage); await scheduledDraftPage.openRescheduleModal(draftMessage);
// # Reschedule it to 2 days from today // # Reschedule it to 2 days from today
await channelPage.scheduledDraftModal.selectDay(2); await channelsPage.scheduledDraftModal.selectDay(2);
await channelPage.scheduledDraftModal.confirm(); await channelsPage.scheduledDraftModal.confirm();
// # Note the new Scheduled time // # Note the new Scheduled time
const scheduledDraftPageInfo = await scheduledDraftPage.getTimeStampOfMessage(draftMessage); const scheduledDraftPageInfo = await scheduledDraftPage.getTimeStampOfMessage(draftMessage);
// # Go to Channel // # Go to Channel
await channelPage.goto(); await channelsPage.goto();
// * Verify the New Time reflecting in the channel // * Verify the New Time reflecting in the channel
const rescheduledDraftChannelInfo = await channelPage.centerView.scheduledDraftChannelInfoMessageText.innerText(); const rescheduledDraftChannelInfo = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
await compareMessageTimestamps(rescheduledDraftChannelInfo, scheduledDraftPageInfo, scheduledDraftPage); await compareMessageTimestamps(rescheduledDraftChannelInfo, scheduledDraftPageInfo, scheduledDraftPage);
}); });
test.fixme('MM-T5645 should delete a scheduled message', async ({pw, pages}) => { test.fixme('MM-T5645 should delete a scheduled message', async ({pw}) => {
const draftMessage = 'Scheduled Draft'; const draftMessage = 'Scheduled Draft';
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
const {user} = await pw.initSetup(); const {user} = await pw.initSetup();
const {page} = await pw.testBrowser.login(user); const {channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
const channelPage = new pages.ChannelsPage(page);
const scheduledDraftPage = new pages.ScheduledDraftPage(page);
await setupChannelPage(channelPage, draftMessage); await setupChannelPage(channelsPage, draftMessage);
await scheduleMessage(channelPage); await scheduleMessage(channelsPage);
const scheduledDraftChannelInfo = await channelPage.centerView.scheduledDraftChannelInfoMessageText.innerText(); const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
await verifyscheduledDrafts(channelPage, pages, draftMessage, scheduledDraftChannelInfo); await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
await scheduledDraftPage.deleteScheduledMessage(draftMessage); await scheduledDraftPage.deleteScheduledMessage(draftMessage);
@@ -168,32 +160,30 @@ test.fixme('MM-T5645 should delete a scheduled message', async ({pw, pages}) =>
await expect(scheduledDraftPage.noscheduledDraftIcon).toBeVisible(); await expect(scheduledDraftPage.noscheduledDraftIcon).toBeVisible();
}); });
test.fixme('MM-T5643_9 should send a scheduled message immediately', async ({pw, pages}) => { test.fixme('MM-T5643_9 should send a scheduled message immediately', async ({pw}) => {
const draftMessage = 'Scheduled Draft'; const draftMessage = 'Scheduled Draft';
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
const {user} = await pw.initSetup(); const {user} = await pw.initSetup();
const {page} = await pw.testBrowser.login(user); const {channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
const channelPage = new pages.ChannelsPage(page);
const scheduledDraftPage = new pages.ScheduledDraftPage(page);
await setupChannelPage(channelPage, draftMessage); await setupChannelPage(channelsPage, draftMessage);
await scheduleMessage(channelPage); await scheduleMessage(channelsPage);
const scheduledDraftChannelInfo = await channelPage.centerView.scheduledDraftChannelInfoMessageText.innerText(); const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
await verifyscheduledDrafts(channelPage, pages, draftMessage, scheduledDraftChannelInfo); await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
await scheduledDraftPage.sendScheduledMessage(draftMessage); await scheduledDraftPage.sendScheduledMessage(draftMessage);
await expect(scheduledDraftPage.scheduledDraftPanel(draftMessage)).not.toBeVisible(); await expect(scheduledDraftPage.scheduledDraftPanel(draftMessage)).not.toBeVisible();
// Verify message has arrived // Verify message has arrived
await expect(channelPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible(); await expect(channelsPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible();
await expect(channelPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible(); await expect(channelsPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible();
await expect(await channelPage.getLastPost()).toHaveText(draftMessage); await expect(await channelsPage.getLastPost()).toHaveText(draftMessage);
}); });
test.fixme('MM-T5643_3 should create a scheduled message from a DM', async ({pw, pages}) => { test.fixme('MM-T5643_3 should create a scheduled message from a DM', async ({pw}) => {
test.setTimeout(120000); test.setTimeout(120000);
const draftMessage = 'Scheduled Draft'; const draftMessage = 'Scheduled Draft';
@@ -203,18 +193,16 @@ test.fixme('MM-T5643_3 should create a scheduled message from a DM', async ({pw,
const {user, team} = await pw.initSetup(); const {user, team} = await pw.initSetup();
const {user: user2} = await pw.initSetup(); const {user: user2} = await pw.initSetup();
const {page} = await pw.testBrowser.login(user); const {page, channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
const channelPage = new pages.ChannelsPage(page);
const scheduledDraftPage = new pages.ScheduledDraftPage(page);
await setupChannelPage(channelPage, draftMessage, team.name, `@${user2.username}`); await setupChannelPage(channelsPage, draftMessage, team.name, `@${user2.username}`);
await scheduleMessage(channelPage); await scheduleMessage(channelsPage);
await channelPage.centerView.verifyscheduledDraftChannelInfo(); await channelsPage.centerView.verifyscheduledDraftChannelInfo();
const scheduledDraftChannelInfo = await channelPage.centerView.scheduledDraftChannelInfoMessageText.innerText(); const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
await verifyscheduledDrafts(channelPage, pages, draftMessage, scheduledDraftChannelInfo); await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
// # Hover and verify options // # Hover and verify options
await scheduledDraftPage.verifyOnHoverActionItems(draftMessage); await scheduledDraftPage.verifyOnHoverActionItems(draftMessage);
@@ -223,49 +211,46 @@ test.fixme('MM-T5643_3 should create a scheduled message from a DM', async ({pw,
await goBackToChannelAndWaitForMessageToArrive(page); await goBackToChannelAndWaitForMessageToArrive(page);
// * Verify the message has been sent and there's no more scheduled messages // * Verify the message has been sent and there's no more scheduled messages
await expect(channelPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible(); await expect(channelsPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible();
await expect(channelPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible(); await expect(channelsPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible();
await expect(await channelPage.getLastPost()).toHaveText(draftMessage); await expect(await channelsPage.getLastPost()).toHaveText(draftMessage);
await verifyNoscheduledDraftsPending(channelPage, team, scheduledDraftPage, draftMessage); await verifyNoscheduledDraftsPending(channelsPage, team, scheduledDraftPage, draftMessage);
}); });
test('MM-T5648 should create a draft and then schedule it', async ({pw, pages}) => { test('MM-T5648 should create a draft and then schedule it', async ({pw}) => {
test.setTimeout(120000); test.setTimeout(120000);
const draftMessage = 'Draft to be Scheduled'; const draftMessage = 'Draft to be Scheduled';
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
const {user, team} = await pw.initSetup(); const {user, team} = await pw.initSetup();
const {page} = await pw.testBrowser.login(user); const {channelsPage, draftPage, scheduledDraftPage} = await pw.testBrowser.login(user);
const channelPage = new pages.ChannelsPage(page);
// await setupChannelPage(channelPage, draftMessage); // await setupChannelPage(channelsPage, draftMessage);
await channelPage.goto(); await channelsPage.goto();
await channelPage.toBeVisible(); await channelsPage.toBeVisible();
await channelPage.centerView.postCreate.writeMessage(draftMessage); await channelsPage.centerView.postCreate.writeMessage(draftMessage);
// go to drafts page // go to drafts page
const draftsPage = new pages.DraftPage(page); await draftPage.goTo(team.name);
await draftsPage.goTo(team.name); await draftPage.toBeVisible();
await draftsPage.toBeVisible(); await draftPage.assertBadgeCountOnTab('1');
await draftsPage.assertBadgeCountOnTab('1'); await draftPage.assertDraftBody(draftMessage);
await draftsPage.assertDraftBody(draftMessage); await draftPage.verifyScheduleIcon(draftMessage);
await draftsPage.verifyScheduleIcon(draftMessage); await draftPage.openScheduleModal(draftMessage);
await draftsPage.openScheduleModal(draftMessage);
// # Reschedule it to 2 days from today // # Reschedule it to 2 days from today
await channelPage.scheduledDraftModal.selectDay(2); await channelsPage.scheduledDraftModal.selectDay(2);
await channelPage.scheduledDraftModal.confirm(); await channelsPage.scheduledDraftModal.confirm();
const scheduledDraftPage = new pages.ScheduledDraftPage(page);
await scheduledDraftPage.goTo(team.name); await scheduledDraftPage.goTo(team.name);
await scheduledDraftPage.toBeVisible(); await scheduledDraftPage.toBeVisible();
await scheduledDraftPage.assertBadgeCountOnTab('1'); await scheduledDraftPage.assertBadgeCountOnTab('1');
await scheduledDraftPage.assertscheduledDraftBody(draftMessage); await scheduledDraftPage.assertscheduledDraftBody(draftMessage);
}); });
test.fixme('MM-T5644 should edit scheduled message', async ({pw, pages}) => { test.fixme('MM-T5644 should edit scheduled message', async ({pw}) => {
test.setTimeout(120000); test.setTimeout(120000);
const draftMessage = 'Scheduled Draft'; const draftMessage = 'Scheduled Draft';
@@ -273,18 +258,16 @@ test.fixme('MM-T5644 should edit scheduled message', async ({pw, pages}) => {
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
const {user, team} = await pw.initSetup(); const {user, team} = await pw.initSetup();
const {page} = await pw.testBrowser.login(user); const {page, channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
const channelPage = new pages.ChannelsPage(page);
const scheduledDraftPage = new pages.ScheduledDraftPage(page);
await setupChannelPage(channelPage, draftMessage); await setupChannelPage(channelsPage, draftMessage);
await scheduleMessage(channelPage); await scheduleMessage(channelsPage);
await channelPage.centerView.verifyscheduledDraftChannelInfo(); await channelsPage.centerView.verifyscheduledDraftChannelInfo();
const scheduledDraftChannelInfo = await channelPage.centerView.scheduledDraftChannelInfoMessageText.innerText(); const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
await verifyscheduledDrafts(channelPage, pages, draftMessage, scheduledDraftChannelInfo); await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
// # Hover and verify options // # Hover and verify options
await scheduledDraftPage.verifyOnHoverActionItems(draftMessage); await scheduledDraftPage.verifyOnHoverActionItems(draftMessage);
@@ -296,60 +279,57 @@ test.fixme('MM-T5644 should edit scheduled message', async ({pw, pages}) => {
await goBackToChannelAndWaitForMessageToArrive(page); await goBackToChannelAndWaitForMessageToArrive(page);
// * Verify the message has been sent and there's no more scheduled messages // * Verify the message has been sent and there's no more scheduled messages
await expect(channelPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible(); await expect(channelsPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible();
await expect(channelPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible(); await expect(channelsPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible();
await expect(await channelPage.getLastPost()).toHaveText(draftMessage); await expect(await channelsPage.getLastPost()).toHaveText(draftMessage);
await verifyNoscheduledDraftsPending(channelPage, team, scheduledDraftPage, draftMessage); await verifyNoscheduledDraftsPending(channelsPage, team, scheduledDraftPage, draftMessage);
}); });
test.fixme('MM-T5650 should copy scheduled message', async ({pw, pages, browserName}) => { test.fixme('MM-T5650 should copy scheduled message', async ({pw, browserName}) => {
test.setTimeout(120000); test.setTimeout(120000);
// Skip this test in Firefox clipboard permissions are not supported // Skip this test in Firefox clipboard permissions are not supported
test.skip(browserName === 'firefox', 'Test not supported in Firefox'); test.skip(browserName === 'firefox', 'Test not supported in Firefox');
const draftMessage = 'Scheduled Draft';
// # Skip test if no license // # Skip test if no license
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
const draftMessage = 'Scheduled Draft';
const {user} = await pw.initSetup(); const {user} = await pw.initSetup();
const {page, context} = await pw.testBrowser.login(user); const {page, channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
await context.grantPermissions(['clipboard-read', 'clipboard-write']);
const channelPage = new pages.ChannelsPage(page); await setupChannelPage(channelsPage, draftMessage);
const scheduledDraftPage = new pages.ScheduledDraftPage(page); await scheduleMessage(channelsPage);
await setupChannelPage(channelPage, draftMessage); await channelsPage.centerView.verifyscheduledDraftChannelInfo();
await scheduleMessage(channelPage);
await channelPage.centerView.verifyscheduledDraftChannelInfo(); const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
const scheduledDraftChannelInfo = await channelPage.centerView.scheduledDraftChannelInfoMessageText.innerText(); await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
await verifyscheduledDrafts(channelPage, pages, draftMessage, scheduledDraftChannelInfo);
await scheduledDraftPage.copyScheduledMessage(draftMessage); await scheduledDraftPage.copyScheduledMessage(draftMessage);
await page.goBack(); await page.goBack();
await channelPage.centerView.postCreate.input.focus(); await channelsPage.centerView.postCreate.input.focus();
await page.keyboard.down('Meta'); await page.keyboard.down('Meta');
await page.keyboard.press('V'); await page.keyboard.press('V');
await page.keyboard.up('Meta'); await page.keyboard.up('Meta');
// * Assert the message typed is same as the copied message // * Assert the message typed is same as the copied message
await expect(channelPage.centerView.postCreate.input).toHaveText(draftMessage); await expect(channelsPage.centerView.postCreate.input).toHaveText(draftMessage);
}); });
async function verifyNoscheduledDraftsPending( async function verifyNoscheduledDraftsPending(
channelPage: ChannelsPage, channelsPage: ChannelsPage,
team: any, team: any,
scheduledDraftPage: ScheduledDraftPage, scheduledDraftPage: ScheduledDraftPage,
draftMessage: string, draftMessage: string,
): Promise<void> { ): Promise<void> {
await channelPage.goto(team.name, 'scheduled_posts'); await channelsPage.goto(team.name, 'scheduled_posts');
await expect(scheduledDraftPage.scheduledDraftPanel(draftMessage)).not.toBeVisible(); await expect(scheduledDraftPage.scheduledDraftPanel(draftMessage)).not.toBeVisible();
await expect(scheduledDraftPage.noscheduledDraftIcon).toBeVisible(); await expect(scheduledDraftPage.noscheduledDraftIcon).toBeVisible();
} }
@@ -367,16 +347,16 @@ async function replyToLastPost(post: any): Promise<void> {
} }
async function setupChannelPage( async function setupChannelPage(
channelPage: ChannelsPage, channelsPage: ChannelsPage,
draftMessage: string, draftMessage: string,
teamName?: string, teamName?: string,
channelName?: string, channelName?: string,
): Promise<void> { ): Promise<void> {
await channelPage.goto(teamName, channelName); await channelsPage.goto(teamName, channelName);
await channelPage.toBeVisible(); await channelsPage.toBeVisible();
await channelPage.centerView.postCreate.writeMessage(draftMessage); await channelsPage.centerView.postCreate.writeMessage(draftMessage);
await channelPage.centerView.postCreate.clickOnScheduleDraftDropdownButton(); await channelsPage.centerView.postCreate.clickOnScheduleDraftDropdownButton();
} }
/** /**
@@ -395,21 +375,19 @@ async function scheduleMessage(pageObject: ChannelsPage): Promise<void> {
/** /**
* Extracts and verifies the scheduled message on the scheduled page and in the channel. * Extracts and verifies the scheduled message on the scheduled page and in the channel.
*/ */
async function verifyscheduledDrafts( async function verifyScheduledDraft(
channelPage: ChannelsPage, channelsPage: ChannelsPage,
pages: any, scheduledDraftPage: ScheduledDraftPage,
draftMessage: string, draftMessage: string,
scheduledDraftChannelInfo: string, postBoxIndicator: string,
): Promise<void> { ): Promise<void> {
const scheduledDraftPage = new pages.ScheduledDraftPage(channelPage.page); await verifyscheduledDraftCount(channelsPage, '1');
await verifyscheduledDraftCount(channelPage, '1');
await scheduledDraftPage.toBeVisible(); await scheduledDraftPage.toBeVisible();
await scheduledDraftPage.assertBadgeCountOnTab('1'); await scheduledDraftPage.assertBadgeCountOnTab('1');
await scheduledDraftPage.assertscheduledDraftBody(draftMessage); await scheduledDraftPage.assertscheduledDraftBody(draftMessage);
const scheduledDraftPageInfo = await scheduledDraftPage.getTimeStampOfMessage(draftMessage); const scheduledDraftPageInfo = await scheduledDraftPage.getTimeStampOfMessage(draftMessage);
await compareMessageTimestamps(scheduledDraftChannelInfo, scheduledDraftPageInfo, scheduledDraftPage); await compareMessageTimestamps(postBoxIndicator, scheduledDraftPageInfo, scheduledDraftPage);
} }
/** /**

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

@@ -6,7 +6,6 @@ import {createRandomChannel} from '@e2e-support/server';
test('MM-T5424 Find channel search returns only 50 results when there are more than 50 channels with similar names', async ({ test('MM-T5424 Find channel search returns only 50 results when there are more than 50 channels with similar names', async ({
pw, pw,
pages,
}) => { }) => {
const {adminClient, user, team} = await pw.initSetup(); const {adminClient, user, team} = await pw.initSetup();
@@ -29,10 +28,9 @@ test('MM-T5424 Find channel search returns only 50 results when there are more t
await Promise.all(channelsRes); await Promise.all(channelsRes);
// # Log in a user in new browser context // # Log in a user in new browser context
const {page} = await pw.testBrowser.login(user); const {channelsPage} = await pw.testBrowser.login(user);
// # Visit a default channel page // # Visit a default channel page
const channelsPage = new pages.ChannelsPage(page);
await channelsPage.goto(); await channelsPage.goto();
await channelsPage.toBeVisible(); await channelsPage.toBeVisible();

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

@@ -3,14 +3,13 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
test('Search box suggestion must be case insensitive', async ({pw, pages}) => { test('Search box suggestion must be case insensitive', async ({pw}) => {
const {user} = await pw.initSetup(); const {user} = await pw.initSetup();
// # Log in a user in new browser context // # Log in a user in new browser context
const {page} = await pw.testBrowser.login(user); const {channelsPage} = await pw.testBrowser.login(user);
// # Visit a default channel page // # Visit a default channel page
const channelsPage = new pages.ChannelsPage(page);
await channelsPage.goto(); await channelsPage.goto();
await channelsPage.toBeVisible(); await channelsPage.toBeVisible();

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

@@ -11,33 +11,32 @@ const keywords = [`AB${getRandomId()}`, `CD${getRandomId()}`, `EF${getRandomId()
const highlightWithoutNotificationClass = 'non-notification-highlight'; const highlightWithoutNotificationClass = 'non-notification-highlight';
test('MM-T5465-1 Should add the keyword when enter, comma or tab is pressed on the textbox', async ({pw, pages}) => { test('MM-T5465-1 Should add the keyword when enter, comma or tab is pressed on the textbox', async ({pw}) => {
// # Skip test if no license // # Skip test if no license
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
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 {channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
await channelPage.centerView.postCreate.postMessage('Hello World'); await channelsPage.centerView.postCreate.postMessage('Hello World');
// # Open settings modal // # Open settings modal
await channelPage.globalHeader.openSettings(); await channelsPage.globalHeader.openSettings();
await channelPage.settingsModal.toBeVisible(); await channelsPage.settingsModal.toBeVisible();
// # Open notifications tab // # Open notifications tab
await channelPage.settingsModal.openNotificationsTab(); await channelsPage.settingsModal.openNotificationsTab();
// # Open keywords that get highlighted section // # Open keywords that get highlighted section
await channelPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight'); await channelsPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
const keywordsInput = await channelPage.settingsModal.notificationsSettings.getKeywordsInput(); const keywordsInput = await channelsPage.settingsModal.notificationsSettings.getKeywordsInput();
// # Enter keyword 1 // # Enter keyword 1
await keywordsInput.fill(keywords[0]); await keywordsInput.fill(keywords[0]);
@@ -58,55 +57,51 @@ test('MM-T5465-1 Should add the keyword when enter, comma or tab is pressed on t
await keywordsInput.press('Enter'); await keywordsInput.press('Enter');
// * Verify that the keywords have been added to the collapsed description // * Verify that the keywords have been added to the collapsed description
const keysWithHighlightDesc = channelPage.settingsModal.notificationsSettings.keysWithHighlightDesc; const keysWithHighlightDesc = channelsPage.settingsModal.notificationsSettings.keysWithHighlightDesc;
await keysWithHighlightDesc.waitFor(); await keysWithHighlightDesc.waitFor();
for (const keyword of keywords.slice(0, 3)) { for (const keyword of keywords.slice(0, 3)) {
expect(await keysWithHighlightDesc).toContainText(keyword); expect(await keysWithHighlightDesc).toContainText(keyword);
} }
}); });
test('MM-T5465-2 Should highlight the keywords when a message is sent with the keyword in center', async ({ test('MM-T5465-2 Should highlight the keywords when a message is sent with the keyword in center', async ({pw}) => {
pw,
pages,
}) => {
// # Skip test if no license // # Skip test if no license
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
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 {channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
// # Open settings modal // # Open settings modal
await channelPage.globalHeader.openSettings(); await channelsPage.globalHeader.openSettings();
await channelPage.settingsModal.toBeVisible(); await channelsPage.settingsModal.toBeVisible();
// # Open notifications tab // # Open notifications tab
await channelPage.settingsModal.openNotificationsTab(); await channelsPage.settingsModal.openNotificationsTab();
// # Open keywords that get highlighted section // # Open keywords that get highlighted section
await channelPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight'); await channelsPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
// # Enter the keyword // # Enter the keyword
const keywordsInput = await channelPage.settingsModal.notificationsSettings.getKeywordsInput(); const keywordsInput = await channelsPage.settingsModal.notificationsSettings.getKeywordsInput();
await keywordsInput.fill(keywords[3]); await keywordsInput.fill(keywords[3]);
await keywordsInput.press('Tab'); await keywordsInput.press('Tab');
// # Save the keyword // # Save the keyword
await channelPage.settingsModal.notificationsSettings.save(); await channelsPage.settingsModal.notificationsSettings.save();
// # Close the settings modal // # Close the settings modal
await channelPage.settingsModal.closeModal(); await channelsPage.settingsModal.closeModal();
// # Post a message without the keyword // # Post a message without the keyword
const messageWithoutKeyword = 'This message does not contain the keyword'; const messageWithoutKeyword = 'This message does not contain the keyword';
await channelPage.centerView.postCreate.postMessage(messageWithoutKeyword); await channelsPage.centerView.postCreate.postMessage(messageWithoutKeyword);
const lastPostWithoutHighlight = await channelPage.centerView.getLastPost(); const lastPostWithoutHighlight = await channelsPage.centerView.getLastPost();
// * Verify that the keywords are not highlighted // * Verify that the keywords are not highlighted
await expect(lastPostWithoutHighlight.container.getByText(messageWithoutKeyword)).toBeVisible(); await expect(lastPostWithoutHighlight.container.getByText(messageWithoutKeyword)).toBeVisible();
@@ -116,116 +111,114 @@ test('MM-T5465-2 Should highlight the keywords when a message is sent with the k
// # Post a message with the keyword // # Post a message with the keyword
const messageWithKeyword = `This message contains the keyword ${keywords[3]}`; const messageWithKeyword = `This message contains the keyword ${keywords[3]}`;
await channelPage.centerView.postCreate.postMessage(messageWithKeyword); await channelsPage.centerView.postCreate.postMessage(messageWithKeyword);
const lastPostWithHighlight = await channelPage.centerView.getLastPost(); const lastPostWithHighlight = await channelsPage.centerView.getLastPost();
// * Verify that the keywords are highlighted // * Verify that the keywords are highlighted
await expect(lastPostWithHighlight.container.getByText(messageWithKeyword)).toBeVisible(); await expect(lastPostWithHighlight.container.getByText(messageWithKeyword)).toBeVisible();
await expect(lastPostWithHighlight.container.getByText(keywords[3])).toHaveClass(highlightWithoutNotificationClass); await expect(lastPostWithHighlight.container.getByText(keywords[3])).toHaveClass(highlightWithoutNotificationClass);
}); });
test('MM-T5465-3 Should highlight the keywords when a message is sent with the keyword in rhs', async ({pw, pages}) => { test('MM-T5465-3 Should highlight the keywords when a message is sent with the keyword in rhs', async ({pw}) => {
// # Skip test if no license // # Skip test if no license
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
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 {channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
// # Open settings modal // # Open settings modal
await channelPage.globalHeader.openSettings(); await channelsPage.globalHeader.openSettings();
await channelPage.settingsModal.toBeVisible(); await channelsPage.settingsModal.toBeVisible();
// # Open notifications tab // # Open notifications tab
await channelPage.settingsModal.openNotificationsTab(); await channelsPage.settingsModal.openNotificationsTab();
// # Open keywords that get highlighted section // # Open keywords that get highlighted section
await channelPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight'); await channelsPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
// # Enter the keyword // # Enter the keyword
const keywordsInput = await channelPage.settingsModal.notificationsSettings.getKeywordsInput(); const keywordsInput = await channelsPage.settingsModal.notificationsSettings.getKeywordsInput();
await keywordsInput.fill(keywords[3]); await keywordsInput.fill(keywords[3]);
await keywordsInput.press('Tab'); await keywordsInput.press('Tab');
// # Save the keyword // # Save the keyword
await channelPage.settingsModal.notificationsSettings.save(); await channelsPage.settingsModal.notificationsSettings.save();
// # Close the settings modal // # Close the settings modal
await channelPage.settingsModal.closeModal(); await channelsPage.settingsModal.closeModal();
// # Post a message without the keyword // # Post a message without the keyword
const messageWithoutKeyword = 'This message does not contain the keyword'; const messageWithoutKeyword = 'This message does not contain the keyword';
await channelPage.centerView.postCreate.postMessage(messageWithoutKeyword); await channelsPage.centerView.postCreate.postMessage(messageWithoutKeyword);
const lastPostWithoutHighlight = await channelPage.centerView.getLastPost(); const lastPostWithoutHighlight = await channelsPage.centerView.getLastPost();
// # Open the message in the RHS // # Open the message in the RHS
await lastPostWithoutHighlight.hover(); await lastPostWithoutHighlight.hover();
await lastPostWithoutHighlight.postMenu.toBeVisible(); await lastPostWithoutHighlight.postMenu.toBeVisible();
await lastPostWithoutHighlight.postMenu.reply(); await lastPostWithoutHighlight.postMenu.reply();
await channelPage.sidebarRight.toBeVisible(); await channelsPage.sidebarRight.toBeVisible();
// # Post a message with the keyword in the RHS // # Post a message with the keyword in the RHS
const messageWithKeyword = `This message contains the keyword ${keywords[3]}`; const messageWithKeyword = `This message contains the keyword ${keywords[3]}`;
await channelPage.sidebarRight.postCreate.postMessage(messageWithKeyword); await channelsPage.sidebarRight.postCreate.postMessage(messageWithKeyword);
// * Verify that the keywords are highlighted // * Verify that the keywords are highlighted
const lastPostWithHighlightInRHS = await channelPage.sidebarRight.getLastPost(); const lastPostWithHighlightInRHS = await channelsPage.sidebarRight.getLastPost();
await expect(lastPostWithHighlightInRHS.container.getByText(messageWithKeyword)).toBeVisible(); await expect(lastPostWithHighlightInRHS.container.getByText(messageWithKeyword)).toBeVisible();
await expect(lastPostWithHighlightInRHS.container.getByText(keywords[3])).toHaveClass( await expect(lastPostWithHighlightInRHS.container.getByText(keywords[3])).toHaveClass(
highlightWithoutNotificationClass, highlightWithoutNotificationClass,
); );
}); });
test('MM-T5465-4 Highlighted keywords should not appear in the Recent Mentions', async ({pw, pages}) => { test('MM-T5465-4 Highlighted keywords should not appear in the Recent Mentions', async ({pw}) => {
// # Skip test if no license // # Skip test if no license
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
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 {channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
// # Open settings modal // # Open settings modal
await channelPage.globalHeader.openSettings(); await channelsPage.globalHeader.openSettings();
await channelPage.settingsModal.toBeVisible(); await channelsPage.settingsModal.toBeVisible();
// # Open notifications tab // # Open notifications tab
await channelPage.settingsModal.openNotificationsTab(); await channelsPage.settingsModal.openNotificationsTab();
// # Open keywords that get highlighted section // # Open keywords that get highlighted section
await channelPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight'); await channelsPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
// # Enter the keyword // # Enter the keyword
const keywordsInput = await channelPage.settingsModal.notificationsSettings.getKeywordsInput(); const keywordsInput = await channelsPage.settingsModal.notificationsSettings.getKeywordsInput();
await keywordsInput.fill(keywords[0]); await keywordsInput.fill(keywords[0]);
await keywordsInput.press('Tab'); await keywordsInput.press('Tab');
// # Save the keyword // # Save the keyword
await channelPage.settingsModal.notificationsSettings.save(); await channelsPage.settingsModal.notificationsSettings.save();
// # Close the settings modal // # Close the settings modal
await channelPage.settingsModal.closeModal(); await channelsPage.settingsModal.closeModal();
// # Open the recent mentions // # Open the recent mentions
await channelPage.globalHeader.openRecentMentions(); await channelsPage.globalHeader.openRecentMentions();
// * Verify recent mentions is empty // * Verify recent mentions is empty
await channelPage.sidebarRight.toBeVisible(); await channelsPage.sidebarRight.toBeVisible();
await expect(channelPage.sidebarRight.container.getByText('No mentions yet')).toBeVisible(); await expect(channelsPage.sidebarRight.container.getByText('No mentions yet')).toBeVisible();
}); });
test('MM-T5465-5 Should highlight keywords in message sent from another user', async ({pw, pages}) => { test('MM-T5465-5 Should highlight keywords in message sent from another user', async ({pw}) => {
// # Skip test if no license // # Skip test if no license
await pw.skipIfNoLicense(); await pw.skipIfNoLicense();
@@ -239,7 +232,7 @@ test('MM-T5465-5 Should highlight keywords in message sent from another user', a
const channel = await adminClient.getChannelByName(team.id, 'town-square'); const channel = await adminClient.getChannelByName(team.id, 'town-square');
const highlightKeyword = keywords[0]; const highlightKeyword = keywords[0];
const messageWithKeyword = `This recieved message contains the ${highlightKeyword} keyword `; const messageWithKeyword = `This received message contains the ${highlightKeyword} keyword `;
// # Create a post containing the keyword in the channel by admin // # Create a post containing the keyword in the channel by admin
await adminClient.createPost( await adminClient.createPost(
@@ -251,36 +244,35 @@ test('MM-T5465-5 Should highlight keywords in message sent from another user', a
); );
// # Now log in as a user in new browser context // # Now log in as a user in new browser context
const {page} = await pw.testBrowser.login(user); const {channelsPage} = await pw.testBrowser.login(user);
// # Visit default channel page // # Visit default channel page
const channelPage = new pages.ChannelsPage(page); await channelsPage.goto();
await channelPage.goto(); await channelsPage.toBeVisible();
await channelPage.toBeVisible();
// # Open settings modal // # Open settings modal
await channelPage.globalHeader.openSettings(); await channelsPage.globalHeader.openSettings();
await channelPage.settingsModal.toBeVisible(); await channelsPage.settingsModal.toBeVisible();
// # Open notifications tab // # Open notifications tab
await channelPage.settingsModal.openNotificationsTab(); await channelsPage.settingsModal.openNotificationsTab();
// # Open keywords that get highlighted section // # Open keywords that get highlighted section
await channelPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight'); await channelsPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
// # Enter the keyword // # Enter the keyword
const keywordsInput = await channelPage.settingsModal.notificationsSettings.getKeywordsInput(); const keywordsInput = await channelsPage.settingsModal.notificationsSettings.getKeywordsInput();
await keywordsInput.fill(keywords[0]); await keywordsInput.fill(keywords[0]);
await keywordsInput.press('Tab'); await keywordsInput.press('Tab');
// # Save the keyword // # Save the keyword
await channelPage.settingsModal.notificationsSettings.save(); await channelsPage.settingsModal.notificationsSettings.save();
// # Close the settings modal // # Close the settings modal
await channelPage.settingsModal.closeModal(); await channelsPage.settingsModal.closeModal();
// * Verify that the keywords are highlighted in the last message recieved // * Verify that the keywords are highlighted in the last message received
const lastPostWithHighlight = await channelPage.centerView.getLastPost(); const lastPostWithHighlight = await channelsPage.centerView.getLastPost();
await expect(lastPostWithHighlight.container.getByText(messageWithKeyword)).toBeVisible(); await expect(lastPostWithHighlight.container.getByText(messageWithKeyword)).toBeVisible();
await expect(lastPostWithHighlight.container.getByText(highlightKeyword)).toHaveClass( await expect(lastPostWithHighlight.container.getByText(highlightKeyword)).toHaveClass(
highlightWithoutNotificationClass, highlightWithoutNotificationClass,

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

@@ -1,5 +1,6 @@
import {Page} from '@playwright/test'; import {Page} from '@playwright/test';
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
import {duration} from '@e2e-support/util';
// Helper function to intercept API request and modify the response // Helper function to intercept API request and modify the response
async function interceptConfigWithLandingPage(page: Page, enabled: boolean) { async function interceptConfigWithLandingPage(page: Page, enabled: boolean) {
@@ -16,9 +17,7 @@ async function interceptConfigWithLandingPage(page: Page, enabled: boolean) {
}); });
} }
test('MM-T5640_1 should not see landing page ', async ({pw, pages, page}) => { test('MM-T5640_1 should not see landing page ', async ({pw, page}) => {
const {adminClient} = await pw.getAdminClient();
const adminConfig = await adminClient.getConfig();
await interceptConfigWithLandingPage(page, false); await interceptConfigWithLandingPage(page, false);
// Navigate to your starting URL // Navigate to your starting URL
@@ -31,25 +30,19 @@ test('MM-T5640_1 should not see landing page ', async ({pw, pages, page}) => {
expect(page.url()).toContain('/login'); expect(page.url()).toContain('/login');
// Verify the login page is visible // Verify the login page is visible
const loginPage = new pages.LoginPage(page, adminConfig); await pw.loginPage.toBeVisible();
await loginPage.toBeVisible();
}); });
test('MM-T5640_2 should see landing page', async ({pages, isMobile, page}) => { test('MM-T5640_2 should see landing page', async ({pw, page}) => {
// Navigate to your starting URL // Navigate to your starting URL
await page.goto('/'); await page.goto('/');
await page.evaluate(() => localStorage.clear());
await page.goto('/');
// Wait until the URL contains '/landing' // Wait until the URL contains '/landing'
await page.waitForURL(/.*\/landing.*/); await page.waitForURL(/.*\/landing.*/, {timeout: duration.ten_sec});
// At this point, the URL should contain '/landing' // At this point, the URL should contain '/landing'
expect(page.url()).toContain('/landing'); expect(page.url()).toContain('/landing');
// Verify the landing page is visible // Verify the landing page is visible
const landingLoginPage = new pages.LandingLoginPage(page, isMobile); await pw.landingLoginPage.toBeVisible();
await landingLoginPage.toBeVisible();
}); });

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

@@ -4,8 +4,6 @@
import {TestBrowser} from '@e2e-support//browser_context'; import {TestBrowser} from '@e2e-support//browser_context';
import {Client, createRandomTeam, createRandomUser} from '@e2e-support/server'; import {Client, createRandomTeam, createRandomUser} from '@e2e-support/server';
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
import {components} from '@e2e-support/ui/components';
import {SystemConsolePage} from '@e2e-support/ui/pages/system_console';
import {getRandomId} from '@e2e-support/util'; import {getRandomId} from '@e2e-support/util';
import {UserProfile} from '@mattermost/types/users'; import {UserProfile} from '@mattermost/types/users';
@@ -15,10 +13,10 @@ import {UserProfile} from '@mattermost/types/users';
* @param pages * @param pages
* @returns A function to get the refreshed user, and the System Console page for navigation * @returns A function to get the refreshed user, and the System Console page for navigation
*/ */
async function setupAndGetRandomUser( async function setupAndGetRandomUser(pw: {
pw: {testBrowser: TestBrowser; initSetup: () => Promise<{adminUser: UserProfile | null; adminClient: Client}>}, testBrowser: TestBrowser;
pages: {SystemConsolePage: typeof SystemConsolePage}, initSetup: () => Promise<{adminUser: UserProfile | null; adminClient: Client}>;
) { }) {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -26,7 +24,7 @@ async function setupAndGetRandomUser(
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create a random user to edit for // # Create a random user to edit for
const user = await adminClient.createUser(createRandomUser(), '', ''); const user = await adminClient.createUser(createRandomUser(), '', '');
@@ -34,7 +32,6 @@ async function setupAndGetRandomUser(
await adminClient.addToTeam(team.id, user.id); await adminClient.addToTeam(team.id, user.id);
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -52,8 +49,8 @@ async function setupAndGetRandomUser(
return {getUser: () => adminClient.getUser(user.id), systemConsolePage}; return {getUser: () => adminClient.getUser(user.id), systemConsolePage};
} }
test('MM-T5520-1 should activate and deactivate users', async ({pw, pages}) => { test('MM-T5520-1 should activate and deactivate users', async ({pw}) => {
const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw, pages); const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw);
// # Open menu and deactivate the user // # Open menu and deactivate the user
await systemConsolePage.systemUsers.actionMenuButtons[0].click(); await systemConsolePage.systemUsers.actionMenuButtons[0].click();
@@ -61,8 +58,7 @@ test('MM-T5520-1 should activate and deactivate users', async ({pw, pages}) => {
await deactivate.click(); await deactivate.click();
// # Press confirm on the modal // # Press confirm on the modal
const confirmModal = new components.GenericConfirmModal(systemConsolePage.page); await systemConsolePage.confirmModal.confirm();
await confirmModal.confirm();
// * Verify user is deactivated // * Verify user is deactivated
const firstRow = await systemConsolePage.systemUsers.getNthRow(1); const firstRow = await systemConsolePage.systemUsers.getNthRow(1);
@@ -80,8 +76,8 @@ test('MM-T5520-1 should activate and deactivate users', async ({pw, pages}) => {
expect(await firstRow.innerText()).toContain('Member'); expect(await firstRow.innerText()).toContain('Member');
}); });
test('MM-T5520-2 should change user roles', async ({pw, pages}) => { test('MM-T5520-2 should change user roles', async ({pw}) => {
const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw, pages); const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw);
// # Open menu and click Manage roles // # Open menu and click Manage roles
await systemConsolePage.systemUsers.actionMenuButtons[0].click(); await systemConsolePage.systemUsers.actionMenuButtons[0].click();
@@ -121,8 +117,8 @@ test('MM-T5520-2 should change user roles', async ({pw, pages}) => {
expect((await getUser()).roles).toContain('system_user'); expect((await getUser()).roles).toContain('system_user');
}); });
test('MM-T5520-3 should be able to manage teams', async ({pw, pages}) => { test('MM-T5520-3 should be able to manage teams', async ({pw}) => {
const {systemConsolePage} = await setupAndGetRandomUser(pw, pages); const {systemConsolePage} = await setupAndGetRandomUser(pw);
// # Open menu and click Manage teams // # Open menu and click Manage teams
await systemConsolePage.systemUsers.actionMenuButtons[0].click(); await systemConsolePage.systemUsers.actionMenuButtons[0].click();
@@ -157,8 +153,8 @@ test('MM-T5520-3 should be able to manage teams', async ({pw, pages}) => {
expect(team).not.toBeVisible(); expect(team).not.toBeVisible();
}); });
test('MM-T5520-4 should reset the users password', async ({pw, pages}) => { test('MM-T5520-4 should reset the users password', async ({pw}) => {
const {systemConsolePage} = await setupAndGetRandomUser(pw, pages); const {systemConsolePage} = await setupAndGetRandomUser(pw);
// # Open menu and click Reset Password // # Open menu and click Reset Password
await systemConsolePage.systemUsers.actionMenuButtons[0].click(); await systemConsolePage.systemUsers.actionMenuButtons[0].click();
@@ -174,8 +170,8 @@ test('MM-T5520-4 should reset the users password', async ({pw, pages}) => {
await passwordInput.waitFor({state: 'detached'}); await passwordInput.waitFor({state: 'detached'});
}); });
test('MM-T5520-5 should change the users email', async ({pw, pages}) => { test('MM-T5520-5 should change the users email', async ({pw}) => {
const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw, pages); const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw);
const newEmail = `${getRandomId()}@example.com`; const newEmail = `${getRandomId()}@example.com`;
// # Open menu and click Update Email // # Open menu and click Update Email
@@ -197,8 +193,8 @@ test('MM-T5520-5 should change the users email', async ({pw, pages}) => {
expect((await getUser()).email).toEqual(newEmail); expect((await getUser()).email).toEqual(newEmail);
}); });
test('MM-T5520-6 should revoke sessions', async ({pw, pages}) => { test('MM-T5520-6 should revoke sessions', async ({pw}) => {
const {systemConsolePage} = await setupAndGetRandomUser(pw, pages); const {systemConsolePage} = await setupAndGetRandomUser(pw);
// # Open menu and revoke sessions // # Open menu and revoke sessions
await systemConsolePage.systemUsers.actionMenuButtons[0].click(); await systemConsolePage.systemUsers.actionMenuButtons[0].click();
@@ -206,8 +202,7 @@ test('MM-T5520-6 should revoke sessions', async ({pw, pages}) => {
await removeSessions.click(); await removeSessions.click();
// # Press confirm on the modal // # Press confirm on the modal
const confirmModal = new components.GenericConfirmModal(systemConsolePage.page); await systemConsolePage.confirmModal.confirm();
await confirmModal.confirm();
const firstRow = await systemConsolePage.systemUsers.getNthRow(1); const firstRow = await systemConsolePage.systemUsers.getNthRow(1);
expect(await firstRow.innerHTML()).not.toContain('class="error"'); expect(await firstRow.innerHTML()).not.toContain('class="error"');

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

@@ -7,7 +7,7 @@ import {test} from '@e2e-support/test_fixture';
import {createRandomUser} from '@e2e-support/server'; import {createRandomUser} from '@e2e-support/server';
import {simpleEmailRe} from '@e2e-support/util'; import {simpleEmailRe} from '@e2e-support/util';
test('MM-T5523-1 Sortable columns should sort the list when clicked', async ({pw, pages}) => { test('MM-T5523-1 Sortable columns should sort the list when clicked', async ({pw}) => {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -15,7 +15,7 @@ test('MM-T5523-1 Sortable columns should sort the list when clicked', async ({pw
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create 10 random users // # Create 10 random users
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {
@@ -23,7 +23,6 @@ test('MM-T5523-1 Sortable columns should sort the list when clicked', async ({pw
} }
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -52,7 +51,7 @@ test('MM-T5523-1 Sortable columns should sort the list when clicked', async ({pw
expect(firstRowEmailWithoutSort).not.toBe(firstRowEmailWithSort); expect(firstRowEmailWithoutSort).not.toBe(firstRowEmailWithSort);
}); });
test('MM-T5523-2 Non sortable columns should not sort the list when clicked', async ({pw, pages}) => { test('MM-T5523-2 Non sortable columns should not sort the list when clicked', async ({pw}) => {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -60,7 +59,7 @@ test('MM-T5523-2 Non sortable columns should not sort the list when clicked', as
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create 10 random users // # Create 10 random users
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {
@@ -68,7 +67,6 @@ test('MM-T5523-2 Non sortable columns should not sort the list when clicked', as
} }
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();

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

@@ -5,7 +5,7 @@ import {expect} from '@playwright/test';
import {test} from '@e2e-support/test_fixture'; import {test} from '@e2e-support/test_fixture';
test('MM-T5523-3 Should list the column names with checkboxes in the correct order', async ({pw, pages}) => { test('MM-T5523-3 Should list the column names with checkboxes in the correct order', async ({pw}) => {
const {adminUser} = await pw.initSetup(); const {adminUser} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -13,10 +13,9 @@ test('MM-T5523-3 Should list the column names with checkboxes in the correct ord
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -47,7 +46,7 @@ test('MM-T5523-3 Should list the column names with checkboxes in the correct ord
]); ]);
}); });
test('MM-T5523-4 Should allow certain columns to be checked and others to be disabled', async ({pw, pages}) => { test('MM-T5523-4 Should allow certain columns to be checked and others to be disabled', async ({pw}) => {
const {adminUser} = await pw.initSetup(); const {adminUser} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -55,10 +54,9 @@ test('MM-T5523-4 Should allow certain columns to be checked and others to be dis
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -83,7 +81,7 @@ test('MM-T5523-4 Should allow certain columns to be checked and others to be dis
expect(emailMenuItem).not.toBeDisabled(); expect(emailMenuItem).not.toBeDisabled();
}); });
test('MM-T5523-5 Should show/hide the columns which are toggled on/off', async ({pw, pages}) => { test('MM-T5523-5 Should show/hide the columns which are toggled on/off', async ({pw}) => {
const {adminUser} = await pw.initSetup(); const {adminUser} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -91,10 +89,9 @@ test('MM-T5523-5 Should show/hide the columns which are toggled on/off', async (
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();

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

@@ -5,9 +5,8 @@ import {expect} from '@playwright/test';
import {test} from '@e2e-support/test_fixture'; import {test} from '@e2e-support/test_fixture';
import {duration} from '@e2e-support/util'; import {duration} from '@e2e-support/util';
import {components} from '@e2e-support/ui/components';
test.fixme('MM-T5522 Should begin export of data when export button is pressed', async ({pw, pages}) => { test.fixme('MM-T5522 Should begin export of data when export button is pressed', async ({pw}) => {
test.slow(); test.slow();
// # Skip test if no license // # Skip test if no license
@@ -19,10 +18,9 @@ test.fixme('MM-T5522 Should begin export of data when export button is pressed',
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {page, channelsPage, systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -36,8 +34,7 @@ test.fixme('MM-T5522 Should begin export of data when export button is pressed',
// # Click Export button and confirm the modal // # Click Export button and confirm the modal
await systemConsolePage.systemUsers.exportButton.click(); await systemConsolePage.systemUsers.exportButton.click();
const confirmModal = new components.GenericConfirmModal(page, 'exportUserDataModal'); await systemConsolePage.exportModal.confirm();
await confirmModal.confirm();
// # Change the export duration to all time // # Change the export duration to all time
await systemConsolePage.systemUsers.dateRangeSelectorMenuButton.click(); await systemConsolePage.systemUsers.dateRangeSelectorMenuButton.click();
@@ -45,17 +42,16 @@ test.fixme('MM-T5522 Should begin export of data when export button is pressed',
// # Click Export button and confirm the modal // # Click Export button and confirm the modal
await systemConsolePage.systemUsers.exportButton.click(); await systemConsolePage.systemUsers.exportButton.click();
await confirmModal.confirm(); await systemConsolePage.exportModal.confirm();
// # Click Export again button and confirm the modal // # Click Export again button and confirm the modal
await systemConsolePage.systemUsers.exportButton.click(); await systemConsolePage.systemUsers.exportButton.click();
await confirmModal.confirm(); await systemConsolePage.exportModal.confirm();
// * Verify that we are told that one is already running // * Verify that we are told that one is already running
expect(page.getByText('Export is in progress')).toBeVisible(); expect(page.getByText('Export is in progress')).toBeVisible();
// # Go back to Channels and open the system bot DM // # Go back to Channels and open the system bot DM
const channelsPage = new pages.ChannelsPage(page);
channelsPage.goto('ad-1/messages', '@system-bot'); channelsPage.goto('ad-1/messages', '@system-bot');
await channelsPage.centerView.toBeVisible(); await channelsPage.centerView.toBeVisible();

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

@@ -4,7 +4,7 @@
import {test} from '@e2e-support/test_fixture'; import {test} from '@e2e-support/test_fixture';
import {createRandomTeam, createRandomUser} from '@e2e-support/server'; import {createRandomTeam, createRandomUser} from '@e2e-support/server';
test('MM-T5521-7 Should be able to filter users with team filter', async ({pw, pages}) => { test('MM-T5521-7 Should be able to filter users with team filter', async ({pw}) => {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -12,7 +12,7 @@ test('MM-T5521-7 Should be able to filter users with team filter', async ({pw, p
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create a team with a user // # Create a team with a user
const team1 = await adminClient.createTeam(createRandomTeam()); const team1 = await adminClient.createTeam(createRandomTeam());
@@ -25,7 +25,6 @@ test('MM-T5521-7 Should be able to filter users with team filter', async ({pw, p
await adminClient.addToTeam(team2.id, user2.id); await adminClient.addToTeam(team2.id, user2.id);
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -53,7 +52,7 @@ test('MM-T5521-7 Should be able to filter users with team filter', async ({pw, p
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email); await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
}); });
test('MM-T5521-8 Should be able to filter users with role filter', async ({pw, pages}) => { test('MM-T5521-8 Should be able to filter users with role filter', async ({pw}) => {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -61,7 +60,7 @@ test('MM-T5521-8 Should be able to filter users with role filter', async ({pw, p
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create a guest user // # Create a guest user
const guestUser = await adminClient.createUser(createRandomUser(), '', ''); const guestUser = await adminClient.createUser(createRandomUser(), '', '');
@@ -71,7 +70,6 @@ test('MM-T5521-8 Should be able to filter users with role filter', async ({pw, p
const regularUser = await adminClient.createUser(createRandomUser(), '', ''); const regularUser = await adminClient.createUser(createRandomUser(), '', '');
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -109,7 +107,7 @@ test('MM-T5521-8 Should be able to filter users with role filter', async ({pw, p
await systemConsolePage.systemUsers.verifyRowWithTextIsFound('No data'); await systemConsolePage.systemUsers.verifyRowWithTextIsFound('No data');
}); });
test('MM-T5521-9 Should be able to filter users with status filter', async ({pw, pages}) => { test('MM-T5521-9 Should be able to filter users with status filter', async ({pw}) => {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -117,7 +115,7 @@ test('MM-T5521-9 Should be able to filter users with status filter', async ({pw,
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create a user and then deactivate it // # Create a user and then deactivate it
const deactivatedUser = await adminClient.createUser(createRandomUser(), '', ''); const deactivatedUser = await adminClient.createUser(createRandomUser(), '', '');
@@ -127,7 +125,6 @@ test('MM-T5521-9 Should be able to filter users with status filter', async ({pw,
const regularUser = await adminClient.createUser(createRandomUser(), '', ''); const regularUser = await adminClient.createUser(createRandomUser(), '', '');
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();

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

@@ -5,7 +5,7 @@ import {test} from '@e2e-support/test_fixture';
import {createRandomUser} from '@e2e-support/server'; import {createRandomUser} from '@e2e-support/server';
import {getRandomId} from '@e2e-support/util'; import {getRandomId} from '@e2e-support/util';
test('MM-T5521-1 Should be able to search users with their first names', async ({pw, pages}) => { test('MM-T5521-1 Should be able to search users with their first names', async ({pw}) => {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -13,14 +13,13 @@ test('MM-T5521-1 Should be able to search users with their first names', async (
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create 2 users // # Create 2 users
const user1 = await adminClient.createUser(createRandomUser(), '', ''); const user1 = await adminClient.createUser(createRandomUser(), '', '');
const user2 = await adminClient.createUser(createRandomUser(), '', ''); const user2 = await adminClient.createUser(createRandomUser(), '', '');
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -38,7 +37,7 @@ test('MM-T5521-1 Should be able to search users with their first names', async (
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email); await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
}); });
test('MM-T5521-2 Should be able to search users with their last names', async ({pw, pages}) => { test('MM-T5521-2 Should be able to search users with their last names', async ({pw}) => {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -46,14 +45,13 @@ test('MM-T5521-2 Should be able to search users with their last names', async ({
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create 2 users // # Create 2 users
const user1 = await adminClient.createUser(createRandomUser(), '', ''); const user1 = await adminClient.createUser(createRandomUser(), '', '');
const user2 = await adminClient.createUser(createRandomUser(), '', ''); const user2 = await adminClient.createUser(createRandomUser(), '', '');
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -71,7 +69,7 @@ test('MM-T5521-2 Should be able to search users with their last names', async ({
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email); await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
}); });
test('MM-T5521-3 Should be able to search users with their emails', async ({pw, pages}) => { test('MM-T5521-3 Should be able to search users with their emails', async ({pw}) => {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -79,14 +77,13 @@ test('MM-T5521-3 Should be able to search users with their emails', async ({pw,
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create 2 users // # Create 2 users
const user1 = await adminClient.createUser(createRandomUser(), '', ''); const user1 = await adminClient.createUser(createRandomUser(), '', '');
const user2 = await adminClient.createUser(createRandomUser(), '', ''); const user2 = await adminClient.createUser(createRandomUser(), '', '');
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -104,7 +101,7 @@ test('MM-T5521-3 Should be able to search users with their emails', async ({pw,
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email); await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
}); });
test('MM-T5521-4 Should be able to search users with their usernames', async ({pw, pages}) => { test('MM-T5521-4 Should be able to search users with their usernames', async ({pw}) => {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -112,14 +109,13 @@ test('MM-T5521-4 Should be able to search users with their usernames', async ({p
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create 2 users // # Create 2 users
const user1 = await adminClient.createUser(createRandomUser(), '', ''); const user1 = await adminClient.createUser(createRandomUser(), '', '');
const user2 = await adminClient.createUser(createRandomUser(), '', ''); const user2 = await adminClient.createUser(createRandomUser(), '', '');
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -137,7 +133,7 @@ test('MM-T5521-4 Should be able to search users with their usernames', async ({p
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email); await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
}); });
test('MM-T5521-5 Should be able to search users with their nick names', async ({pw, pages}) => { test('MM-T5521-5 Should be able to search users with their nick names', async ({pw}) => {
const {adminUser, adminClient} = await pw.initSetup(); const {adminUser, adminClient} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -145,14 +141,13 @@ test('MM-T5521-5 Should be able to search users with their nick names', async ({
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Create 2 users // # Create 2 users
const user1 = await adminClient.createUser(createRandomUser(), '', ''); const user1 = await adminClient.createUser(createRandomUser(), '', '');
const user2 = await adminClient.createUser(createRandomUser(), '', ''); const user2 = await adminClient.createUser(createRandomUser(), '', '');
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();
@@ -169,7 +164,7 @@ test('MM-T5521-5 Should be able to search users with their nick names', async ({
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email); await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
}); });
test('MM-T5521-6 Should show no user is found when user doesnt exists', async ({pw, pages}) => { test('MM-T5521-6 Should show no user is found when user doesnt exists', async ({pw}) => {
const {adminUser} = await pw.initSetup(); const {adminUser} = await pw.initSetup();
if (!adminUser) { if (!adminUser) {
@@ -177,10 +172,9 @@ test('MM-T5521-6 Should show no user is found when user doesnt exists', async ({
} }
// # Log in as admin // # Log in as admin
const {page} = await pw.testBrowser.login(adminUser); const {systemConsolePage} = await pw.testBrowser.login(adminUser);
// # Visit system console // # Visit system console
const systemConsolePage = new pages.SystemConsolePage(page);
await systemConsolePage.goto(); await systemConsolePage.goto();
await systemConsolePage.toBeVisible(); await systemConsolePage.toBeVisible();

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

@@ -3,15 +3,14 @@
import {expect, test} from '@e2e-support/test_fixture'; import {expect, test} from '@e2e-support/test_fixture';
test.fixme('Intro to channel as regular user', async ({pw, pages, browserName, viewport}, testInfo) => { test.fixme('Intro to channel as regular user', async ({pw, 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();
// Log in a user in new browser context // Log in a user in new browser context
const {page} = await pw.testBrowser.login(user); const {page, channelsPage} = await pw.testBrowser.login(user);
// Visit a default channel page // Visit a default channel page
const channelsPage = new pages.ChannelsPage(page);
await channelsPage.goto(); await channelsPage.goto();
await channelsPage.toBeVisible(); await channelsPage.toBeVisible();
@@ -22,6 +21,6 @@ test.fixme('Intro to channel as regular user', async ({pw, pages, browserName, v
await pw.hideDynamicChannelsContent(page); await pw.hideDynamicChannelsContent(page);
// Match snapshot of channel intro page // Match snapshot of channel intro page
const testArgs = {page, browserName, viewport}; const testArgs = {page: page, browserName, viewport};
await pw.matchSnapshot(testInfo, testArgs); await pw.matchSnapshot(testInfo, testArgs);
}); });

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

@@ -3,11 +3,10 @@
import {test} from '@e2e-support/test_fixture'; import {test} from '@e2e-support/test_fixture';
test('/landing#/login', async ({pw, pages, page, isMobile, browserName, viewport}, testInfo) => { test('/landing#/login', async ({pw, page, browserName, viewport}, testInfo) => {
// Go to landing login page // Go to landing login page
const landingLoginPage = new pages.LandingLoginPage(page, isMobile); await pw.landingLoginPage.goto();
await landingLoginPage.goto(); await pw.landingLoginPage.toBeVisible();
await landingLoginPage.toBeVisible();
// Match snapshot of landing page // Match snapshot of landing page
await pw.matchSnapshot(testInfo, {page, browserName, viewport}); await pw.matchSnapshot(testInfo, {page, browserName, viewport});

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

@@ -3,27 +3,28 @@
import {test} from '@e2e-support/test_fixture'; import {test} from '@e2e-support/test_fixture';
test('/login', async ({pw, pages, page, browserName, viewport}, testInfo) => { test('/login', async ({pw, page, browserName, viewport}, testInfo) => {
// Set up the page not to redirect to the landing page
await pw.hasSeenLandingPage();
// Go to login page // Go to login page
const {adminClient} = await pw.getAdminClient(); const {adminClient} = await pw.getAdminClient();
const adminConfig = await adminClient.getConfig(); await pw.loginPage.goto();
const license = await adminClient.getClientLicenseOld(); await pw.loginPage.toBeVisible();
const loginPage = new pages.LoginPage(page, adminConfig);
await loginPage.goto();
await loginPage.toBeVisible();
// Click to other element to remove focus from email input // Click to other element to remove focus from email input
await loginPage.title.click(); await pw.loginPage.title.click();
// Match snapshot of login page // Match snapshot of login page
const testArgs = {page, browserName, viewport}; const testArgs = {page, browserName, viewport};
const license = await adminClient.getClientLicenseOld();
const editionSuffix = license.IsLicensed === 'true' ? '' : 'free edition'; const editionSuffix = license.IsLicensed === 'true' ? '' : 'free edition';
await pw.matchSnapshot({...testInfo, title: `${testInfo.title} ${editionSuffix}`}, testArgs); await pw.matchSnapshot({...testInfo, title: `${testInfo.title} ${editionSuffix}`}, testArgs);
// Click sign in button without entering user credential // Click sign in button without entering user credential
await loginPage.signInButton.click(); await pw.loginPage.signInButton.click();
await loginPage.userErrorLabel.waitFor(); await pw.loginPage.userErrorLabel.waitFor();
await pw.waitForAnimationEnd(loginPage.bodyCard); await pw.waitForAnimationEnd(pw.loginPage.bodyCard);
// Match snapshot of login page with error // Match snapshot of login page with error
await pw.matchSnapshot({...testInfo, title: `${testInfo.title} error ${editionSuffix}`}, testArgs); await pw.matchSnapshot({...testInfo, title: `${testInfo.title} error ${editionSuffix}`}, testArgs);

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

@@ -3,37 +3,37 @@
import {test} from '@e2e-support/test_fixture'; import {test} from '@e2e-support/test_fixture';
test('/signup_email', async ({pw, pages, page, browserName, viewport}, testInfo) => { test('/signup_email', async ({pw, page, browserName, viewport}, testInfo) => {
// Set up the page not to redirect to the landing page
await pw.hasSeenLandingPage();
// Go to login page // Go to login page
const {adminClient} = await pw.getAdminClient(); const {adminClient} = await pw.getAdminClient();
const adminConfig = await adminClient.getConfig(); await pw.loginPage.goto();
const license = await adminClient.getClientLicenseOld(); await pw.loginPage.toBeVisible();
const loginPage = new pages.LoginPage(page, adminConfig);
await loginPage.goto();
await loginPage.toBeVisible();
// Create an account // Create an account
await loginPage.createAccountLink.click(); await pw.loginPage.createAccountLink.click();
// Should have redirected to signup page // Should have redirected to signup page
const signupPage = new pw.pages.SignupPage(page); await pw.signupPage.toBeVisible();
await signupPage.toBeVisible();
// Click to other element to remove focus from email input // Click to other element to remove focus from email input
await signupPage.title.click(); await pw.signupPage.title.click();
// Match snapshot of signup_email page // Match snapshot of signup_email page
const testArgs = {page, browserName, viewport}; const testArgs = {page, browserName, viewport};
const license = await adminClient.getClientLicenseOld();
const editionSuffix = license.IsLicensed === 'true' ? '' : 'free edition'; const editionSuffix = license.IsLicensed === 'true' ? '' : 'free edition';
await pw.matchSnapshot({...testInfo, title: `${testInfo.title} ${editionSuffix}`}, testArgs); await pw.matchSnapshot({...testInfo, title: `${testInfo.title} ${editionSuffix}`}, testArgs);
// Click sign in button without entering user credential // Click sign in button without entering user credential
const invalidUser = {email: 'invalid', username: 'a', password: 'b'}; const invalidUser = {email: 'invalid', username: 'a', password: 'b'};
await signupPage.create(invalidUser, false); await pw.signupPage.create(invalidUser, false);
await signupPage.emailError.waitFor(); await pw.signupPage.emailError.waitFor();
await signupPage.usernameError.waitFor(); await pw.signupPage.usernameError.waitFor();
await signupPage.passwordError.waitFor(); await pw.signupPage.passwordError.waitFor();
await pw.waitForAnimationEnd(signupPage.bodyCard); await pw.waitForAnimationEnd(pw.signupPage.bodyCard);
// Match snapshot of signup_email page // Match snapshot of signup_email page
await pw.matchSnapshot({...testInfo, title: `${testInfo.title} error ${editionSuffix}`}, testArgs); await pw.matchSnapshot({...testInfo, title: `${testInfo.title} error ${editionSuffix}`}, testArgs);