playwright: restructure page and components model (#22602)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
19c7c6fa7a
Коммит
82c9d647b8
@@ -1,2 +1,3 @@
|
|||||||
results
|
|
||||||
node_modules
|
node_modules
|
||||||
|
playwright-report
|
||||||
|
test-results
|
||||||
|
|||||||
@@ -2,18 +2,10 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {expect} from '@playwright/test';
|
import {expect} from '@playwright/test';
|
||||||
import {AdminConfig} from '@mattermost/types/config';
|
|
||||||
import {UserProfile} from '@mattermost/types/users';
|
import {UserProfile} from '@mattermost/types/users';
|
||||||
import {PluginsResponse} from '@mattermost/types/plugins';
|
|
||||||
|
|
||||||
import {
|
import {Client, createRandomTeam, getAdminClient, getDefaultAdminUser, makeClient} from './support/server';
|
||||||
Client,
|
import {boardsPluginId, callsPluginId} from './support/constant';
|
||||||
createRandomTeam,
|
|
||||||
getAdminClient,
|
|
||||||
getDefaultAdminUser,
|
|
||||||
getOnPremServerConfig,
|
|
||||||
makeClient,
|
|
||||||
} from './support/server';
|
|
||||||
import {defaultTeam} from './support/util';
|
import {defaultTeam} from './support/util';
|
||||||
import testConfig from './test.config';
|
import testConfig from './test.config';
|
||||||
|
|
||||||
@@ -43,9 +35,6 @@ async function sysadminSetup(client: Client, user: UserProfile | null) {
|
|||||||
await client.verifyUserEmail(client.token);
|
await client.verifyUserEmail(client.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update default server config
|
|
||||||
const adminConfig = await client.updateConfig(getOnPremServerConfig());
|
|
||||||
|
|
||||||
// Log license and config info
|
// Log license and config info
|
||||||
await printLicenseInfo(client);
|
await printLicenseInfo(client);
|
||||||
await printClientInfo(client);
|
await printClientInfo(client);
|
||||||
@@ -75,9 +64,6 @@ async function sysadminSetup(client: Client, user: UserProfile | null) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log boards product status
|
|
||||||
printBoardsProductStatus(adminConfig);
|
|
||||||
|
|
||||||
// Ensure all products as plugin are installed and active.
|
// Ensure all products as plugin are installed and active.
|
||||||
await ensurePluginsLoaded(client);
|
await ensurePluginsLoaded(client);
|
||||||
|
|
||||||
@@ -110,9 +96,6 @@ async function printClientInfo(client: Client) {
|
|||||||
- BuildHash = ${config.BuildHash}
|
- BuildHash = ${config.BuildHash}
|
||||||
- BuildHashEnterprise = ${config.BuildHashEnterprise}
|
- BuildHashEnterprise = ${config.BuildHashEnterprise}
|
||||||
- BuildEnterpriseReady = ${config.BuildEnterpriseReady}
|
- BuildEnterpriseReady = ${config.BuildEnterpriseReady}
|
||||||
- BuildHashBoards = ${config.BuildHashBoards}
|
|
||||||
- BuildBoards = ${config.BuildBoards}
|
|
||||||
- BuildHashPlaybooks = ${config.BuildHashPlaybooks}
|
|
||||||
- FeatureFlagAppsEnabled = ${config.FeatureFlagAppsEnabled}
|
- FeatureFlagAppsEnabled = ${config.FeatureFlagAppsEnabled}
|
||||||
- FeatureFlagBoardsProduct = ${config.FeatureFlagBoardsProduct}
|
- FeatureFlagBoardsProduct = ${config.FeatureFlagBoardsProduct}
|
||||||
- FeatureFlagCallsEnabled = ${config.FeatureFlagCallsEnabled}
|
- FeatureFlagCallsEnabled = ${config.FeatureFlagCallsEnabled}
|
||||||
@@ -120,10 +103,10 @@ async function printClientInfo(client: Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getProductsAsPlugin() {
|
function getProductsAsPlugin() {
|
||||||
const productsAsPlugin = ['com.mattermost.calls', 'playbooks'];
|
const productsAsPlugin = [callsPluginId];
|
||||||
|
|
||||||
if (!testConfig.boardsProductEnabled) {
|
if (!testConfig.boardsProductEnabled) {
|
||||||
productsAsPlugin.push('focalboard');
|
productsAsPlugin.push(boardsPluginId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return productsAsPlugin;
|
return productsAsPlugin;
|
||||||
@@ -131,7 +114,7 @@ function getProductsAsPlugin() {
|
|||||||
|
|
||||||
async function ensurePluginsLoaded(client: Client) {
|
async function ensurePluginsLoaded(client: Client) {
|
||||||
const pluginStatus = await client.getPluginStatuses();
|
const pluginStatus = await client.getPluginStatuses();
|
||||||
const plugins = (await client.getPlugins()) as PluginsResponse;
|
const plugins = await client.getPlugins();
|
||||||
|
|
||||||
getProductsAsPlugin().forEach(async (pluginId) => {
|
getProductsAsPlugin().forEach(async (pluginId) => {
|
||||||
const isInstalled = pluginStatus.some((plugin) => plugin.plugin_id === pluginId);
|
const isInstalled = pluginStatus.some((plugin) => plugin.plugin_id === pluginId);
|
||||||
@@ -154,19 +137,8 @@ async function ensurePluginsLoaded(client: Client) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function printBoardsProductStatus(config: AdminConfig) {
|
|
||||||
// Ensure boards as product is enabled
|
|
||||||
if (!config.FeatureFlags.BoardsProduct) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log('FeatureFlags.BoardsProduct is disabled. Related visual test will fail.');
|
|
||||||
} else {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log('FeatureFlags.BoardsProduct is enabled.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function printPluginDetails(client: Client) {
|
async function printPluginDetails(client: Client) {
|
||||||
const plugins = (await client.getPlugins()) as PluginsResponse;
|
const plugins = await client.getPlugins();
|
||||||
|
|
||||||
if (plugins.active.length) {
|
if (plugins.active.length) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|||||||
15
e2e/playwright/package-lock.json
сгенерированный
15
e2e/playwright/package-lock.json
сгенерированный
@@ -9,6 +9,7 @@
|
|||||||
"@percy/cli": "1.18.0",
|
"@percy/cli": "1.18.0",
|
||||||
"@percy/playwright": "1.0.4",
|
"@percy/playwright": "1.0.4",
|
||||||
"@playwright/test": "1.30.0",
|
"@playwright/test": "1.30.0",
|
||||||
|
"async-wait-until": "2.0.12",
|
||||||
"chalk": "4.1.2",
|
"chalk": "4.1.2",
|
||||||
"deepmerge": "4.3.0",
|
"deepmerge": "4.3.0",
|
||||||
"dotenv": "16.0.3",
|
"dotenv": "16.0.3",
|
||||||
@@ -740,6 +741,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/async-wait-until": {
|
||||||
|
"version": "2.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/async-wait-until/-/async-wait-until-2.0.12.tgz",
|
||||||
|
"integrity": "sha512-SXy/vDs6UPJMG6YeEYOQ4ilA/JnGxk187KPGqFx9O+qVxsjkSl+jH+3P50qSNyMpEmDgr8qOFGOKCJckWb1i7A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.12.0",
|
||||||
|
"npm": ">= 1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/asynckit": {
|
"node_modules/asynckit": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
@@ -2861,6 +2871,11 @@
|
|||||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"async-wait-until": {
|
||||||
|
"version": "2.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/async-wait-until/-/async-wait-until-2.0.12.tgz",
|
||||||
|
"integrity": "sha512-SXy/vDs6UPJMG6YeEYOQ4ilA/JnGxk187KPGqFx9O+qVxsjkSl+jH+3P50qSNyMpEmDgr8qOFGOKCJckWb1i7A=="
|
||||||
|
},
|
||||||
"asynckit": {
|
"asynckit": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"@percy/cli": "1.18.0",
|
"@percy/cli": "1.18.0",
|
||||||
"@percy/playwright": "1.0.4",
|
"@percy/playwright": "1.0.4",
|
||||||
"@playwright/test": "1.30.0",
|
"@playwright/test": "1.30.0",
|
||||||
|
"async-wait-until": "2.0.12",
|
||||||
"chalk": "4.1.2",
|
"chalk": "4.1.2",
|
||||||
"deepmerge": "4.3.0",
|
"deepmerge": "4.3.0",
|
||||||
"dotenv": "16.0.3",
|
"dotenv": "16.0.3",
|
||||||
|
|||||||
@@ -24,9 +24,16 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
use: {
|
use: {
|
||||||
baseURL: testConfig.baseURL,
|
baseURL: testConfig.baseURL,
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
headless: testConfig.headless,
|
headless: testConfig.headless,
|
||||||
locale: 'en-US',
|
locale: 'en-US',
|
||||||
launchOptions: {
|
launchOptions: {
|
||||||
|
args: ['--use-fake-device-for-media-stream', '--use-fake-ui-for-media-stream'],
|
||||||
|
firefoxUserPrefs: {
|
||||||
|
'media.navigator.streams.fake': true,
|
||||||
|
'permissions.default.microphone': 1,
|
||||||
|
'permissions.default.camera': 1,
|
||||||
|
},
|
||||||
slowMo: testConfig.slowMo,
|
slowMo: testConfig.slowMo,
|
||||||
},
|
},
|
||||||
screenshot: 'only-on-failure',
|
screenshot: 'only-on-failure',
|
||||||
|
|||||||
56
e2e/playwright/sample.env
Обычный файл
56
e2e/playwright/sample.env
Обычный файл
@@ -0,0 +1,56 @@
|
|||||||
|
# 1. PW_BASE_URL
|
||||||
|
# - Default to "http://localhost:8065" if not set.
|
||||||
|
# - When running test inside the Playwright docker image
|
||||||
|
# PW_BASE_URL=http://host.docker.internal:8065
|
||||||
|
|
||||||
|
# 2. NODE_TLS_REJECT_UNAUTHORIZED
|
||||||
|
# This node environment variable disables the verification of local certificates. Set for local testing only.
|
||||||
|
# NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||||
|
|
||||||
|
# 3. PW_ADMIN_USERNAME
|
||||||
|
# - Default to "sysadmin" if not set.
|
||||||
|
|
||||||
|
# 4. PW_ADMIN_PASSWORD
|
||||||
|
# - Default to "Sys@dmin-sample1" if not set.
|
||||||
|
|
||||||
|
# 5. PW_ADMIN_EMAIL
|
||||||
|
# - Default to "sysadmin@sample.mattermost.com" if not set.
|
||||||
|
|
||||||
|
# 6. PW_BOARDS_PRODUCT_ENABLED
|
||||||
|
# - Default to "true" if not set. Used to correctly set server config.
|
||||||
|
|
||||||
|
# 7. PW_HA_CLUSTER_ENABLED
|
||||||
|
# - Default to "false" if not set. Set to true if the test server is with HA enabled.
|
||||||
|
|
||||||
|
# 8. PW_HA_CLUSTER_NODE_COUNT
|
||||||
|
# - Default to "2" if not set.
|
||||||
|
|
||||||
|
# 9. PW_HA_CLUSTER_NAME
|
||||||
|
# - Default to "mm_dev_cluster" if not set.
|
||||||
|
|
||||||
|
# 10. PW_RESET_BEFORE_TEST
|
||||||
|
# - Default to "false" if not set. If true, the setup deletes all teams and channels other than the default team which is "ad-1".
|
||||||
|
|
||||||
|
# 11. CI
|
||||||
|
# - Default to "false" if not set.
|
||||||
|
|
||||||
|
# 12. PW_HEADLESS
|
||||||
|
# - Default to "true" if not set. Set to false to run test in head mode.
|
||||||
|
|
||||||
|
# 13. PW_SLOWMO
|
||||||
|
# - Default to "0" if not set which means normal test speed run. Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
||||||
|
|
||||||
|
# 14. PW_WORKERS
|
||||||
|
# - Default to "1" if not set. The maximum number of concurrent worker processes to use for parallelizing tests.
|
||||||
|
|
||||||
|
# 15. PW_SNAPSHOT_ENABLE
|
||||||
|
# - Default to "false" if not set. Set to true to enable snapshot testing.
|
||||||
|
# Note that, snapshot testing should be done in Playwright docker image only.
|
||||||
|
# This is to ensure that, there's a common base platform for all contributors
|
||||||
|
# regardless of each local development platform.
|
||||||
|
|
||||||
|
# 16. PW_PERCY_ENABLE
|
||||||
|
# - Default to "false" if not set. Use to save and compare results via https://percy.io/.
|
||||||
|
|
||||||
|
# 17. PERCY_TOKEN
|
||||||
|
# - A token required by https://percy.io/.
|
||||||
@@ -15,12 +15,16 @@ export class TestBrowser {
|
|||||||
this.browser = browser;
|
this.browser = browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(user: UserProfile) {
|
async login(user: UserProfile | null) {
|
||||||
|
const options = {storageState: ''};
|
||||||
|
if (user) {
|
||||||
// Log in via API request and save user storage
|
// Log in via API request and save user storage
|
||||||
const storagePath = await loginByAPI(user.username, user.password);
|
const storagePath = await loginByAPI(user.username, user.password);
|
||||||
|
options.storageState = storagePath;
|
||||||
|
}
|
||||||
|
|
||||||
// Sign in a user in new browser context
|
// Sign in a user in new browser context
|
||||||
const context = await this.browser.newContext({storageState: storagePath});
|
const context = await this.browser.newContext(options);
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
|
|
||||||
return {context, page};
|
return {context, page};
|
||||||
|
|||||||
7
e2e/playwright/support/constant.ts
Обычный файл
7
e2e/playwright/support/constant.ts
Обычный файл
@@ -0,0 +1,7 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
export const boardsPluginId = 'focalboard';
|
||||||
|
export const boardsProductId = 'boards';
|
||||||
|
export const callsPluginId = 'com.mattermost.calls';
|
||||||
|
export const playbooksPluginId = 'playbooks';
|
||||||
@@ -5,6 +5,7 @@ import os from 'node:os';
|
|||||||
|
|
||||||
import {expect, test} from '@playwright/test';
|
import {expect, test} from '@playwright/test';
|
||||||
|
|
||||||
|
import {boardsPluginId, callsPluginId} from './constant';
|
||||||
import {getAdminClient} from './server/init';
|
import {getAdminClient} from './server/init';
|
||||||
import {isSmallScreen} from './util';
|
import {isSmallScreen} from './util';
|
||||||
|
|
||||||
@@ -14,12 +15,22 @@ export async function shouldHaveBoardsEnabled(enabled = true) {
|
|||||||
|
|
||||||
const boardsEnabled =
|
const boardsEnabled =
|
||||||
(typeof config.FeatureFlags.BoardsProduct === 'boolean' && config.FeatureFlags.BoardsProduct) ||
|
(typeof config.FeatureFlags.BoardsProduct === 'boolean' && config.FeatureFlags.BoardsProduct) ||
|
||||||
config.PluginSettings.PluginStates['focalboard'].Enable;
|
config.PluginSettings.PluginStates[boardsPluginId].Enable;
|
||||||
|
|
||||||
const matched = boardsEnabled === enabled;
|
const matched = boardsEnabled === enabled;
|
||||||
expect(matched, matched ? '' : `Boards expect "${enabled}" but actual "${boardsEnabled}"`).toBeTruthy();
|
expect(matched, matched ? '' : `Boards expect "${enabled}" but actual "${boardsEnabled}"`).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function shouldHaveCallsEnabled(enabled = true) {
|
||||||
|
const {adminClient} = await getAdminClient();
|
||||||
|
const config = await adminClient.getConfig();
|
||||||
|
|
||||||
|
const callsEnabled = config.PluginSettings.PluginStates[callsPluginId].Enable;
|
||||||
|
|
||||||
|
const matched = callsEnabled === enabled;
|
||||||
|
expect(matched, matched ? '' : `Calls expect "${enabled}" but actual "${callsEnabled}"`).toBeTruthy();
|
||||||
|
}
|
||||||
|
|
||||||
export async function shouldHaveFeatureFlag(name: string, value: string | boolean) {
|
export async function shouldHaveFeatureFlag(name: string, value: string | boolean) {
|
||||||
const {adminClient} = await getAdminClient();
|
const {adminClient} = await getAdminClient();
|
||||||
const config = await adminClient.getConfig();
|
const config = await adminClient.getConfig();
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ const onPremServerConfig = (): Partial<TestAdminConfig> => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Should be based only from the generated default config from mattermost-server via "make config-reset"
|
// Should be based only from the generated default config from ./server via "make config-reset"
|
||||||
// Based on v7.9 server
|
// Based on v7.10 server
|
||||||
const defaultServerConfig: AdminConfig = {
|
const defaultServerConfig: AdminConfig = {
|
||||||
ServiceSettings: {
|
ServiceSettings: {
|
||||||
SiteURL: '',
|
SiteURL: '',
|
||||||
@@ -180,9 +180,6 @@ const defaultServerConfig: AdminConfig = {
|
|||||||
EnableCustomGroups: true,
|
EnableCustomGroups: true,
|
||||||
SelfHostedPurchase: true,
|
SelfHostedPurchase: true,
|
||||||
AllowSyncedDrafts: true,
|
AllowSyncedDrafts: true,
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
SelfHostedExpansion: false,
|
SelfHostedExpansion: false,
|
||||||
},
|
},
|
||||||
TeamSettings: {
|
TeamSettings: {
|
||||||
@@ -636,7 +633,7 @@ const defaultServerConfig: AdminConfig = {
|
|||||||
Enable: true,
|
Enable: true,
|
||||||
},
|
},
|
||||||
focalboard: {
|
focalboard: {
|
||||||
Enable: false,
|
Enable: true,
|
||||||
},
|
},
|
||||||
playbooks: {
|
playbooks: {
|
||||||
Enable: true,
|
Enable: true,
|
||||||
@@ -689,13 +686,12 @@ const defaultServerConfig: AdminConfig = {
|
|||||||
GraphQL: false,
|
GraphQL: false,
|
||||||
InsightsEnabled: true,
|
InsightsEnabled: true,
|
||||||
CommandPalette: false,
|
CommandPalette: false,
|
||||||
BoardsProduct: true,
|
BoardsProduct: false,
|
||||||
SendWelcomePost: true,
|
SendWelcomePost: true,
|
||||||
WorkTemplate: false,
|
WorkTemplate: false,
|
||||||
PostPriority: true,
|
PostPriority: true,
|
||||||
WysiwygEditor: false,
|
WysiwygEditor: false,
|
||||||
PeopleProduct: false,
|
PeopleProduct: false,
|
||||||
AnnualSubscription: false,
|
|
||||||
ReduceOnBoardingTaskList: false,
|
ReduceOnBoardingTaskList: false,
|
||||||
OnboardingAutoShowLinkedBoard: true,
|
OnboardingAutoShowLinkedBoard: true,
|
||||||
ThreadsEverywhere: false,
|
ThreadsEverywhere: false,
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
import {Locator, Page} from '@playwright/test';
|
import {Locator, Page} from '@playwright/test';
|
||||||
|
|
||||||
|
export {waitUntil} from 'async-wait-until';
|
||||||
|
|
||||||
const visibilityHidden = 'visibility: hidden !important;';
|
const visibilityHidden = 'visibility: hidden !important;';
|
||||||
const hideTeamHeader = `.test-team-header {${visibilityHidden}} `;
|
const hideTeamHeader = `.test-team-header {${visibilityHidden}} `;
|
||||||
const hidePostHeaderTime = `.post__time {${visibilityHidden}} `;
|
const hidePostHeaderTime = `.post__time {${visibilityHidden}} `;
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
import {test as base, Browser} from '@playwright/test';
|
import {test as base, Browser} from '@playwright/test';
|
||||||
|
|
||||||
import {TestBrowser} from './browser_context';
|
import {TestBrowser} from './browser_context';
|
||||||
import {shouldHaveBoardsEnabled, shouldHaveFeatureFlag, shouldSkipInSmallScreen, shouldRunInLinux} from './flag';
|
import {
|
||||||
|
shouldHaveBoardsEnabled,
|
||||||
|
shouldHaveCallsEnabled,
|
||||||
|
shouldHaveFeatureFlag,
|
||||||
|
shouldSkipInSmallScreen,
|
||||||
|
shouldRunInLinux,
|
||||||
|
} from './flag';
|
||||||
import {initSetup, getAdminClient} from './server';
|
import {initSetup, getAdminClient} from './server';
|
||||||
import {hideDynamicChannelsContent, waitForAnimationEnd} 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';
|
||||||
|
|
||||||
@@ -30,24 +36,26 @@ class PlaywrightExtended {
|
|||||||
readonly testBrowser: TestBrowser;
|
readonly testBrowser: TestBrowser;
|
||||||
|
|
||||||
// ./flag
|
// ./flag
|
||||||
readonly shouldHaveBoardsEnabled: typeof shouldHaveBoardsEnabled;
|
readonly shouldHaveBoardsEnabled;
|
||||||
readonly shouldHaveFeatureFlag: typeof shouldHaveFeatureFlag;
|
readonly shouldHaveCallsEnabled;
|
||||||
readonly shouldSkipInSmallScreen: typeof shouldSkipInSmallScreen;
|
readonly shouldHaveFeatureFlag;
|
||||||
readonly shouldRunInLinux: typeof shouldRunInLinux;
|
readonly shouldSkipInSmallScreen;
|
||||||
|
readonly shouldRunInLinux;
|
||||||
|
|
||||||
// ./server
|
// ./server
|
||||||
readonly getAdminClient: typeof getAdminClient;
|
readonly getAdminClient;
|
||||||
readonly initSetup: typeof initSetup;
|
readonly initSetup;
|
||||||
|
|
||||||
// ./test_action
|
// ./test_action
|
||||||
readonly hideDynamicChannelsContent: typeof hideDynamicChannelsContent;
|
readonly hideDynamicChannelsContent;
|
||||||
readonly waitForAnimationEnd: typeof waitForAnimationEnd;
|
readonly waitForAnimationEnd;
|
||||||
|
readonly waitUntil;
|
||||||
|
|
||||||
// ./ui/pages
|
// ./ui/pages
|
||||||
readonly pages: typeof pages;
|
readonly pages;
|
||||||
|
|
||||||
// ./visual
|
// ./visual
|
||||||
readonly matchSnapshot: typeof matchSnapshot;
|
readonly matchSnapshot;
|
||||||
|
|
||||||
constructor(browser: Browser) {
|
constructor(browser: Browser) {
|
||||||
// ./browser_context
|
// ./browser_context
|
||||||
@@ -55,6 +63,7 @@ class PlaywrightExtended {
|
|||||||
|
|
||||||
// ./flag
|
// ./flag
|
||||||
this.shouldHaveBoardsEnabled = shouldHaveBoardsEnabled;
|
this.shouldHaveBoardsEnabled = shouldHaveBoardsEnabled;
|
||||||
|
this.shouldHaveCallsEnabled = shouldHaveCallsEnabled;
|
||||||
this.shouldHaveFeatureFlag = shouldHaveFeatureFlag;
|
this.shouldHaveFeatureFlag = shouldHaveFeatureFlag;
|
||||||
this.shouldSkipInSmallScreen = shouldSkipInSmallScreen;
|
this.shouldSkipInSmallScreen = shouldSkipInSmallScreen;
|
||||||
this.shouldRunInLinux = shouldRunInLinux;
|
this.shouldRunInLinux = shouldRunInLinux;
|
||||||
@@ -66,6 +75,7 @@ class PlaywrightExtended {
|
|||||||
// ./test_action
|
// ./test_action
|
||||||
this.hideDynamicChannelsContent = hideDynamicChannelsContent;
|
this.hideDynamicChannelsContent = hideDynamicChannelsContent;
|
||||||
this.waitForAnimationEnd = waitForAnimationEnd;
|
this.waitForAnimationEnd = waitForAnimationEnd;
|
||||||
|
this.waitUntil = waitUntil;
|
||||||
|
|
||||||
// ./ui/pages
|
// ./ui/pages
|
||||||
this.pages = pages;
|
this.pages = pages;
|
||||||
|
|||||||
@@ -4,22 +4,23 @@
|
|||||||
import {expect, Locator} from '@playwright/test';
|
import {expect, Locator} from '@playwright/test';
|
||||||
|
|
||||||
export default class BoardsCreateModal {
|
export default class BoardsCreateModal {
|
||||||
readonly locator: Locator;
|
readonly container: Locator;
|
||||||
readonly productSwitchMenu: Locator;
|
|
||||||
|
|
||||||
constructor(locator: Locator) {
|
readonly productSwitchMenu;
|
||||||
this.locator = locator;
|
|
||||||
|
|
||||||
this.productSwitchMenu = locator.getByRole('button', {name: 'Product switch menu'});
|
constructor(container: Locator) {
|
||||||
|
this.container = container;
|
||||||
|
|
||||||
|
this.productSwitchMenu = container.getByRole('button', {name: 'Product switch menu'});
|
||||||
}
|
}
|
||||||
|
|
||||||
async switchProduct(name: string) {
|
async switchProduct(name: string) {
|
||||||
await this.productSwitchMenu.click();
|
await this.productSwitchMenu.click();
|
||||||
await this.locator.getByRole('link', {name: ` ${name}`}).click();
|
await this.container.getByRole('link', {name: ` ${name}`}).click();
|
||||||
}
|
}
|
||||||
|
|
||||||
async toBeVisible(name: string) {
|
async toBeVisible(name: string) {
|
||||||
await expect(this.locator.getByRole('heading', {name})).toBeVisible();
|
await expect(this.container.getByRole('heading', {name})).toBeVisible();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import {Locator} from '@playwright/test';
|
|||||||
|
|
||||||
export default class BoardsSidebar {
|
export default class BoardsSidebar {
|
||||||
readonly container: Locator;
|
readonly container: Locator;
|
||||||
readonly plusButton: Locator;
|
|
||||||
readonly createNewBoardMenuItem: Locator;
|
readonly plusButton;
|
||||||
readonly createNewCategoryMenuItem: Locator;
|
readonly createNewBoardMenuItem;
|
||||||
readonly titles: Locator;
|
readonly createNewCategoryMenuItem;
|
||||||
|
readonly titles;
|
||||||
|
|
||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import {expect, Locator} from '@playwright/test';
|
|||||||
|
|
||||||
export default class ChannelsAppBar {
|
export default class ChannelsAppBar {
|
||||||
readonly container: Locator;
|
readonly container: Locator;
|
||||||
readonly playbooksIcon: Locator;
|
|
||||||
|
readonly playbooksIcon;
|
||||||
|
|
||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|||||||
18
e2e/playwright/support/ui/components/channels/header.ts
Обычный файл
18
e2e/playwright/support/ui/components/channels/header.ts
Обычный файл
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, Locator} from '@playwright/test';
|
||||||
|
|
||||||
|
export default class ChannelsHeader {
|
||||||
|
readonly container: Locator;
|
||||||
|
|
||||||
|
constructor(container: Locator) {
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBeVisible() {
|
||||||
|
await expect(this.container).toBeVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {ChannelsHeader};
|
||||||
@@ -5,12 +5,17 @@ import {expect, Locator} from '@playwright/test';
|
|||||||
|
|
||||||
export default class ChannelsPost {
|
export default class ChannelsPost {
|
||||||
readonly container: Locator;
|
readonly container: Locator;
|
||||||
readonly profileIcon: Locator;
|
|
||||||
|
readonly body;
|
||||||
|
readonly profileIcon;
|
||||||
|
readonly replyButton;
|
||||||
|
|
||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|
||||||
|
this.body = container.locator('.post__body');
|
||||||
this.profileIcon = container.locator('.profile-icon');
|
this.profileIcon = container.locator('.profile-icon');
|
||||||
|
this.replyButton = container.getByRole('button', {name: 'reply'});
|
||||||
}
|
}
|
||||||
|
|
||||||
async toBeVisible() {
|
async toBeVisible() {
|
||||||
@@ -26,6 +31,12 @@ export default class ChannelsPost {
|
|||||||
async getProfileImage(username: string) {
|
async getProfileImage(username: string) {
|
||||||
return await this.profileIcon.getByAltText(`${username} profile image`);
|
return await this.profileIcon.getByAltText(`${username} profile image`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async openRHS() {
|
||||||
|
await this.container.hover();
|
||||||
|
await this.replyButton.waitFor();
|
||||||
|
await this.replyButton.click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {ChannelsPost};
|
export {ChannelsPost};
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ import {expect, Locator} from '@playwright/test';
|
|||||||
|
|
||||||
export default class ChannelsPostCreate {
|
export default class ChannelsPostCreate {
|
||||||
readonly container: Locator;
|
readonly container: Locator;
|
||||||
readonly input: Locator;
|
|
||||||
readonly attachmentButton: Locator;
|
readonly input;
|
||||||
readonly emojiButton: Locator;
|
readonly attachmentButton;
|
||||||
|
readonly emojiButton;
|
||||||
|
|
||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|||||||
18
e2e/playwright/support/ui/components/channels/sidebar_right.ts
Обычный файл
18
e2e/playwright/support/ui/components/channels/sidebar_right.ts
Обычный файл
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, Locator} from '@playwright/test';
|
||||||
|
|
||||||
|
export default class ChannelsSidebarRight {
|
||||||
|
readonly container: Locator;
|
||||||
|
|
||||||
|
constructor(container: Locator) {
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBeVisible() {
|
||||||
|
await expect(this.container).toBeVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {ChannelsSidebarRight};
|
||||||
@@ -5,7 +5,8 @@ import {expect, Locator} from '@playwright/test';
|
|||||||
|
|
||||||
export default class GlobalHeader {
|
export default class GlobalHeader {
|
||||||
readonly container: Locator;
|
readonly container: Locator;
|
||||||
readonly productSwitchMenu: Locator;
|
|
||||||
|
readonly productSwitchMenu;
|
||||||
|
|
||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|||||||
@@ -2,17 +2,30 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {BoardsSidebar} from './boards/sidebar';
|
import {BoardsSidebar} from './boards/sidebar';
|
||||||
|
import {ChannelsHeader} from './channels/header';
|
||||||
import {ChannelsAppBar} from './channels/app_bar';
|
import {ChannelsAppBar} from './channels/app_bar';
|
||||||
import {ChannelsPostCreate} from './channels/post_create';
|
import {ChannelsPostCreate} from './channels/post_create';
|
||||||
import {ChannelsPost} from './channels/post';
|
import {ChannelsPost} from './channels/post';
|
||||||
|
import {ChannelsSidebarRight} from './channels/sidebar_right';
|
||||||
import {GlobalHeader} from './global_header';
|
import {GlobalHeader} from './global_header';
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
BoardsSidebar,
|
BoardsSidebar,
|
||||||
ChannelsAppBar,
|
ChannelsAppBar,
|
||||||
|
ChannelsHeader,
|
||||||
ChannelsPostCreate,
|
ChannelsPostCreate,
|
||||||
ChannelsPost,
|
ChannelsPost,
|
||||||
|
ChannelsSidebarRight,
|
||||||
GlobalHeader,
|
GlobalHeader,
|
||||||
};
|
};
|
||||||
|
|
||||||
export {components, BoardsSidebar, ChannelsAppBar, ChannelsPostCreate, ChannelsPost, GlobalHeader};
|
export {
|
||||||
|
components,
|
||||||
|
BoardsSidebar,
|
||||||
|
ChannelsAppBar,
|
||||||
|
ChannelsHeader,
|
||||||
|
ChannelsPostCreate,
|
||||||
|
ChannelsPost,
|
||||||
|
ChannelsSidebarRight,
|
||||||
|
GlobalHeader,
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
// 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, Page} from '@playwright/test';
|
||||||
|
|
||||||
import {GlobalHeader} from '@e2e-support/ui/components';
|
import {components} from '@e2e-support/ui/components';
|
||||||
|
|
||||||
export default class BoardsCreatePage {
|
export default class BoardsCreatePage {
|
||||||
readonly boards = 'Boards';
|
readonly boards = 'Boards';
|
||||||
readonly page: Page;
|
readonly page: Page;
|
||||||
readonly globalHeader: GlobalHeader;
|
|
||||||
readonly createBoardHeading: Locator;
|
readonly globalHeader;
|
||||||
readonly createEmptyBoardButton: Locator;
|
|
||||||
readonly useTemplateButton: Locator;
|
readonly createBoardHeading;
|
||||||
|
readonly createEmptyBoardButton;
|
||||||
|
readonly useTemplateButton;
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
this.globalHeader = new GlobalHeader(this.page.locator('#global-header'));
|
this.globalHeader = new components.GlobalHeader(this.page.locator('#global-header'));
|
||||||
this.createBoardHeading = page.getByRole('heading', {name: 'Create a board'});
|
this.createBoardHeading = page.getByRole('heading', {name: 'Create a board'});
|
||||||
this.createEmptyBoardButton = page.getByRole('button', {name: ' Create an empty board'});
|
this.createEmptyBoardButton = page.getByRole('button', {name: ' Create an empty board'});
|
||||||
this.useTemplateButton = page.getByRole('button', {name: 'Use this template'});
|
this.useTemplateButton = page.getByRole('button', {name: 'Use this template'});
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
// 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, Page} from '@playwright/test';
|
||||||
|
|
||||||
import {BoardsSidebar, GlobalHeader} from '@e2e-support/ui/components';
|
import {components} from '@e2e-support/ui/components';
|
||||||
|
|
||||||
export default class BoardsViewPage {
|
export default class BoardsViewPage {
|
||||||
readonly boards = 'Boards';
|
readonly boards = 'Boards';
|
||||||
readonly page: Page;
|
readonly page: Page;
|
||||||
readonly sidebar: BoardsSidebar;
|
|
||||||
readonly globalHeader: GlobalHeader;
|
readonly sidebar;
|
||||||
readonly topHead: Locator;
|
readonly globalHeader;
|
||||||
readonly editableTitle: Locator;
|
|
||||||
readonly shareButton: Locator;
|
readonly topHead;
|
||||||
|
readonly editableTitle;
|
||||||
|
readonly shareButton;
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
this.sidebar = new BoardsSidebar(page.locator('.octo-sidebar'));
|
this.sidebar = new components.BoardsSidebar(page.locator('.octo-sidebar'));
|
||||||
this.globalHeader = new GlobalHeader(this.page.locator('#global-header'));
|
this.globalHeader = new components.GlobalHeader(this.page.locator('#global-header'));
|
||||||
this.topHead = page.locator('.top-head');
|
this.topHead = page.locator('.top-head');
|
||||||
this.editableTitle = this.topHead.getByPlaceholder('Untitled board');
|
this.editableTitle = this.topHead.getByPlaceholder('Untitled board');
|
||||||
this.shareButton = page.getByRole('button', {name: ' Share'});
|
this.shareButton = page.getByRole('button', {name: ' Share'});
|
||||||
|
|||||||
@@ -3,27 +3,32 @@
|
|||||||
|
|
||||||
import {Page} from '@playwright/test';
|
import {Page} from '@playwright/test';
|
||||||
|
|
||||||
import {ChannelsAppBar, ChannelsPost, ChannelsPostCreate, GlobalHeader} from '@e2e-support/ui/components';
|
import {waitUntil} from '@e2e-support/test_action';
|
||||||
import {isSmallScreen} from '@e2e-support/util';
|
import {components} from '@e2e-support/ui/components';
|
||||||
|
import {duration, isSmallScreen} from '@e2e-support/util';
|
||||||
|
|
||||||
export default class ChannelsPage {
|
export default class ChannelsPage {
|
||||||
readonly channels = 'Channels';
|
readonly channels = 'Channels';
|
||||||
readonly page: Page;
|
readonly page: Page;
|
||||||
readonly postCreate: ChannelsPostCreate;
|
readonly postCreate;
|
||||||
readonly globalHeader: GlobalHeader;
|
readonly globalHeader;
|
||||||
readonly appBar: ChannelsAppBar;
|
readonly header;
|
||||||
|
readonly appBar;
|
||||||
|
readonly sidebarRight;
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
this.postCreate = new ChannelsPostCreate(page.locator('#post-create'));
|
this.postCreate = new components.ChannelsPostCreate(page.locator('#post-create'));
|
||||||
this.globalHeader = new GlobalHeader(this.page.locator('#global-header'));
|
this.globalHeader = new components.GlobalHeader(page.locator('#global-header'));
|
||||||
this.appBar = new ChannelsAppBar(page.locator('.app-bar'));
|
this.header = new components.ChannelsHeader(page.locator('.channel-header'));
|
||||||
|
this.appBar = new components.ChannelsAppBar(page.locator('.app-bar'));
|
||||||
|
this.sidebarRight = new components.ChannelsSidebarRight(page.locator('#sidebar-right'));
|
||||||
}
|
}
|
||||||
|
|
||||||
async goto(teamName = '', channelName = '') {
|
async goto(teamName = '', channelName = '') {
|
||||||
let channelsUrl = '/';
|
let channelsUrl = '/';
|
||||||
if (teamName) {
|
if (teamName) {
|
||||||
channelsUrl += `/${teamName}`;
|
channelsUrl += `${teamName}`;
|
||||||
if (channelName) {
|
if (channelName) {
|
||||||
channelsUrl += `/${channelName}`;
|
channelsUrl += `/${channelName}`;
|
||||||
}
|
}
|
||||||
@@ -47,25 +52,54 @@ export default class ChannelsPage {
|
|||||||
async getFirstPost() {
|
async getFirstPost() {
|
||||||
await this.page.getByTestId('postView').first().waitFor();
|
await this.page.getByTestId('postView').first().waitFor();
|
||||||
const post = await this.page.getByTestId('postView').first();
|
const post = await this.page.getByTestId('postView').first();
|
||||||
return new ChannelsPost(post);
|
return new components.ChannelsPost(post);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLastPost() {
|
async getLastPost() {
|
||||||
await this.page.getByTestId('postView').last().waitFor();
|
await this.page.getByTestId('postView').last().waitFor();
|
||||||
const post = await this.page.getByTestId('postView').last();
|
const post = await this.page.getByTestId('postView').last();
|
||||||
return new ChannelsPost(post);
|
return new components.ChannelsPost(post);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNthPost(index: number) {
|
async getNthPost(index: number) {
|
||||||
await this.page.getByTestId('postView').nth(index).waitFor();
|
await this.page.getByTestId('postView').nth(index).waitFor();
|
||||||
const post = await this.page.getByTestId('postView').nth(index);
|
const post = await this.page.getByTestId('postView').nth(index);
|
||||||
return new ChannelsPost(post);
|
return new components.ChannelsPost(post);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPostById(id: string) {
|
async getPostById(id: string) {
|
||||||
await this.page.locator(`[id="post_${id}"]`).waitFor();
|
await this.page.locator(`[id="post_${id}"]`).waitFor();
|
||||||
const post = await this.page.locator(`[id="post_${id}"]`);
|
const post = await this.page.locator(`[id="post_${id}"]`);
|
||||||
return new ChannelsPost(post);
|
return new components.ChannelsPost(post);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRHSPostById(id: string) {
|
||||||
|
await this.page.locator(`[id="rhsPost_${id}"]`).waitFor();
|
||||||
|
const post = await this.page.locator(`[id="rhsPost_${id}"]`);
|
||||||
|
return new components.ChannelsPost(post);
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitUntilLastPostContains(text: string, timeout = duration.ten_sec) {
|
||||||
|
await waitUntil(
|
||||||
|
async () => {
|
||||||
|
const post = await this.getLastPost();
|
||||||
|
const content = await post.container.textContent();
|
||||||
|
return content?.includes(text);
|
||||||
|
},
|
||||||
|
{timeout}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitUntilPostWithIdContains(id: string, text: string, timeout = duration.ten_sec) {
|
||||||
|
await waitUntil(
|
||||||
|
async () => {
|
||||||
|
const post = await this.getPostById(id);
|
||||||
|
const content = await post.container.textContent();
|
||||||
|
|
||||||
|
return content?.includes(text);
|
||||||
|
},
|
||||||
|
{timeout}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
// 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, Page} from '@playwright/test';
|
||||||
|
|
||||||
export default class LandingLoginPage {
|
export default class LandingLoginPage {
|
||||||
readonly page: Page;
|
readonly page: Page;
|
||||||
|
|
||||||
readonly isMobile?: boolean;
|
readonly isMobile?: boolean;
|
||||||
readonly viewInAppButton: Locator;
|
|
||||||
readonly viewInDesktopAppButton: Locator;
|
readonly viewInAppButton;
|
||||||
readonly viewInBrowserButton: Locator;
|
readonly viewInDesktopAppButton;
|
||||||
|
readonly viewInBrowserButton;
|
||||||
|
|
||||||
constructor(page: Page, isMobile?: boolean) {
|
constructor(page: Page, isMobile?: boolean) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
|
|||||||
@@ -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, Page} from '@playwright/test';
|
||||||
|
|
||||||
import {AdminConfig} from '@mattermost/types/config';
|
import {AdminConfig} from '@mattermost/types/config';
|
||||||
import {UserProfile} from '@mattermost/types/users';
|
import {UserProfile} from '@mattermost/types/users';
|
||||||
@@ -10,18 +10,19 @@ export default class LoginPage {
|
|||||||
readonly adminConfig: AdminConfig;
|
readonly adminConfig: AdminConfig;
|
||||||
|
|
||||||
readonly page: Page;
|
readonly page: Page;
|
||||||
readonly title: Locator;
|
|
||||||
readonly subtitle: Locator;
|
readonly title;
|
||||||
readonly bodyCard: Locator;
|
readonly subtitle;
|
||||||
readonly loginInput: Locator;
|
readonly bodyCard;
|
||||||
readonly loginPlaceholder: Locator;
|
readonly loginInput;
|
||||||
readonly passwordInput: Locator;
|
readonly loginPlaceholder;
|
||||||
readonly signInButton: Locator;
|
readonly passwordInput;
|
||||||
readonly createAccountLink: Locator;
|
readonly signInButton;
|
||||||
readonly forgotPasswordLink: Locator;
|
readonly createAccountLink;
|
||||||
readonly userErrorLabel: Locator;
|
readonly forgotPasswordLink;
|
||||||
readonly fieldWithError: Locator;
|
readonly userErrorLabel;
|
||||||
readonly formContainer: Locator;
|
readonly fieldWithError;
|
||||||
|
readonly formContainer;
|
||||||
|
|
||||||
constructor(page: Page, adminConfig: AdminConfig) {
|
constructor(page: Page, adminConfig: AdminConfig) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
// 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, Page} from '@playwright/test';
|
||||||
|
|
||||||
import {duration, wait} from '@e2e-support/util';
|
import {duration, wait} from '@e2e-support/util';
|
||||||
|
|
||||||
export default class SignupPage {
|
export default class SignupPage {
|
||||||
readonly page: Page;
|
readonly page: Page;
|
||||||
readonly title: Locator;
|
|
||||||
readonly subtitle: Locator;
|
readonly title;
|
||||||
readonly bodyCard: Locator;
|
readonly subtitle;
|
||||||
readonly emailInput: Locator;
|
readonly bodyCard;
|
||||||
readonly usernameInput: Locator;
|
readonly emailInput;
|
||||||
readonly passwordInput: Locator;
|
readonly usernameInput;
|
||||||
readonly createAccountButton: Locator;
|
readonly passwordInput;
|
||||||
readonly loginLink: Locator;
|
readonly createAccountButton;
|
||||||
readonly emailError: Locator;
|
readonly loginLink;
|
||||||
readonly usernameError: Locator;
|
readonly emailError;
|
||||||
readonly passwordError: Locator;
|
readonly usernameError;
|
||||||
|
readonly passwordError;
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
|
|||||||
@@ -13,5 +13,6 @@
|
|||||||
"@e2e-test.config": ["test.config.ts"]
|
"@e2e-test.config": ["test.config.ts"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["./**/*"]
|
"include": ["./**/*"],
|
||||||
|
"exclude": ["playwright-report"]
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user