Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
29 changes: 0 additions & 29 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -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):
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
.vscode
*.log
*.pkg
.env
coverage
.nyc_output
/config
Expand Down Expand Up @@ -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/
2 changes: 2 additions & 0 deletions e2e-tests/.env.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
WEBAPP_URL=op://Test Automation/BackendConnection staging/webappUrl
BACKEND_URL=op://Test Automation/BackendConnection staging/backendUrl
21 changes: 21 additions & 0 deletions e2e-tests/README.md
Original file line number Diff line number Diff line change
@@ -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`.
52 changes: 52 additions & 0 deletions e2e-tests/fixtures.ts
Original file line number Diff line number Diff line change
@@ -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<FixtureOptions & Fixtures>({
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';
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
46 changes: 46 additions & 0 deletions e2e-tests/utils/createApp.ts
Original file line number Diff line number Diff line change
@@ -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<App> => {
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});
};
1 change: 1 addition & 0 deletions electron/src/lib/eventType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
15 changes: 0 additions & 15 deletions electron/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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);
Expand Down Expand Up @@ -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.');
}
}
7 changes: 7 additions & 0 deletions electron/src/preload/preload-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
7 changes: 5 additions & 2 deletions electron/src/preload/preload-webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
});
Expand Down
2 changes: 0 additions & 2 deletions electron/src/settings/SettingsType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
}
2 changes: 0 additions & 2 deletions electron/src/types/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -43,7 +42,6 @@ export declare global {
version: number;
};
var environment: typeof EnvironmentUtil;
var desktopAppSettings: typeof SettingsUtil;
var openGraphAsync: (url: string) => Promise<OpenGraphResult>;
var desktopAppConfig: {
version: string;
Expand Down
Loading
Loading