diff --git a/.eslintrc.json b/.eslintrc.json index e8e60f90b9f..13b6ec21d8a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -15,7 +15,7 @@ } ], "parserOptions": { - "project": ["./tsconfig.json", "./tsconfig.mocha.json", "./tsconfig.bin.json"] + "project": ["./tsconfig.json", "./tsconfig.mocha.json", "./tsconfig.bin.json", "./tsconfig.playwright.json"] }, "plugins": ["jasmine"], "rules": { diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7704bd0842e..e69de29bb2d 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,29 +0,0 @@ -# Pull Request - -## Summary - -- What did I change and why? -- Risks and how to roll out / roll back (e.g. feature flags): - ---- - -## Security Checklist (required) - -- [ ] **External inputs are validated & sanitized** on client and/or server where applicable. -- [ ] **API responses are validated**; unexpected shapes are handled safely (fallbacks or errors). -- [ ] **No unsafe HTML is rendered**; if unavoidable, sanitization is applied **and** documented where it happens. -- [ ] **Injection risks (XSS/SQL/command) are prevented** via safe APIs and/or escaping. - -## Standards Acknowledgement (required) - -- [ ] I have read and this PR **upholds** our [Coding Standards](https://github.com/wireapp/wire-desktop/tree/docs/coding-standards.md) and [Tech Radar Choices](https://github.com/wireapp/wire-desktop/tree/docs/tech-radar.md). - ---- - -## Screenshots or demo (if the user interface changed) - -## Notes for reviewers - -- Trade-offs: -- Follow-ups (linked issues): -- Linked PRs (e.g. web-packages): diff --git a/.gitignore b/.gitignore index 23e00851a9d..889e165eeab 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .vscode *.log *.pkg +.env coverage .nyc_output /config @@ -33,3 +34,11 @@ resources !.yarn/releases !.yarn/sdks !.yarn/versions + +# Playwright +!e2e-tests/.env.tpl +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +/playwright/.auth/ diff --git a/e2e-tests/.env.tpl b/e2e-tests/.env.tpl new file mode 100644 index 00000000000..1d5e6e16b55 --- /dev/null +++ b/e2e-tests/.env.tpl @@ -0,0 +1,2 @@ +WEBAPP_URL=op://Test Automation/BackendConnection staging/webappUrl +BACKEND_URL=op://Test Automation/BackendConnection staging/backendUrl \ No newline at end of file diff --git a/e2e-tests/README.md b/e2e-tests/README.md new file mode 100644 index 00000000000..8ec517dd2ec --- /dev/null +++ b/e2e-tests/README.md @@ -0,0 +1,21 @@ +# Wire Desktop E2E Tests + +This readme serves as documentation for the E2E tests which are part of this repository. All necessary setup instructions as well as architecture decisions will be documented in here. + +## Getting started + +Make sure you already followed the instructions of the [README.md](../README.md) in the root of this repository e.g. for installing dependencies. + +### Setting up environment variables + +The E2E tests depend on configs / secrets which need to be provided as environment variables in order to run them. These secrets are stored within 1Password. To create a `.env` file containing the actual values follow these steps: + +1. Make sure you have the [1Password CLI](https://www.1password.dev/cli/get-started) installed and set up with the 1PW desktop app +2. Run `op inject -i e2e-tests/.env.tpl -o e2e-tests/.env` to create the .env file within the `e2e-tests` folder +3. Re-run the command in case the `.env.tpl` file was updated or the secrets changed + +### Running the E2E tests + +Before attempting to execute the E2E tests make sure to run the script `yarn run prestart` once. It will generate the outputs needed for launching the application within the tests. + +To then execute the e2e tests run `yarn run test:e2e` which will execute all of them. To only run specific tests you can pass the file containing them e.g. `yarn run test:e2e e2e-tests/specs/example.spec.ts`. diff --git a/e2e-tests/fixtures.ts b/e2e-tests/fixtures.ts new file mode 100644 index 00000000000..13fcbac924e --- /dev/null +++ b/e2e-tests/fixtures.ts @@ -0,0 +1,52 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {test as baseTest} from '@playwright/test'; + +import fs from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; + +import {createApp, type App} from './utils/createApp'; + +type FixtureOptions = {appOptions: {env?: string; lang?: string}}; + +type Fixtures = {app: App}; + +export const test = baseTest.extend({ + appOptions: {env: process.env.WEBAPP_URL, lang: 'en'}, + + app: async ({appOptions}, use) => { + // Always use a fresh temporary directory for the user data to ensure test isolation + const tempUserDataDir = await fs.mkdtemp(path.join(os.tmpdir(), 'wire-desktop-e2e-tests-')); + const app = await createApp({...appOptions, dataDir: tempUserDataDir}); + + await use(app); + + await app.close(); + await fs.rm(tempUserDataDir, {recursive: true}); + }, + + // Overwrite of the default page fixture to reference the apps page instead + page: async ({app}, use) => { + await use(app.page); + }, +}); + +export * from '@playwright/test'; diff --git a/electron/src/settings/SettingsUtil.ts b/e2e-tests/specs/example.spec.ts similarity index 62% rename from electron/src/settings/SettingsUtil.ts rename to e2e-tests/specs/example.spec.ts index ab3adebfa1a..704ab9d7230 100644 --- a/electron/src/settings/SettingsUtil.ts +++ b/e2e-tests/specs/example.spec.ts @@ -17,14 +17,8 @@ * */ -import {settings} from './ConfigurationPersistence'; -import {SettingsType} from './SettingsType'; +import {test, expect} from '../fixtures'; -export const setHardwareAccelerationEnabled = (enabled: boolean): void => { - settings.save(SettingsType.HARDWARE_ACCELERATION_ENABLED, enabled); - settings.persistToFile(); -}; - -export const isHardwareAccelerationEnabled = (): boolean => { - return settings.restore(SettingsType.HARDWARE_ACCELERATION_ENABLED, true); -}; +test('starts the app', async ({page}) => { + await expect(page.getByText('Welcome to Wire!')).toBeVisible(); +}); diff --git a/e2e-tests/utils/createApp.ts b/e2e-tests/utils/createApp.ts new file mode 100644 index 00000000000..057c89275a3 --- /dev/null +++ b/e2e-tests/utils/createApp.ts @@ -0,0 +1,46 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {_electron as electron, ElectronApplication, Page} from '@playwright/test'; + +export type App = ElectronApplication & { + /* The playwright page for the main electron window wrapping the webapp */ + wrapper: Page; + /* The playwright page for the currently shown webapp */ + page: Page; +}; + +export const createApp = async (options: {env?: string; lang?: string; dataDir: string}): Promise => { + if (!options.env) { + throw new Error(`Can't create app without environment, make sure the env var "WEBAPP_URL" is set`); + } + + const app = await electron.launch({ + args: ['.', `--env=${options.env}`, `--lang=${options.lang ?? 'en'}`, `--user-data-dir=${options.dataDir}`], + }); + + /** + * The webview element isn't treated as a regular webcomponent / iframe by electron but as individual window. + * So in order to access the contents of the application we need to use the second window. + */ + const wrapper = await app.waitForEvent('window'); + const page = await app.waitForEvent('window'); + + return Object.assign(app, {wrapper, page}); +}; diff --git a/electron/src/lib/eventType.ts b/electron/src/lib/eventType.ts index cf5edebb1ca..bb5300bd1e7 100644 --- a/electron/src/lib/eventType.ts +++ b/electron/src/lib/eventType.ts @@ -87,6 +87,7 @@ export const EVENT_TYPE = { }, UI: { BADGE_COUNT: 'EVENT_TYPE.UI.BADGE_COUNT', + REQUEST_WEBAPP_VERSION: 'EVENT_TYPE.UI.REQUEST_WEBAPP_VERSION', SYSTEM_MENU: 'EVENT_TYPE.UI.SYSTEM_MENU', THEME_UPDATE: 'EVENT_TYPE.UI.THEME_UPDATE', WEBAPP_VERSION: 'EVENT_TYPE.UI.WEBAPP_VERSION', diff --git a/electron/src/main.ts b/electron/src/main.ts index a8634e8bcd0..46ee434e7e7 100644 --- a/electron/src/main.ts +++ b/electron/src/main.ts @@ -68,7 +68,6 @@ import {OriginValidator} from './runtime/OriginValidator'; import {config} from './settings/config'; import {settings} from './settings/ConfigurationPersistence'; import {SettingsType} from './settings/SettingsType'; -import * as SettingsUtil from './settings/SettingsUtil'; import {SingleSignOn} from './sso/SingleSignOn'; import {initMacAutoUpdater} from './update/macosAutoUpdater'; import {AboutWindow} from './window/AboutWindow'; @@ -78,10 +77,6 @@ import * as WindowUtil from './window/WindowUtil'; const logger = getLogger(path.basename(__filename)); -// Set first main settings like hardware acceleration for video rendering -// This needs to be done before the app is ready, otherwise it will be overwritten by the main process -handleHardwareAcceleration(); - remoteMain.initialize(); const APP_PATH = path.join(app.getAppPath(), config.electronDirectory); @@ -784,13 +779,3 @@ if (lifecycle.isFirstInstance) { fs.ensureFileSync(LOG_FILE); new ElectronWrapperInit().run().catch(error => logger.error(error)); } - -function handleHardwareAcceleration(): void { - const isEnabledHw = SettingsUtil.isHardwareAccelerationEnabled(); - if (isEnabledHw) { - logger.info('Hardware acceleration is enabled.'); - } else { - app.disableHardwareAcceleration(); - logger.info('Hardware acceleration is disabled.'); - } -} diff --git a/electron/src/preload/preload-app.ts b/electron/src/preload/preload-app.ts index 9cc9f489837..db8f354bfb7 100644 --- a/electron/src/preload/preload-app.ts +++ b/electron/src/preload/preload-app.ts @@ -64,6 +64,13 @@ const subscribeToMainProcessEvents = (): void => { } }); + ipcRenderer.on(EVENT_TYPE.UI.REQUEST_WEBAPP_VERSION, async () => { + const selectedWebview = getSelectedWebview(); + if (selectedWebview) { + await selectedWebview.send(EVENT_TYPE.UI.REQUEST_WEBAPP_VERSION); + } + }); + ipcRenderer.on(WebAppEvents.LIFECYCLE.SSO_WINDOW_CLOSED, async () => { const selectedWebview = getSelectedWebview(); if (selectedWebview) { diff --git a/electron/src/preload/preload-webview.ts b/electron/src/preload/preload-webview.ts index a967e50c74e..a73d19c2457 100644 --- a/electron/src/preload/preload-webview.ts +++ b/electron/src/preload/preload-webview.ts @@ -28,7 +28,6 @@ import {WebAppEvents} from '@wireapp/webapp-events'; import {EVENT_TYPE} from '../lib/eventType'; import {getLogger} from '../logging/getLogger'; import * as EnvironmentUtil from '../runtime/EnvironmentUtil'; -import * as SettingsUtil from '../settings/SettingsUtil'; const remote = require('@electron/remote'); @@ -212,6 +211,11 @@ const subscribeToMainProcessEvents = (): void => { logger.info(`Received event "${EVENT_TYPE.PREFERENCES.SHOW}", forwarding to amplify ...`); window.amplify.publish(WebAppEvents.PREFERENCES.MANAGE_ACCOUNT); }); + ipcRenderer.on(EVENT_TYPE.UI.REQUEST_WEBAPP_VERSION, () => { + logger.info(`Received event "${EVENT_TYPE.UI.REQUEST_WEBAPP_VERSION}", reporting versions ...`); + reportWebappVersion(); + reportWebappAVSVersion(); + }); ipcRenderer.on(EVENT_TYPE.ACTION.SIGN_OUT, () => { logger.info(`Received event "${EVENT_TYPE.ACTION.SIGN_OUT}", forwarding to amplify ...`); window.amplify.publish(WebAppEvents.LIFECYCLE.ASK_TO_CLEAR_DATA); @@ -278,7 +282,6 @@ process.once('loaded', () => { }; global.environment = EnvironmentUtil; global.desktopAppConfig = {version: EnvironmentUtil.app.DESKTOP_VERSION, supportsCallingPopoutWindow: true}; - global.desktopAppSettings = SettingsUtil; global.openGraphAsync = getOpenGraphDataViaChannel; global.setImmediate = _setImmediate; }); diff --git a/electron/src/settings/SettingsType.ts b/electron/src/settings/SettingsType.ts index d5ea6ece3c5..9d6636ce00a 100644 --- a/electron/src/settings/SettingsType.ts +++ b/electron/src/settings/SettingsType.ts @@ -58,6 +58,4 @@ export enum SettingsType { SHOW_MENU_BAR = 'showMenu', /** At which part of the screen shall the app be initially rendered? */ WINDOW_BOUNDS = 'bounds', - /** Enable disabling of hardware GPU support during video rendering */ - HARDWARE_ACCELERATION_ENABLED = 'hardwareAccelerationEnabled', } diff --git a/electron/src/types/globals.d.ts b/electron/src/types/globals.d.ts index ddf0f606de9..a554976b502 100644 --- a/electron/src/types/globals.d.ts +++ b/electron/src/types/globals.d.ts @@ -24,7 +24,6 @@ import type {WebAppEvents} from '@wireapp/webapp-events'; import type {i18nStrings, SupportedI18nLanguage} from '../locale'; import type * as EnvironmentUtil from '../runtime/EnvironmentUtil'; -import type * as SettingsUtil from '../settings/SettingsUtil'; export declare global { /* eslint-disable no-var */ @@ -43,7 +42,6 @@ export declare global { version: number; }; var environment: typeof EnvironmentUtil; - var desktopAppSettings: typeof SettingsUtil; var openGraphAsync: (url: string) => Promise; var desktopAppConfig: { version: string; diff --git a/electron/src/window/AboutWindow.ts b/electron/src/window/AboutWindow.ts index b2a0ad95de1..87b5ae3686a 100644 --- a/electron/src/window/AboutWindow.ts +++ b/electron/src/window/AboutWindow.ts @@ -26,11 +26,15 @@ import {EVENT_TYPE} from '../lib/eventType'; import * as locale from '../locale'; import * as EnvironmentUtil from '../runtime/EnvironmentUtil'; import {config} from '../settings/config'; +import {WindowManager} from '../window/WindowManager'; import * as WindowUtil from '../window/WindowUtil'; -let webappVersion: string; +let webappVersion = ''; let webappAVSVersion: string | undefined; +const VERSION_REQUEST_TIMEOUT_MS = 1500; +const AVS_VERSION_GRACE_PERIOD_MS = 50; + // Paths const APP_PATH = path.join(app.getAppPath(), config.electronDirectory); const iconFileName = `logo.${EnvironmentUtil.platform.IS_WINDOWS ? 'ico' : 'png'}`; @@ -50,16 +54,67 @@ const WINDOW_SIZE = { WIDTH: 304, }; -ipcMain.once(EVENT_TYPE.UI.WEBAPP_VERSION, (_event, version: string) => { +ipcMain.on(EVENT_TYPE.UI.WEBAPP_VERSION, (_event, version: string) => { webappVersion = version; }); -ipcMain.once(EVENT_TYPE.UI.WEBAPP_AVS_VERSION, (_event, version: string) => { +ipcMain.on(EVENT_TYPE.UI.WEBAPP_AVS_VERSION, (_event, version: string) => { webappAVSVersion = version; }); +const requestActiveWebappVersions = async (): Promise<{webappVersion: string; webappAVSVersion?: string}> => { + const primaryWindow = WindowManager.getPrimaryWindow(); + + if (!primaryWindow) { + return {webappVersion, webappAVSVersion}; + } + + return new Promise(resolve => { + let requestedVersion = webappVersion; + let requestedAVSVersion = webappAVSVersion; + let hasResolved = false; + let gracePeriodId: ReturnType | undefined; + + const resolveWithValues = () => { + if (hasResolved) { + return; + } + hasResolved = true; + if (timeoutId) { + clearTimeout(timeoutId); + } + if (gracePeriodId) { + clearTimeout(gracePeriodId); + } + ipcMain.removeListener(EVENT_TYPE.UI.WEBAPP_VERSION, onVersion); + ipcMain.removeListener(EVENT_TYPE.UI.WEBAPP_AVS_VERSION, onAVSVersion); + resolve({webappVersion: requestedVersion, webappAVSVersion: requestedAVSVersion}); + }; + + const onVersion = (_event: Electron.IpcMainEvent, version: string) => { + requestedVersion = version; + if (gracePeriodId) { + clearTimeout(gracePeriodId); + } + // Wait briefly for optional AVS version that can arrive right after main version. + gracePeriodId = setTimeout(resolveWithValues, AVS_VERSION_GRACE_PERIOD_MS); + }; + + const onAVSVersion = (_event: Electron.IpcMainEvent, version: string) => { + requestedAVSVersion = version; + resolveWithValues(); + }; + + ipcMain.on(EVENT_TYPE.UI.WEBAPP_VERSION, onVersion); + ipcMain.on(EVENT_TYPE.UI.WEBAPP_AVS_VERSION, onAVSVersion); + const timeoutId = setTimeout(resolveWithValues, VERSION_REQUEST_TIMEOUT_MS); + primaryWindow.webContents.send(EVENT_TYPE.UI.REQUEST_WEBAPP_VERSION); + }); +}; + const showWindow = async () => { let aboutWindow: BrowserWindow | undefined; + const activeWebappVersions = await requestActiveWebappVersions(); if (!aboutWindow) { aboutWindow = new BrowserWindow({ @@ -136,8 +191,8 @@ const showWindow = async () => { copyright: config.copyright, electronVersion: config.version, productName: config.name, - webappVersion, - webappAVSVersion, + webappVersion: activeWebappVersions.webappVersion, + webappAVSVersion: activeWebappVersions.webappAVSVersion, }); } } diff --git a/jenkins/deployment.groovy b/jenkins/deployment.groovy index c32e2266046..9cc9a0ac257 100644 --- a/jenkins/deployment.groovy +++ b/jenkins/deployment.groovy @@ -314,7 +314,19 @@ node('built-in') { def presignedFile - // Make sure we use Jenkins AWS plugin + local "aws" command + sh ''' + if ! command -v aws >/dev/null 2>&1; then + echo "Installing AWS CLI locally..." + mkdir -p $HOME/bin + rm -rf aws awscliv2.zip + curl -sSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o awscliv2.zip + unzip -oq awscliv2.zip + ./aws/install --bin-dir $HOME/bin --install-dir $HOME/aws-cli --update + export PATH=$HOME/bin:$PATH + fi + aws --version + ''' + withAWS(region: 'eu-west-1', credentials: 'wire-taco') { if (params.Release == 'Custom') { // Custom (on-prem) @@ -324,7 +336,7 @@ node('built-in') { artifacts.each { fileObj -> def presignedUrl = sh( script: """ - aws s3 presign s3://${env.S3_BUCKET}/${env.S3_PATH}/${fileObj.name} --expires-in 604800 + /var/lib/jenkins/bin/aws s3 presign s3://${env.S3_BUCKET}/${env.S3_PATH}/${fileObj.name} --expires-in 604800 """, returnStdout: true ).trim() @@ -351,7 +363,7 @@ node('built-in') { artifacts.each { fileObj -> def presignedUrl = sh( script: """ - aws s3 presign s3://${env.S3_BUCKET}/${env.S3_PATH}/${fileObj.name} --expires-in 604800 + /var/lib/jenkins/bin/aws s3 presign s3://${env.S3_BUCKET}/${env.S3_PATH}/${fileObj.name} --expires-in 604800 """, returnStdout: true ).trim() diff --git a/jest.config.js b/jest.config.js index 5e611ac36ed..89e4b28058a 100644 --- a/jest.config.js +++ b/jest.config.js @@ -24,7 +24,7 @@ const jestConfig = { moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx'], testEnvironment: 'jsdom', - testPathIgnorePatterns: ['/electron/dist'], + testPathIgnorePatterns: ['/electron/dist', '/e2e-tests'], }; module.exports = jestConfig; diff --git a/package.json b/package.json index 6bc0f3f611d..948fbfcd7b6 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@babel/register": "7.28.6", "@electron/fuses": "1.8.0", "@electron/osx-sign": "1.3.3", + "@playwright/test": "1.60.0", "@types/adm-zip": "0.5.8", "@types/amplify": "1.1.28", "@types/auto-launch": "5.0.5", @@ -197,6 +198,7 @@ "start:fed": "yarn start --env=https://webapp.${FED}.wire.link/ ", "test": "yarn test:types && yarn prestart && yarn build:ts:tests && yarn test:react && yarn test:main && yarn test:renderer && yarn test:bin", "test:bin": "mocha --require .babel-register.js \"bin/**/*.test?(.main).ts\"", + "test:e2e": "playwright test", "test:main": "electron-mocha --require .babel-register.js \"electron/src/**/*.test?(.main).ts\" --no-sandbox", "test:renderer": "electron-mocha --renderer --require .babel-register.js \"electron/src/**/*.test?(.renderer).ts\" --no-sandbox --window-config electron/test/mocha-window-config.json", "test:types": "tsc --noEmit", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 00000000000..0da773c8b6d --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,55 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {defineConfig, devices} from '@playwright/test'; +import dotenv from 'dotenv'; + +import path from 'node:path'; + +dotenv.config({path: path.resolve(__dirname, './e2e-tests/.env')}); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './e2e-tests', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests because there can only be one running instance of the app at a time */ + workers: 1, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: {...devices['Desktop Chrome']}, + }, + ], +}); diff --git a/tsconfig.playwright.json b/tsconfig.playwright.json new file mode 100644 index 00000000000..afe461e589a --- /dev/null +++ b/tsconfig.playwright.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "lib": ["ESNext"] + }, + "include": ["e2e-tests/**/*.ts", "playwright.config.ts"] +} diff --git a/yarn.lock b/yarn.lock index c871d085e85..b626b787f28 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3494,6 +3494,17 @@ __metadata: languageName: node linkType: hard +"@playwright/test@npm:1.60.0": + version: 1.60.0 + resolution: "@playwright/test@npm:1.60.0" + dependencies: + playwright: 1.60.0 + bin: + playwright: cli.js + checksum: 29176a1fcf016a06299353f01de7f35817d78731294bfca62bfa44f18e2ad3a9b5f8a8480cf55046b597ee28c5c5340a4dd03a268f8fb853522ddd96a437204a + languageName: node + linkType: hard + "@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2": version: 1.1.2 resolution: "@protobufjs/aspromise@npm:1.1.2" @@ -11421,7 +11432,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": +"fsevents@npm:2.3.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": version: 2.3.2 resolution: "fsevents@npm:2.3.2" dependencies: @@ -11431,7 +11442,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": +"fsevents@patch:fsevents@2.3.2#~builtin, fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": version: 2.3.2 resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" dependencies: @@ -16546,6 +16557,30 @@ __metadata: languageName: node linkType: hard +"playwright-core@npm:1.60.0": + version: 1.60.0 + resolution: "playwright-core@npm:1.60.0" + bin: + playwright-core: cli.js + checksum: 8afc6ce9b3fc2f17ebbc671555b1d982a6e1b554c9215ba92d843e9ced8ebdd66c25996debcf1773c15b449c5fa8a42e6bc8ec0b1d96c5b5b759214c3a54c80f + languageName: node + linkType: hard + +"playwright@npm:1.60.0": + version: 1.60.0 + resolution: "playwright@npm:1.60.0" + dependencies: + fsevents: 2.3.2 + playwright-core: 1.60.0 + dependenciesMeta: + fsevents: + optional: true + bin: + playwright: cli.js + checksum: 07b893cfe34fed7039910f6bb9ecabac29888578b42ea54026815c3642989efdf9b9480184ce097c6f49cade3e8addcb026afcaf58800b639dc572ed3487ee42 + languageName: node + linkType: hard + "please-upgrade-node@npm:^3.2.0": version: 3.2.0 resolution: "please-upgrade-node@npm:3.2.0" @@ -20757,6 +20792,7 @@ __metadata: "@electron/osx-sign": 1.3.3 "@electron/remote": 2.1.3 "@hapi/joi": 17.1.1 + "@playwright/test": 1.60.0 "@types/adm-zip": 0.5.8 "@types/amplify": 1.1.28 "@types/auto-launch": 5.0.5