E2E/Playwright: Upgrade playwright/dependencies and test server config (#26464)

* chore: upgrade playwright and test server config

* add post install script

* update config types

* fix visual test
This commit is contained in:
Saturnino Abril 2024-03-19 08:09:25 +08:00 committed by GitHub
parent 297135c5b4
commit 53471c7e8c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 705 additions and 502 deletions

View File

@ -222,7 +222,7 @@ $(if mme2e_is_token_in_list "webhook-interactions" "$ENABLED_DOCKER_SERVICES"; t
$(if mme2e_is_token_in_list "playwright" "$ENABLED_DOCKER_SERVICES"; then $(if mme2e_is_token_in_list "playwright" "$ENABLED_DOCKER_SERVICES"; then
echo ' echo '
playwright: playwright:
image: mcr.microsoft.com/playwright:v1.38.1-jammy image: mcr.microsoft.com/playwright:v1.42.1-jammy
entrypoint: ["/bin/bash", "-c"] entrypoint: ["/bin/bash", "-c"]
command: ["until [ -f /var/run/mm_terminate ]; do sleep 5; done"] command: ["until [ -f /var/run/mm_terminate ]; do sleep 5; done"]
env_file: env_file:

View File

@ -14,7 +14,20 @@ EOF
# Install Playwright dependencies # Install Playwright dependencies
mme2e_log "Prepare Playwright: install dependencies" mme2e_log "Prepare Playwright: install dependencies"
${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- playwright bash -c "cd e2e-tests/playwright && rm -rf node_modules && npm install --cache /tmp/empty-cache" ${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- playwright bash -c "cd e2e-tests/playwright && rm -rf node_modules && PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install --cache /tmp/empty-cache"
mme2e_log "Prepare Playwright: environment info"
${MME2E_DC_SERVER} exec -T -u "$MME2E_UID" -- playwright bash <<"EOF"
cat <<INNEREOF
debian = $(cat /etc/debian_version)
uname = $(uname -m)
node = $(node -v)
npm = $(npm -v)
playwright = $(cd e2e-tests/playwright && npx playwright --version)
browsers
$(du -hs ~/ms-playwright/* | awk '{print " = " $2 " (" $1 ")"}')
INNEREOF
EOF
# Enable next line to debug Playwright # Enable next line to debug Playwright
# export DEBUG=pw:protocol,pw:browser,pw:api # export DEBUG=pw:protocol,pw:browser,pw:api

View File

@ -45,7 +45,7 @@ npm run test
Change to root directory, run docker container Change to root directory, run docker container
``` ```
docker run -it --rm -v "$(pwd):/mattermost/" --ipc=host mcr.microsoft.com/playwright:v1.41.1-jammy /bin/bash docker run -it --rm -v "$(pwd):/mattermost/" --ipc=host mcr.microsoft.com/playwright:v1.42.1-jammy /bin/bash
``` ```
#### 2. Inside the docker container #### 2. Inside the docker container
@ -57,7 +57,7 @@ export PW_HEADLESS=true
cd mattermost/e2e-tests/playwright cd mattermost/e2e-tests/playwright
# Install npm packages. Use "npm ci" to match the automated environment # Install npm packages. Use "npm ci" to match the automated environment
npm ci PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm ci
# Run specific test. See https://playwright.dev/docs/test-cli. # Run specific test. See https://playwright.dev/docs/test-cli.
npm run test -- login --project=chrome npm run test -- login --project=chrome

View File

@ -13,10 +13,11 @@ import testConfig from './test.config';
async function globalSetup() { async function globalSetup() {
let adminClient: Client; let adminClient: Client;
let adminUser: UserProfile | null; let adminUser: UserProfile | null;
({adminClient, adminUser} = await getAdminClient()); ({adminClient, adminUser} = await getAdminClient({skipLog: true}));
if (!adminUser) { if (!adminUser) {
const {client: firstClient} = await makeClient(); const firstClient = new Client();
firstClient.setUrl(testConfig.baseURL);
const defaultAdmin = getDefaultAdminUser(); const defaultAdmin = getDefaultAdminUser();
await firstClient.createUser(defaultAdmin, '', ''); await firstClient.createUser(defaultAdmin, '', '');
@ -100,8 +101,6 @@ async function printClientInfo(client: Client) {
- BuildHash = ${config.BuildHash} - BuildHash = ${config.BuildHash}
- BuildHashEnterprise = ${config.BuildHashEnterprise} - BuildHashEnterprise = ${config.BuildHashEnterprise}
- BuildEnterpriseReady = ${config.BuildEnterpriseReady} - BuildEnterpriseReady = ${config.BuildEnterpriseReady}
- FeatureFlagAppsEnabled = ${config.FeatureFlagAppsEnabled}
- FeatureFlagCallsEnabled = ${config.FeatureFlagCallsEnabled}
- TelemetryId = ${config.TelemetryId} - TelemetryId = ${config.TelemetryId}
- ServiceEnvironment = ${config.ServiceEnvironment}`); - ServiceEnvironment = ${config.ServiceEnvironment}`);
} }

File diff suppressed because it is too large Load Diff

View File

@ -12,29 +12,29 @@
"playwright-ui": "cross-env NODE_OPTIONS='--no-experimental-fetch' playwright test --ui", "playwright-ui": "cross-env NODE_OPTIONS='--no-experimental-fetch' playwright test --ui",
"test-slomo": "cross-env NODE_OPTIONS='--no-experimental-fetch' PW_SNAPSHOT_ENABLE=true PW_SLOWMO=1000 playwright test", "test-slomo": "cross-env NODE_OPTIONS='--no-experimental-fetch' PW_SNAPSHOT_ENABLE=true PW_SLOWMO=1000 playwright test",
"show-report": "npx playwright show-report", "show-report": "npx playwright show-report",
"postinstall": "npx playwright install" "postinstall": "script/post_install.sh"
}, },
"dependencies": { "dependencies": {
"@axe-core/playwright": "4.8.3", "@axe-core/playwright": "4.8.5",
"@percy/cli": "1.27.7", "@percy/cli": "1.28.1",
"@percy/playwright": "1.0.4", "@percy/playwright": "1.0.4",
"@playwright/test": "1.41.1", "@playwright/test": "1.42.1",
"async-wait-until": "2.0.12", "async-wait-until": "2.0.12",
"axe-core": "4.8.3", "axe-core": "4.8.4",
"chalk": "4.1.2", "chalk": "4.1.2",
"deepmerge": "4.3.1", "deepmerge": "4.3.1",
"dotenv": "16.3.2", "dotenv": "16.4.5",
"form-data": "4.0.0", "form-data": "4.0.0",
"isomorphic-unfetch": "4.0.2", "isomorphic-unfetch": "4.0.2",
"uuid": "9.0.1" "uuid": "9.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/uuid": "9.0.7", "@types/uuid": "9.0.8",
"@typescript-eslint/eslint-plugin": "6.19.1", "@typescript-eslint/eslint-plugin": "7.2.0",
"@typescript-eslint/parser": "6.19.1", "@typescript-eslint/parser": "7.2.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"eslint": "8.56.0", "eslint": "8.57.0",
"prettier": "3.2.4", "prettier": "3.2.5",
"typescript": "5.3.3" "typescript": "5.4.2"
} }
} }

View File

@ -0,0 +1,12 @@
#!/bin/bash
if [ -n "$PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD" ]; then
echo "Skipped browsers download for Playwright"
exit 0
fi
# Install needed Playwright browsers only -- chromium and firefox only for these are the ones being used by the tests.
# May add more browsers in the future.
# https://playwright.dev/docs/library#browser-downloads
npx playwright install chromium
npx playwright install firefox

View File

@ -136,7 +136,10 @@ export default class Client extends Client4 {
// Variable to hold cache // Variable to hold cache
const clients: Record<string, ClientCache> = {}; const clients: Record<string, ClientCache> = {};
async function makeClient(userRequest?: UserRequest, useCache = true): Promise<ClientCache> { async function makeClient(
userRequest?: UserRequest,
opts: {useCache?: boolean; skipLog?: boolean} = {useCache: true, skipLog: false},
): Promise<ClientCache> {
const client = new Client(); const client = new Client();
client.setUrl(testConfig.baseURL); client.setUrl(testConfig.baseURL);
@ -146,22 +149,24 @@ async function makeClient(userRequest?: UserRequest, useCache = true): Promise<C
} }
const cacheKey = userRequest.username + userRequest.password; const cacheKey = userRequest.username + userRequest.password;
if (useCache && clients[cacheKey] != null) { if (opts?.useCache && clients[cacheKey] != null) {
return clients[cacheKey]; return clients[cacheKey];
} }
const userProfile = await client.login(userRequest.username, userRequest.password); const userProfile = await client.login(userRequest.username, userRequest.password);
const user = {...userProfile, password: userRequest.password}; const user = {...userProfile, password: userRequest.password};
if (useCache) { if (opts?.useCache) {
clients[cacheKey] = {client, user}; clients[cacheKey] = {client, user};
} }
return {client, user}; return {client, user};
} catch (err) { } catch (err) {
// log an error for debugging if (!opts?.skipLog) {
// eslint-disable-next-line no-console // log an error for debugging
console.log('makeClient', err); // eslint-disable-next-line no-console
console.log('makeClient', err);
}
return {client, user: null}; return {client, user: null};
} }
} }

View File

@ -75,7 +75,7 @@ const onPremServerConfig = (): Partial<TestAdminConfig> => {
}; };
// Should be based only from the generated default config from ./server via "make config-reset" // Should be based only from the generated default config from ./server via "make config-reset"
// Based on v9.5 server // Based on v9.7 server
const defaultServerConfig: AdminConfig = { const defaultServerConfig: AdminConfig = {
ServiceSettings: { ServiceSettings: {
SiteURL: '', SiteURL: '',
@ -101,6 +101,7 @@ const defaultServerConfig: AdminConfig = {
EnableOAuthServiceProvider: true, EnableOAuthServiceProvider: true,
EnableIncomingWebhooks: true, EnableIncomingWebhooks: true,
EnableOutgoingWebhooks: true, EnableOutgoingWebhooks: true,
EnableOutgoingOAuthConnections: false,
EnableCommands: true, EnableCommands: true,
OutgoingIntegrationRequestsTimeout: 30, OutgoingIntegrationRequestsTimeout: 30,
EnablePostUsernameOverride: false, EnablePostUsernameOverride: false,
@ -700,6 +701,7 @@ const defaultServerConfig: AdminConfig = {
CWSURL: 'https://customers.mattermost.com', CWSURL: 'https://customers.mattermost.com',
CWSAPIURL: 'https://portal.internal.prod.cloud.mattermost.com', CWSAPIURL: 'https://portal.internal.prod.cloud.mattermost.com',
CWSMock: false, CWSMock: false,
Disable: false,
}, },
FeatureFlags: { FeatureFlags: {
TestFeature: 'off', TestFeature: 'off',
@ -720,7 +722,8 @@ const defaultServerConfig: AdminConfig = {
CloudIPFiltering: false, CloudIPFiltering: false,
ConsumePostHook: false, ConsumePostHook: false,
CloudAnnualRenewals: false, CloudAnnualRenewals: false,
OutgoingOAuthConnections: false, CloudDedicatedExportUI: false,
WebSocketEventScope: false,
}, },
ImportSettings: { ImportSettings: {
Directory: './import', Directory: './import',

View File

@ -92,11 +92,14 @@ export async function initSetup({
} }
} }
export async function getAdminClient() { export async function getAdminClient(opts: {skipLog: boolean} = {skipLog: false}) {
const {client: adminClient, user: adminUser} = await makeClient({ const {client: adminClient, user: adminUser} = await makeClient(
username: testConfig.adminUsername, {
password: testConfig.adminPassword, username: testConfig.adminUsername,
}); password: testConfig.adminPassword,
},
opts,
);
return {adminClient, adminUser}; return {adminClient, adminUser};
} }

View File

@ -6,7 +6,7 @@ import os from 'node:os';
import chalk from 'chalk'; import chalk from 'chalk';
import {expect, TestInfo} from '@playwright/test'; import {expect, TestInfo} from '@playwright/test';
import {illegalRe} from '@e2e-support/util'; import {duration, illegalRe, wait} from '@e2e-support/util';
import testConfig from '@e2e-test.config'; import testConfig from '@e2e-test.config';
import {ScreenshotOptions, TestArgs} from '@e2e-types'; import {ScreenshotOptions, TestArgs} from '@e2e-types';
@ -23,6 +23,12 @@ export async function matchSnapshot(testInfo: TestInfo, testArgs: TestArgs, opti
return; return;
} }
if (testConfig.snapshotEnabled || testConfig.percyEnabled) {
await testArgs.page.waitForLoadState('networkidle');
await testArgs.page.waitForLoadState('domcontentloaded');
await wait(duration.half_sec);
}
if (testConfig.snapshotEnabled) { if (testConfig.snapshotEnabled) {
// Visual test with built-in snapshot // Visual test with built-in snapshot
const filename = testInfo.title.replace(illegalRe, '').replace(/\s/g, '-').trim().toLowerCase(); const filename = testInfo.title.replace(illegalRe, '').replace(/\s/g, '-').trim().toLowerCase();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -11,9 +11,9 @@
"@mattermost/types/*": ["../../webapp/platform/types/lib/*"], "@mattermost/types/*": ["../../webapp/platform/types/lib/*"],
"@e2e-support/*": ["support/*"], "@e2e-support/*": ["support/*"],
"@e2e-test.config": ["test.config.ts"], "@e2e-test.config": ["test.config.ts"],
"@e2e-types": ["types.ts"], "@e2e-types": ["types.ts"]
}, }
}, },
"include": ["./**/*"], "include": ["./**/*"],
"exclude": ["playwright-report"], "exclude": ["playwright-report"]
} }

View File

@ -303,6 +303,7 @@ export type ServiceSettings = {
EnableOAuthServiceProvider: boolean; EnableOAuthServiceProvider: boolean;
EnableIncomingWebhooks: boolean; EnableIncomingWebhooks: boolean;
EnableOutgoingWebhooks: boolean; EnableOutgoingWebhooks: boolean;
EnableOutgoingOAuthConnections: boolean;
EnableCommands: boolean; EnableCommands: boolean;
OutgoingIntegrationRequestsTimeout: number; OutgoingIntegrationRequestsTimeout: number;
EnablePostUsernameOverride: boolean; EnablePostUsernameOverride: boolean;
@ -911,6 +912,7 @@ export type CloudSettings = {
CWSURL: string; CWSURL: string;
CWSAPIURL: string; CWSAPIURL: string;
CWSMock: boolean; CWSMock: boolean;
Disable: boolean;
}; };
export type FeatureFlags = Record<string, string | boolean>; export type FeatureFlags = Record<string, string | boolean>;