Skip to content

Commit ac2a940

Browse files
authored
chore: Version-Agnostic Playwright Setup for Mynah UI E2E Tests (#369)
* fix: addressing issues with webkit in github ci * Fix code formatting and downgrade TypeScript to supported version - Fix Prettier formatting issues in 3 script files - Downgrade TypeScript from 5.3.3 to 5.1.6 (within supported range <5.2.0) - Resolves pre-push hook failures * Fix TypeScript lint error: remove unnecessary type assertion - Remove 'as string' type assertion from markdown test file - Resolves @typescript-eslint/no-unnecessary-type-assertion error * fix: revert webkit configuration to original format - Keep webkit configuration simple and identical to main branch format - Maintain chromium-specific launch arguments for CI compatibility - Fixes webkit test failures caused by configuration structure changes * fic: increated the timeout to 60000ms for playwright defaultConfig * fix: removing unwanted code
1 parent 00e64fe commit ac2a940

File tree

13 files changed

+390
-20
lines changed

13 files changed

+390
-20
lines changed

.github/workflows/e2e-linux.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ jobs:
5454
run: npm run docker:run
5555
env:
5656
WEBKIT_FORCE_COMPLEX_TEXT: 0
57+
WEBKIT_DISABLE_COMPOSITING_MODE: 1
58+
PLAYWRIGHT_BROWSERS_PATH: 0
5759

5860
# Extract test results from Docker container
5961
- name: Extract test results from Docker container

Dockerfile

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
# Use the official Playwright image which includes browsers
2-
FROM mcr.microsoft.com/playwright:v1.53.0
1+
# Version-agnostic Dockerfile for Mynah UI E2E Tests
2+
# Supports dynamic Playwright version detection
3+
ARG PLAYWRIGHT_VERSION=latest
4+
FROM mcr.microsoft.com/playwright:${PLAYWRIGHT_VERSION}
35

46
# Set working directory
57
WORKDIR /app
@@ -14,6 +16,9 @@ COPY ./postinstall.js /app
1416
COPY ./webpack.config.js /app
1517
COPY ./tsconfig.json /app
1618

19+
# Copy scripts directory for version-agnostic setup
20+
COPY ./scripts /app/scripts
21+
1722
# Copy required files from ui-tests
1823
COPY ./ui-tests/package.json /app/ui-tests/
1924
COPY ./ui-tests/playwright.config.ts /app/ui-tests/
@@ -28,7 +33,19 @@ COPY ./ui-tests/__snapshots__ /app/ui-tests/__snapshots__
2833
# Install dependencies and build MynahUI
2934
RUN npm install
3035
RUN npm run build
31-
RUN cd ./ui-tests && npm install && npm run prepare
36+
37+
# Setup Playwright with version-agnostic approach
38+
RUN cd ./ui-tests && node ../scripts/setup-playwright.js && npm run prepare
39+
40+
# Ensure all browsers are installed with dependencies
41+
RUN cd ./ui-tests && npx playwright install --with-deps
42+
43+
# Run health check to verify installation
44+
RUN cd ./ui-tests && node ../scripts/docker-health-check.js
45+
46+
# Set environment variables for WebKit
47+
ENV WEBKIT_FORCE_COMPLEX_TEXT=0
48+
ENV WEBKIT_DISABLE_COMPOSITING_MODE=1
3249

3350
# Default command to run the tests
34-
CMD ["sh", "-c", "cd ./ui-tests && npm run e2e${BROWSER:+:$BROWSER}"]
51+
CMD ["sh", "-c", "cd ./ui-tests && npm run e2e${BROWSER:+:$BROWSER}"]

package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,20 @@
2828
"format:check": "npx prettier --check .",
2929
"format:write": "npx prettier --write .",
3030
"docker:clean": "docker rm -f mynah-ui-e2e-container || true",
31-
"docker:build": "docker build -t mynah-ui-e2e -f Dockerfile .",
32-
"docker:run": "docker run --name mynah-ui-e2e-container mynah-ui-e2e",
31+
"docker:build": "node scripts/docker-build.js",
32+
"docker:run": "docker run --name mynah-ui-e2e-container -e WEBKIT_FORCE_COMPLEX_TEXT=0 -e WEBKIT_DISABLE_COMPOSITING_MODE=1 mynah-ui-e2e",
3333
"docker:run:chromium": "docker run -e BROWSER=chromium --name mynah-ui-e2e-container mynah-ui-e2e",
34-
"docker:run:webkit": "docker run -e BROWSER=webkit --name mynah-ui-e2e-container mynah-ui-e2e",
34+
"docker:run:webkit": "docker run -e BROWSER=webkit -e WEBKIT_FORCE_COMPLEX_TEXT=0 -e WEBKIT_DISABLE_COMPOSITING_MODE=1 --name mynah-ui-e2e-container mynah-ui-e2e",
3535
"docker:extract": "docker cp mynah-ui-e2e-container:/app/ui-tests/__results__ ./ui-tests/ && docker cp mynah-ui-e2e-container:/app/ui-tests/__snapshots__ ./ui-tests/__results__/__snapshots__",
36+
"playwright:setup": "node scripts/setup-playwright.js",
37+
"playwright:version": "node scripts/get-playwright-version.js",
38+
"playwright:pre-test": "node scripts/pre-test-setup.js",
3639
"tests:e2e": "npm run docker:clean && npm run docker:build && npm run docker:run",
3740
"tests:e2e:chromium": "npm run docker:clean && npm run docker:build && npm run docker:run:chromium",
3841
"tests:e2e:webkit": "npm run docker:clean && npm run docker:build && npm run docker:run:webkit",
42+
"tests:e2e:webkit:local": "npm run playwright:pre-test && cd ui-tests && npm run e2e:webkit",
43+
"tests:webkit:check": "node scripts/test-webkit.js",
44+
"tests:e2e:local": "npm run playwright:pre-test && cd ui-tests && npm run e2e",
3945
"tests:e2e:trace": "cd ./ui-tests && npm run trace",
4046
"tests:unit": "jest --collect-coverage",
4147
"api-docs": "npx typedoc src/main.ts --out ./api-docs",
@@ -96,7 +102,7 @@
96102
"ts-loader": "^9.4.4",
97103
"ts-node": "^10.9.1",
98104
"typedoc": "^0.25.13",
99-
"typescript": "^5.0.4",
105+
"typescript": "^5.1.6",
100106
"webpack": "5.94.0",
101107
"webpack-cli": "4.7.2"
102108
}

scripts/docker-build.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Script to build Docker image with detected Playwright version
5+
*/
6+
7+
const { execSync } = require('child_process');
8+
const { getPlaywrightVersion } = require('./get-playwright-version');
9+
10+
function buildDockerImage() {
11+
try {
12+
const version = getPlaywrightVersion();
13+
console.log(`Building Docker image with Playwright version: ${version}`);
14+
15+
// Use the detected version or fallback to latest
16+
// Add 'v' prefix for version numbers, but not for 'latest'
17+
const dockerVersion = version === 'latest' ? 'latest' : `v${version}`;
18+
19+
const buildCommand = `docker build --build-arg PLAYWRIGHT_VERSION=${dockerVersion} -t mynah-ui-e2e .`;
20+
21+
console.log(`Executing: ${buildCommand}`);
22+
execSync(buildCommand, { stdio: 'inherit' });
23+
24+
console.log('Docker image built successfully!');
25+
} catch (error) {
26+
console.error('Error building Docker image:', error.message);
27+
process.exit(1);
28+
}
29+
}
30+
31+
// If called directly, run the build
32+
if (require.main === module) {
33+
buildDockerImage();
34+
}
35+
36+
module.exports = { buildDockerImage };

scripts/docker-health-check.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Docker health check script to verify browser installations
5+
*/
6+
7+
const { execSync } = require('child_process');
8+
9+
function healthCheck() {
10+
try {
11+
console.log('=== Docker Health Check ===');
12+
13+
// Check if we're in Docker
14+
console.log('Environment: Docker Container');
15+
16+
// Check Playwright installation
17+
console.log('\n1. Checking Playwright...');
18+
execSync('npx playwright --version', { stdio: 'inherit' });
19+
20+
// Check browser installations
21+
console.log('\n2. Checking browsers...');
22+
execSync('npx playwright install --dry-run', { stdio: 'inherit' });
23+
24+
// Test WebKit specifically
25+
console.log('\n3. Testing WebKit launch...');
26+
execSync('npx playwright test --list --project=webkit | head -5', {
27+
stdio: 'inherit',
28+
shell: true,
29+
});
30+
31+
console.log('\n=== Health Check Passed ===');
32+
return true;
33+
} catch (error) {
34+
console.error('Health check failed:', error.message);
35+
return false;
36+
}
37+
}
38+
39+
// If called directly, run the health check
40+
if (require.main === module) {
41+
const success = healthCheck();
42+
process.exit(success ? 0 : 1);
43+
}
44+
45+
module.exports = { healthCheck };

scripts/get-playwright-version.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Script to detect and return the appropriate Playwright version
5+
* Priority: local installation > package.json > latest
6+
*/
7+
8+
const fs = require('fs');
9+
const path = require('path');
10+
const { execSync } = require('child_process');
11+
12+
function getPlaywrightVersion() {
13+
try {
14+
// 1. Try to get locally installed version
15+
try {
16+
const localVersion = execSync('playwright --version', { encoding: 'utf8', stdio: 'pipe' });
17+
const versionMatch = localVersion.match(/Version (\d+\.\d+\.\d+)/);
18+
if (versionMatch) {
19+
console.log(`Found local Playwright version: ${versionMatch[1]}`);
20+
return versionMatch[1];
21+
}
22+
} catch (error) {
23+
console.log('No local Playwright installation found');
24+
}
25+
26+
// 2. Try to get version from ui-tests package.json
27+
const uiTestsPackagePath = path.join(__dirname, '../ui-tests/package.json');
28+
if (fs.existsSync(uiTestsPackagePath)) {
29+
const packageJson = JSON.parse(fs.readFileSync(uiTestsPackagePath, 'utf8'));
30+
31+
// Check both playwright and @playwright/test dependencies
32+
const playwrightVersion = packageJson.devDependencies?.playwright || packageJson.dependencies?.playwright;
33+
const playwrightTestVersion =
34+
packageJson.devDependencies?.['@playwright/test'] || packageJson.dependencies?.['@playwright/test'];
35+
36+
// Prefer @playwright/test version if available, otherwise use playwright
37+
const version = playwrightTestVersion || playwrightVersion;
38+
39+
if (version) {
40+
// Remove ^ or ~ prefix and get clean version
41+
const cleanVersion = version.replace(/[\^~]/, '');
42+
const sourcePackage = playwrightTestVersion ? '@playwright/test' : 'playwright';
43+
console.log(`Found ${sourcePackage} version in ui-tests package.json: ${cleanVersion}`);
44+
return cleanVersion;
45+
}
46+
}
47+
48+
// 3. Fallback to latest
49+
console.log('No specific version found, using latest');
50+
return 'latest';
51+
} catch (error) {
52+
console.error('Error detecting Playwright version:', error.message);
53+
return 'latest';
54+
}
55+
}
56+
57+
// If called directly, output the version
58+
if (require.main === module) {
59+
console.log(getPlaywrightVersion());
60+
}
61+
62+
module.exports = { getPlaywrightVersion };

scripts/pre-test-setup.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Pre-test setup script that ensures Playwright is properly configured
5+
* This runs before tests to guarantee version consistency
6+
*/
7+
8+
const fs = require('fs');
9+
const path = require('path');
10+
const { execSync } = require('child_process');
11+
const { getPlaywrightVersion } = require('./get-playwright-version');
12+
13+
function checkPlaywrightInstallation() {
14+
const uiTestsPath = path.join(__dirname, '../ui-tests');
15+
const nodeModulesPath = path.join(uiTestsPath, 'node_modules');
16+
const playwrightPath = path.join(nodeModulesPath, '@playwright');
17+
18+
return fs.existsSync(playwrightPath);
19+
}
20+
21+
function getInstalledPlaywrightVersion() {
22+
try {
23+
const uiTestsPath = path.join(__dirname, '../ui-tests');
24+
const packageLockPath = path.join(uiTestsPath, 'package-lock.json');
25+
26+
if (fs.existsSync(packageLockPath)) {
27+
const packageLock = JSON.parse(fs.readFileSync(packageLockPath, 'utf8'));
28+
return (
29+
packageLock.packages?.['node_modules/@playwright/test']?.version ||
30+
packageLock.packages?.['node_modules/playwright']?.version ||
31+
null
32+
);
33+
}
34+
return null;
35+
} catch (error) {
36+
console.warn('Could not read package-lock.json:', error.message);
37+
return null;
38+
}
39+
}
40+
41+
function preTestSetup() {
42+
console.log('🔍 Running pre-test setup...');
43+
44+
try {
45+
const expectedVersion = getPlaywrightVersion();
46+
console.log(`📋 Expected Playwright version: ${expectedVersion}`);
47+
48+
const isInstalled = checkPlaywrightInstallation();
49+
const installedVersion = getInstalledPlaywrightVersion();
50+
51+
console.log(`📦 Playwright installed: ${isInstalled}`);
52+
console.log(`📦 Installed version: ${installedVersion || 'unknown'}`);
53+
54+
// Check if we need to install/update
55+
const needsSetup = !isInstalled || (expectedVersion !== 'latest' && installedVersion !== expectedVersion);
56+
57+
if (needsSetup) {
58+
console.log('🔧 Setting up Playwright...');
59+
60+
// Run setup with target directory
61+
const { setupPlaywright } = require('./setup-playwright');
62+
const uiTestsPath = path.join(__dirname, '../ui-tests');
63+
setupPlaywright(uiTestsPath);
64+
} else {
65+
console.log('✅ Playwright is already properly configured');
66+
}
67+
68+
console.log('🎉 Pre-test setup completed successfully!');
69+
} catch (error) {
70+
console.error('❌ Pre-test setup failed:', error.message);
71+
process.exit(1);
72+
}
73+
}
74+
75+
// If called directly, run the setup
76+
if (require.main === module) {
77+
preTestSetup();
78+
}
79+
80+
module.exports = { preTestSetup };

scripts/setup-playwright.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Script to setup Playwright with version-agnostic approach
5+
* This ensures consistent versions across local and Docker environments
6+
*/
7+
8+
const { execSync } = require('child_process');
9+
const path = require('path');
10+
const fs = require('fs');
11+
const { getPlaywrightVersion } = require('./get-playwright-version');
12+
13+
function setupPlaywright(targetDir = null) {
14+
try {
15+
const version = getPlaywrightVersion();
16+
console.log(`Setting up Playwright version: ${version}`);
17+
18+
// Determine target directory
19+
const uiTestsPath = targetDir || path.join(__dirname, '../ui-tests');
20+
21+
// Ensure target directory exists
22+
if (!fs.existsSync(uiTestsPath)) {
23+
throw new Error(`Target directory does not exist: ${uiTestsPath}`);
24+
}
25+
26+
const installCommand =
27+
version === 'latest'
28+
? 'npm install @playwright/test@latest playwright@latest --save-dev'
29+
: `npm install @playwright/test@${version} playwright@${version} --save-dev`;
30+
31+
console.log(`Installing Playwright in ${uiTestsPath}...`);
32+
execSync(installCommand, {
33+
stdio: 'inherit',
34+
cwd: uiTestsPath,
35+
});
36+
37+
// Install Playwright browsers with dependencies
38+
console.log('Installing Playwright browsers with dependencies...');
39+
execSync('npx playwright install --with-deps', {
40+
stdio: 'inherit',
41+
cwd: uiTestsPath,
42+
});
43+
44+
console.log('Playwright setup completed successfully!');
45+
return true;
46+
} catch (error) {
47+
console.error('Error setting up Playwright:', error.message);
48+
throw error; // Re-throw to allow caller to handle
49+
}
50+
}
51+
52+
// If called directly, run the setup
53+
if (require.main === module) {
54+
try {
55+
setupPlaywright();
56+
} catch (error) {
57+
process.exit(1);
58+
}
59+
}
60+
61+
module.exports = { setupPlaywright };

0 commit comments

Comments
 (0)