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>
This commit is contained in:
Saturnino Abril 2023-04-19 12:04:25 +08:00 committed by GitHub
parent 4ef3081f65
commit 6ca5824ea1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 575 additions and 514 deletions

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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"
}
}

View File

@ -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.

View File

@ -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) {

View File

@ -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> {

View File

@ -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',

View File

@ -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;
}

View File

@ -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) => {

View File

@ -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) {

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 KiB

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 285 KiB

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 355 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 KiB

After

Width:  |  Height:  |  Size: 393 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 266 KiB

View File

@ -526,7 +526,6 @@ export type EmailSettings = {
LoginButtonColor: string;
LoginButtonBorderColor: string;
LoginButtonTextColor: string;
EnableInactivityEmail: boolean;
};
export type RateLimitSettings = {