E2E/Playwright: Update dependencies, screenshots, config and type (#23000)
* update dependencies * update default server config and client type * close browser context once test is done * fix test when switching a product * update screenshots and readme * add cross-env and make headless mode as default --------- Co-authored-by: Mattermost Build <build@mattermost.com>
@ -2,8 +2,21 @@
|
||||
|
||||
#### 1. Start local server in a separate terminal.
|
||||
|
||||
```
|
||||
# Typically run the local server with:
|
||||
cd server && make run
|
||||
|
||||
# Or build and distribute webapp including channels, boards and playbooks
|
||||
# so that their product URLs do not rely on Webpack dev server.
|
||||
# Especially important when running test inside the Playwright's docker container.
|
||||
cd webapp && make dist
|
||||
cd server && make run-server
|
||||
```
|
||||
|
||||
#### 2. Install dependencies and run the test.
|
||||
|
||||
Note: If you're using Node.js version 18 and above, you may need to set `NODE_OPTIONS='--no-experimental-fetch'`.
|
||||
|
||||
```
|
||||
# Install npm packages
|
||||
npm i
|
||||
@ -32,14 +45,16 @@ npm run test
|
||||
Change to root directory, run docker container
|
||||
|
||||
```
|
||||
docker run -it --rm -v "$(pwd):/mattermost/" --ipc=host mcr.microsoft.com/playwright:v1.30.0-focal /bin/bash
|
||||
docker run -it --rm -v "$(pwd):/mattermost/" --ipc=host mcr.microsoft.com/playwright:v1.32.0-focal /bin/bash
|
||||
```
|
||||
|
||||
#### 2. Inside the docker container
|
||||
|
||||
```
|
||||
export NODE_OPTIONS='--no-experimental-fetch'
|
||||
export PW_BASE_URL=http://host.docker.internal:8065
|
||||
cd mattermost/e2e/playwright
|
||||
export PW_HEADLESS=true
|
||||
cd mattermost/e2e-tests/playwright
|
||||
|
||||
# Install npm packages. Use "npm ci" to match the automated environment
|
||||
npm ci
|
||||
|
991
e2e-tests/playwright/package-lock.json
generated
@ -1,33 +1,35 @@
|
||||
{
|
||||
"scripts": {
|
||||
"test": "PW_SNAPSHOT_ENABLE=true playwright test",
|
||||
"percy": "PERCY_TOKEN=$PERCY_TOKEN PW_PERCY_ENABLE=true percy exec -- playwright test --project=chrome --project=iphone --project=ipad",
|
||||
"test": "cross-env PW_SNAPSHOT_ENABLE=true playwright test",
|
||||
"percy": "cross-env PERCY_TOKEN=$PERCY_TOKEN PW_PERCY_ENABLE=true percy exec -- playwright test --project=chrome --project=iphone --project=ipad",
|
||||
"tsc": "tsc -b",
|
||||
"lint": "eslint . --ext .js,.ts",
|
||||
"prettier": "prettier --write .",
|
||||
"check": "npm run tsc && npm run lint && npm run prettier",
|
||||
"codegen": "playwright codegen $PW_BASE_URL",
|
||||
"test-slomo": "PW_SNAPSHOT_ENABLE=true PW_HEADLESS=false PW_SLOWMO=1000 playwright test",
|
||||
"codegen": "cross-env playwright codegen $PW_BASE_URL",
|
||||
"playwright-ui": "playwright test --ui",
|
||||
"test-slomo": "cross-env PW_SNAPSHOT_ENABLE=true PW_SLOWMO=1000 playwright test",
|
||||
"show-report": "npx playwright show-report"
|
||||
},
|
||||
"dependencies": {
|
||||
"@percy/cli": "1.18.0",
|
||||
"@percy/cli": "1.23.0",
|
||||
"@percy/playwright": "1.0.4",
|
||||
"@playwright/test": "1.32.3",
|
||||
"async-wait-until": "2.0.12",
|
||||
"chalk": "4.1.2",
|
||||
"deepmerge": "4.3.0",
|
||||
"deepmerge": "4.3.1",
|
||||
"dotenv": "16.0.3",
|
||||
"form-data": "4.0.0",
|
||||
"isomorphic-unfetch": "4.0.2",
|
||||
"uuid": "9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/uuid": "9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.51.0",
|
||||
"@typescript-eslint/parser": "5.51.0",
|
||||
"eslint": "8.34.0",
|
||||
"prettier": "2.8.4",
|
||||
"typescript": "4.9.5"
|
||||
"@types/uuid": "9.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "5.59.0",
|
||||
"@typescript-eslint/parser": "5.59.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint": "8.38.0",
|
||||
"prettier": "2.8.7",
|
||||
"typescript": "5.0.4"
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
# - Default to "false" if not set.
|
||||
|
||||
# 12. PW_HEADLESS
|
||||
# - Default to "true" if not set. Set to false to run test in head mode.
|
||||
# - Default to "false" or headless mode if not set. Set to true to run test in headed 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.
|
||||
|
@ -3,16 +3,18 @@
|
||||
|
||||
import {writeFile} from 'node:fs/promises';
|
||||
|
||||
import {request, Browser} from '@playwright/test';
|
||||
import {request, Browser, BrowserContext} from '@playwright/test';
|
||||
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
import testConfig from '@e2e-test.config';
|
||||
|
||||
export class TestBrowser {
|
||||
readonly browser: Browser;
|
||||
context: BrowserContext | null;
|
||||
|
||||
constructor(browser: Browser) {
|
||||
this.browser = browser;
|
||||
this.context = null;
|
||||
}
|
||||
|
||||
async login(user: UserProfile | null) {
|
||||
@ -27,8 +29,16 @@ export class TestBrowser {
|
||||
const context = await this.browser.newContext(options);
|
||||
const page = await context.newPage();
|
||||
|
||||
this.context = context;
|
||||
|
||||
return {context, page};
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this.context) {
|
||||
await this.context.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function loginByAPI(loginId: string, password: string, token = '', ldapOnly = false) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// This is based on "packages/client/src/client4.ts". Modified for node client.
|
||||
// This is based on "webapp/platform/client/src/client4.ts". Modified for node client.
|
||||
// Update should be made in comparison with the base Client4.
|
||||
|
||||
import fs from 'node:fs';
|
||||
@ -134,7 +134,7 @@ export default class Client extends Client4 {
|
||||
|
||||
// *****************************************************************************
|
||||
// Boards client
|
||||
// based on https://github.com/mattermost/focalboard/blob/main/webapp/src/octoClient.ts
|
||||
// based on "webapp/boards/src/octoClient.ts"
|
||||
// *****************************************************************************
|
||||
|
||||
async patchUserConfig(userID: string, patch: UserConfigPatch): Promise<UserPreference[] | undefined> {
|
||||
|
@ -319,7 +319,6 @@ const defaultServerConfig: AdminConfig = {
|
||||
LoginButtonColor: '#0000',
|
||||
LoginButtonBorderColor: '#2389D7',
|
||||
LoginButtonTextColor: '#2389D7',
|
||||
EnableInactivityEmail: true,
|
||||
},
|
||||
RateLimitSettings: {
|
||||
Enable: false,
|
||||
@ -622,12 +621,6 @@ const defaultServerConfig: AdminConfig = {
|
||||
'com.mattermost.nps': {
|
||||
Enable: true,
|
||||
},
|
||||
focalboard: {
|
||||
Enable: true,
|
||||
},
|
||||
playbooks: {
|
||||
Enable: true,
|
||||
},
|
||||
},
|
||||
EnableMarketplace: true,
|
||||
EnableRemoteMarketplace: true,
|
||||
@ -671,13 +664,12 @@ const defaultServerConfig: AdminConfig = {
|
||||
BoardsFeatureFlags: '',
|
||||
BoardsDataRetention: false,
|
||||
NormalizeLdapDNs: false,
|
||||
EnableInactivityCheckJob: true,
|
||||
UseCaseOnboarding: true,
|
||||
GraphQL: false,
|
||||
InsightsEnabled: true,
|
||||
CommandPalette: false,
|
||||
SendWelcomePost: true,
|
||||
WorkTemplate: false,
|
||||
WorkTemplate: true,
|
||||
PostPriority: true,
|
||||
WysiwygEditor: false,
|
||||
PeopleProduct: false,
|
||||
@ -686,7 +678,9 @@ const defaultServerConfig: AdminConfig = {
|
||||
ThreadsEverywhere: false,
|
||||
GlobalDrafts: true,
|
||||
OnboardingTourTips: true,
|
||||
DeprecateCloudFree: false,
|
||||
AppsSidebarCategory: false,
|
||||
CloudReverseTrial: false,
|
||||
},
|
||||
ImportSettings: {
|
||||
Directory: './import',
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
import path from 'node:path';
|
||||
import {expect} from '@playwright/test';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import {ClientError} from '@mattermost/client/client4';
|
||||
import {PreferenceType} from '@mattermost/types/preferences';
|
||||
import testConfig from '@e2e-test.config';
|
||||
|
||||
@ -77,10 +79,21 @@ export async function initSetup({
|
||||
offTopicUrl: getUrl(team.name, 'off-topic'),
|
||||
townSquareUrl: getUrl(team.name, 'town-square'),
|
||||
};
|
||||
} catch (err) {
|
||||
} catch (error) {
|
||||
// log an error for debugging
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(err);
|
||||
const err = error as ClientError;
|
||||
if (err.message === 'Could not parse multipart form.') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(chalk.yellow(`node version: ${process.version}\nNODE_OPTIONS: ${process.env.NODE_OPTIONS}`));
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
chalk.green(
|
||||
`This failed due to the experimental fetch support in Node.js starting v18.0.0.\nYou may set environment variable: "export NODE_OPTIONS='--no-experimental-fetch'", then try again.'`
|
||||
)
|
||||
);
|
||||
}
|
||||
expect(err, 'Should not throw an error').toBeFalsy();
|
||||
throw err;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ export const test = base.extend<ExtendedFixtures>({
|
||||
pw: async ({browser}, use) => {
|
||||
const pw = new PlaywrightExtended(browser);
|
||||
await use(pw);
|
||||
await pw.testBrowser.close();
|
||||
},
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
pages: async ({}, use) => {
|
||||
|
@ -16,7 +16,7 @@ export default class GlobalHeader {
|
||||
|
||||
async switchProduct(name: string) {
|
||||
await this.productSwitchMenu.click();
|
||||
await this.container.getByRole('link', {name: ` ${name}`}).click();
|
||||
await this.container.getByRole('link', {name}).click();
|
||||
}
|
||||
|
||||
async toBeVisible(name: string) {
|
||||
|
@ -55,7 +55,7 @@ const config: TestConfig = {
|
||||
// CI
|
||||
isCI: !!process.env.CI,
|
||||
// Playwright
|
||||
headless: parseBool(process.env.PW_HEADLESS, false),
|
||||
headless: parseBool(process.env.PW_HEADLESS, true),
|
||||
slowMo: parseNumber(process.env.PW_SLOWMO, 0),
|
||||
workers: parseNumber(process.env.PW_WORKERS, 1),
|
||||
// Visual tests
|
||||
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 182 KiB |
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 238 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 167 KiB |
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 170 KiB |
Before Width: | Height: | Size: 212 KiB After Width: | Height: | Size: 213 KiB |
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 270 KiB After Width: | Height: | Size: 271 KiB |
Before Width: | Height: | Size: 312 KiB After Width: | Height: | Size: 312 KiB |
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 241 KiB |
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 277 KiB |
Before Width: | Height: | Size: 297 KiB After Width: | Height: | Size: 297 KiB |
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 230 KiB |
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 165 KiB |
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 170 KiB |
Before Width: | Height: | Size: 285 KiB After Width: | Height: | Size: 296 KiB |
Before Width: | Height: | Size: 368 KiB After Width: | Height: | Size: 411 KiB |
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 355 KiB |
Before Width: | Height: | Size: 280 KiB After Width: | Height: | Size: 291 KiB |
Before Width: | Height: | Size: 348 KiB After Width: | Height: | Size: 393 KiB |
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 266 KiB |
@ -526,7 +526,6 @@ export type EmailSettings = {
|
||||
LoginButtonColor: string;
|
||||
LoginButtonBorderColor: string;
|
||||
LoginButtonTextColor: string;
|
||||
EnableInactivityEmail: boolean;
|
||||
};
|
||||
|
||||
export type RateLimitSettings = {
|
||||
|