summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar <oskar@mullvad.net>2025-08-26 14:51:24 +0200
committerOskar <oskar@mullvad.net>2025-08-26 14:51:24 +0200
commit50922353838e936ed6f05a3f92df72ba6e93d322 (patch)
tree3544a7c401e1f643ebd128b8392688c7434308d7
parent0943270b5005ffc75818ccd9b22a349be09a9ce6 (diff)
parent641bcad1613e791562b2e3d60c2033b17d2e75d2 (diff)
downloadmullvadvpn-50922353838e936ed6f05a3f92df72ba6e93d322.tar.xz
mullvadvpn-50922353838e936ed6f05a3f92df72ba6e93d322.zip
Merge branch 'automate-remaining-parts-of-tcp-obfuscation-test-des-2209'
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/disconnected.spec.ts4
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/tunnel-state.spec.ts239
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/main/main-route-object-model.ts12
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/main/selectors.ts2
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/index.ts2
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/navigation-object-model.ts24
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/selectors.ts5
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/routes-object-model.ts6
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/index.ts2
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/selectors.ts5
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/udp-over-tcp-settings-route-object-model.ts19
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/selectors.ts1
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/vpn-settings-route-object-model.ts6
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/index.ts2
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/selectors.ts10
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/wireguard-settings-route-object-model.ts37
-rw-r--r--test/test-manager/src/tests/tunnel_state.rs8
17 files changed, 289 insertions, 95 deletions
diff --git a/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/disconnected.spec.ts b/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/disconnected.spec.ts
index 51864efa04..650ea5d380 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/disconnected.spec.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/disconnected.spec.ts
@@ -6,6 +6,10 @@ import { expectDisconnected } from '../../shared/tunnel-state';
import { TestUtils } from '../../utils';
import { startInstalledApp } from '../installed-utils';
+// This test isn't called anywhere and is available as a simple test to run manually to verify that
+// running tests works as expected. This is useful e.g. when updating packages such as electron,
+// electron builder, playwright or when making changes to build scripts.
+//
// This test expects the daemon to be logged into an account that has time left and to be
// disconnected.
diff --git a/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/tunnel-state.spec.ts b/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/tunnel-state.spec.ts
index 44ca808734..d6b25b0d99 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/tunnel-state.spec.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/tunnel-state.spec.ts
@@ -3,7 +3,7 @@ import { exec as execAsync } from 'child_process';
import { Page } from 'playwright';
import { promisify } from 'util';
-import { RoutePath } from '../../../../src/shared/routes';
+import { RoutesObjectModel } from '../../route-object-models';
import { expectConnected, expectDisconnected, expectError } from '../../shared/tunnel-state';
import { escapeRegExp, TestUtils } from '../../utils';
import { startInstalledApp } from '../installed-utils';
@@ -16,117 +16,182 @@ const exec = promisify(execAsync);
// IN_IP: In ip of the relay passed in `HOSTNAME`
// CONNECTION_CHECK_URL: Url to the connection check
+const { HOSTNAME, IN_IP, CONNECTION_CHECK_URL } = process.env;
+
let page: Page;
let util: TestUtils;
+let routes: RoutesObjectModel;
-test.beforeAll(async () => {
- ({ page, util } = await startInstalledApp());
- await util.waitForRoute(RoutePath.main);
-});
+test.describe('Tunnel state and settings', () => {
+ const startup = async () => {
+ ({ page, util } = await startInstalledApp());
+ routes = new RoutesObjectModel(page, util);
-test.afterAll(async () => {
- await page.close();
-});
+ await routes.main.waitForRoute();
+ };
-test('App should show disconnected tunnel state', async () => {
- await expectDisconnected(page);
-});
+ test.beforeAll(async () => {
+ await startup();
+ });
-test('App should connect', async () => {
- await page.getByText('Connect', { exact: true }).click();
- await expectConnected(page);
+ test.afterAll(async () => {
+ await page.close();
+ });
- const relay = page.getByTestId('hostname-line');
- const inIp = page.getByTestId('in-ip');
- // If IPv6 is enabled, there will be two "Out" IPs, one for IPv4 and one for IPv6
- // Selecting the first resolves to the IPv4 address regardless of the IP setting
- const outIp = page.locator(':text("Out") + div > span').first();
+ test('App should show disconnected tunnel state', async () => {
+ await expectDisconnected(page);
+ });
- await expect(relay).toHaveText(process.env.HOSTNAME!);
- await expect(inIp).not.toBeVisible();
- await relay.click();
+ test('App should connect', async () => {
+ await page.getByText('Connect', { exact: true }).click();
+ await expectConnected(page);
- await expect(inIp).toBeVisible();
- expect(await inIp.textContent()).toMatch(new RegExp(`^${process.env.IN_IP!}`));
+ const relay = page.getByTestId('hostname-line');
+ const inIp = page.getByTestId('in-ip');
+ // If IPv6 is enabled, there will be two "Out" IPs, one for IPv4 and one for IPv6
+ // Selecting the first resolves to the IPv4 address regardless of the IP setting
+ const outIp = page.locator(':text("Out") + div > span').first();
- await expect(outIp).toBeVisible();
+ await expect(relay).toHaveText(HOSTNAME!);
+ await expect(inIp).not.toBeVisible();
+ await relay.click();
- const ipResponse = await fetch(`${process.env.CONNECTION_CHECK_URL!}/ip`);
- const ip = await ipResponse.text();
+ await expect(inIp).toBeVisible();
+ expect(await inIp.textContent()).toMatch(new RegExp(`^${IN_IP!}`));
- expect(await outIp.textContent()).toBe(ip.trim());
-});
+ await expect(outIp).toBeVisible();
-test('App should show correct WireGuard port', async () => {
- const inData = page.getByTestId('in-ip');
+ const ipResponse = await fetch(`${CONNECTION_CHECK_URL!}/ip`);
+ const ip = await ipResponse.text();
- await expect(inData).toContainText(new RegExp(':[0-9]+'));
+ expect(await outIp.textContent()).toBe(ip.trim());
+ });
- await exec('mullvad obfuscation set mode off');
- await exec('mullvad relay set tunnel wireguard --port=53');
- await expectConnected(page);
- await page.getByTestId('connection-panel-chevron').click();
- await expect(inData).toContainText(new RegExp(':53'));
+ test('App should show correct WireGuard port', async () => {
+ const inValue1 = await routes.main.getInIpText();
+ expect(inValue1).toMatch(new RegExp(':[0-9]+'));
- await exec('mullvad relay set tunnel wireguard --port=51820');
- await expectConnected(page);
- await page.getByTestId('connection-panel-chevron').click();
- await expect(inData).toContainText(new RegExp(':51820'));
+ await exec('mullvad obfuscation set mode off');
+ await exec('mullvad relay set tunnel wireguard --port=53');
+ await expectConnected(page);
+ await routes.main.expandConnectionPanel();
- await exec('mullvad relay set tunnel wireguard --port=any');
- await exec('mullvad obfuscation set mode auto');
-});
+ const inValue2 = await routes.main.getInIpText();
+ expect(inValue2).toMatch(new RegExp(':53'));
-test('App should show correct WireGuard transport protocol', async () => {
- const inData = page.getByTestId('in-ip');
+ await exec('mullvad relay set tunnel wireguard --port=51820');
+ await expectConnected(page);
+ await routes.main.expandConnectionPanel();
- await exec('mullvad obfuscation set mode udp2tcp');
- await expectConnected(page);
- await page.getByTestId('connection-panel-chevron').click();
- await expect(inData).toContainText(new RegExp('TCP'));
+ const inValue3 = await routes.main.getInIpText();
+ expect(inValue3).toMatch(new RegExp(':51820'));
- await exec('mullvad obfuscation set mode off');
- await expectConnected(page);
- await page.getByTestId('connection-panel-chevron').click();
- await expect(inData).toContainText(new RegExp('UDP$'));
-});
+ await exec('mullvad relay set tunnel wireguard --port=any');
+ await exec('mullvad obfuscation set mode auto');
+ });
-test('App should connect with Shadowsocks', async () => {
- await exec('mullvad obfuscation set mode shadowsocks');
- await expectConnected(page);
- await exec('mullvad obfuscation set mode off');
- await expectConnected(page);
-});
+ test.describe('Wireguard UDP-over-TCP', () => {
+ async function gotoWireguardSettings() {
+ await routes.main.gotoSettings();
+ await routes.settings.gotoVpnSettings();
+ await routes.vpnSettings.gotoWireguardSettings();
+ }
-test('App should enter blocked state', async () => {
- await exec('mullvad debug block-connection');
- await expectError(page);
+ async function gotoUdpOverTcpSettings() {
+ await gotoWireguardSettings();
+ await routes.wireguardSettings.gotoUdpOverTcpSettings();
+ }
- await exec(`mullvad relay set location ${process.env.HOSTNAME}`);
- await expectConnected(page);
-});
+ test.beforeAll(async () => {
+ await exec('mullvad connect --wait');
+ });
-test('App should show multihop', async () => {
- await exec('mullvad relay set tunnel wireguard --use-multihop=on');
- await expectConnected(page);
- const relay = page.getByTestId('hostname-line');
- await expect(relay).toHaveText(
- new RegExp('^' + escapeRegExp(`${process.env.HOSTNAME} via`), 'i'),
- );
- await exec('mullvad relay set tunnel wireguard --use-multihop=off');
- await page.getByText('Disconnect').click();
-});
+ test.afterAll(async () => {
+ await routes.wireguardSettings.gotoRoot();
+ });
-test('App should disconnect', async () => {
- await page.getByText('Disconnect').click();
- await expectDisconnected(page);
-});
+ test('App should show UDP', async () => {
+ await expectConnected(page);
+ await routes.main.expandConnectionPanel();
+ const inValue = await routes.main.getInIpText();
+ expect(inValue).toMatch(new RegExp('UDP$'));
+ });
+
+ test('App should enable UDP-over-TCP', async () => {
+ await gotoWireguardSettings();
+
+ const udpOverTcpOption = routes.wireguardSettings.getUdpOverTcpOption();
+ await expect(udpOverTcpOption).toHaveAttribute('aria-selected', 'false');
+
+ await routes.wireguardSettings.selectUdpOverTcp();
+ await expect(udpOverTcpOption).toHaveAttribute('aria-selected', 'true');
+
+ await routes.wireguardSettings.gotoRoot();
+
+ await expectConnected(page);
+
+ await routes.main.expandConnectionPanel();
+
+ const inValue = await routes.main.getInIpText();
+ expect(inValue).toMatch(new RegExp(`${escapeRegExp(IN_IP!)}:(80|5001) TCP`));
+ });
+
+ for (const port of [80, 5001]) {
+ test(`App should show port ${port}`, async () => {
+ await gotoUdpOverTcpSettings();
+ await routes.udpOverTcpSettings.selectPort(port);
+ await routes.udpOverTcpSettings.gotoRoot();
+ await routes.main.expandConnectionPanel();
+
+ const inValue = await routes.main.getInIpText();
+ expect(inValue).toMatch(`${IN_IP}:${port} TCP`);
+ });
+ }
+
+ test('App should set obfuscation to automatic', async () => {
+ await gotoWireguardSettings();
+ await routes.wireguardSettings.selectAutomaticObfuscation();
+
+ const automaticOption = routes.wireguardSettings.getAutomaticObfuscationOption();
+ await expect(automaticOption).toHaveAttribute('aria-selected', 'true');
+ });
+ });
+
+ test('App should connect with Shadowsocks', async () => {
+ await exec('mullvad obfuscation set mode shadowsocks');
+ await expectConnected(page);
+ await exec('mullvad obfuscation set mode off');
+ await expectConnected(page);
+ });
+
+ test('App should enter blocked state', async () => {
+ await exec('mullvad debug block-connection');
+ await expectError(page);
+
+ await exec(`mullvad relay set location ${HOSTNAME}`);
+ await expectConnected(page);
+ });
+
+ test('App should show multihop', async () => {
+ await exec('mullvad relay set tunnel wireguard --use-multihop=on');
+ await expectConnected(page);
+ const relay = page.getByTestId('hostname-line');
+ await expect(relay).toHaveText(new RegExp('^' + escapeRegExp(`${HOSTNAME} via`), 'i'));
+ await exec('mullvad relay set tunnel wireguard --use-multihop=off');
+ await page.getByText('Disconnect').click();
+ });
+
+ test('App should disconnect', async () => {
+ await page.getByText('Disconnect').click();
+ await expectDisconnected(page);
+ });
-test('App should become connected when other frontend connects', async () => {
- await expectDisconnected(page);
- await exec('mullvad connect');
- await expectConnected(page);
+ test('App should become connected when other frontend connects', async () => {
+ await expectDisconnected(page);
+ await exec('mullvad connect');
+ await expectConnected(page);
- await exec('mullvad disconnect');
- await expectDisconnected(page);
+ await exec('mullvad disconnect');
+ await expectDisconnected(page);
+ });
});
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/main/main-route-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/main/main-route-object-model.ts
index ea76183ac3..ec73d591a4 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/main/main-route-object-model.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/main/main-route-object-model.ts
@@ -28,4 +28,16 @@ export class MainRouteObjectModel {
await this.selectors.selectLocationButton().click();
await this.utils.waitForRoute(RoutePath.selectLocation);
}
+
+ async expandConnectionPanel() {
+ await this.selectors.connectionPanelChevronButton().click();
+ }
+
+ getInIp() {
+ return this.selectors.inIpLabel();
+ }
+
+ getInIpText() {
+ return this.getInIp().innerText();
+ }
}
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/main/selectors.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/main/selectors.ts
index 077a34db2d..0e3cbaaa3b 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/main/selectors.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/main/selectors.ts
@@ -3,4 +3,6 @@ import { Page } from 'playwright';
export const createSelectors = (page: Page) => ({
settingsButton: () => page.locator('button[aria-label="Settings"]'),
selectLocationButton: () => page.getByLabel('Select location'),
+ connectionPanelChevronButton: () => page.getByTestId('connection-panel-chevron'),
+ inIpLabel: () => page.getByTestId('in-ip'),
});
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/index.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/index.ts
new file mode 100644
index 0000000000..5513f2ede3
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/index.ts
@@ -0,0 +1,2 @@
+export * from './navigation-object-model';
+export * from './selectors';
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/navigation-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/navigation-object-model.ts
new file mode 100644
index 0000000000..3234905965
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/navigation-object-model.ts
@@ -0,0 +1,24 @@
+import { Page } from 'playwright';
+
+import { TestUtils } from '../../utils';
+import { createSelectors } from './selectors';
+
+export class NavigationObjectModel {
+ readonly navigationSelectors: ReturnType<typeof createSelectors>;
+
+ constructor(
+ protected readonly page: Page,
+ protected readonly utils: TestUtils,
+ ) {
+ this.navigationSelectors = createSelectors(page);
+ }
+
+ async goBack() {
+ await this.navigationSelectors.backButton().click();
+ await this.utils.waitForNextRoute();
+ }
+
+ async gotoRoot() {
+ await this.page.press('body', 'Shift+Escape');
+ }
+}
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/selectors.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/selectors.ts
new file mode 100644
index 0000000000..027b6f3018
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/navigation/selectors.ts
@@ -0,0 +1,5 @@
+import { Page } from 'playwright';
+
+export const createSelectors = (page: Page) => ({
+ backButton: () => page.getByRole('button', { name: /(Back|Close)/ }),
+});
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/routes-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/routes-object-model.ts
index d85c698984..2de9fa7d64 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/routes-object-model.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/routes-object-model.ts
@@ -9,8 +9,10 @@ import { MultihopSettingsRouteObjectModel } from './multihop-settings';
import { SelectLanguageRouteObjectModel } from './select-language';
import { SelectLocationRouteObjectModel } from './select-location';
import { SettingsRouteObjectModel } from './settings/settings-route-object-model';
+import { UdpOverTcpSettingsRouteObjectModel } from './udp-over-tcp-settings';
import { UserInterfaceSettingsRouteObjectModel } from './user-interface-settings';
import { VpnSettingsRouteObjectModel } from './vpn-settings';
+import { WireguardSettingsRouteObjectModel } from './wireguard-settings';
export class RoutesObjectModel {
readonly main: MainRouteObjectModel;
@@ -21,6 +23,8 @@ export class RoutesObjectModel {
readonly filter: FilterRouteObjectModel;
readonly selectLocation: SelectLocationRouteObjectModel;
readonly vpnSettings: VpnSettingsRouteObjectModel;
+ readonly wireguardSettings: WireguardSettingsRouteObjectModel;
+ readonly udpOverTcpSettings: UdpOverTcpSettingsRouteObjectModel;
readonly multihopSettings: MultihopSettingsRouteObjectModel;
readonly daitaSettings: DaitaSettingsRouteObjectModel;
@@ -33,6 +37,8 @@ export class RoutesObjectModel {
this.filter = new FilterRouteObjectModel(page, utils);
this.selectLocation = new SelectLocationRouteObjectModel(page, utils);
this.vpnSettings = new VpnSettingsRouteObjectModel(page, utils);
+ this.wireguardSettings = new WireguardSettingsRouteObjectModel(page, utils);
+ this.udpOverTcpSettings = new UdpOverTcpSettingsRouteObjectModel(page, utils);
this.multihopSettings = new MultihopSettingsRouteObjectModel(page, utils);
this.daitaSettings = new DaitaSettingsRouteObjectModel(page, utils);
}
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/index.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/index.ts
new file mode 100644
index 0000000000..89fbb87028
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/index.ts
@@ -0,0 +1,2 @@
+export * from './udp-over-tcp-settings-route-object-model';
+export * from './selectors';
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/selectors.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/selectors.ts
new file mode 100644
index 0000000000..f993e501ca
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/selectors.ts
@@ -0,0 +1,5 @@
+import { Page } from 'playwright';
+
+export const createSelectors = (page: Page) => ({
+ portNumber: (port: number) => page.getByRole('option', { name: `${port}` }),
+});
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/udp-over-tcp-settings-route-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/udp-over-tcp-settings-route-object-model.ts
new file mode 100644
index 0000000000..962a350311
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/udp-over-tcp-settings-route-object-model.ts
@@ -0,0 +1,19 @@
+import { Page } from 'playwright';
+
+import { TestUtils } from '../../utils';
+import { NavigationObjectModel } from '../navigation';
+import { createSelectors } from './selectors';
+
+export class UdpOverTcpSettingsRouteObjectModel extends NavigationObjectModel {
+ readonly selectors: ReturnType<typeof createSelectors>;
+
+ constructor(page: Page, utils: TestUtils) {
+ super(page, utils);
+
+ this.selectors = createSelectors(page);
+ }
+
+ async selectPort(port: number) {
+ await this.selectors.portNumber(port).click();
+ }
+}
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/selectors.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/selectors.ts
index ebae817f2f..367f84e38d 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/selectors.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/selectors.ts
@@ -4,4 +4,5 @@ export const createSelectors = (page: Page) => ({
launchAppOnStartupSwitch: () => page.getByLabel('Launch app on start-up'),
autoConnectSwitch: () => page.getByLabel('Auto-connect'),
lanSwitch: () => page.getByLabel('Local network sharing'),
+ wireguardSettingsButton: () => page.getByRole('button', { name: 'WireGuard settings' }),
});
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/vpn-settings-route-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/vpn-settings-route-object-model.ts
index 5e8ea0e99b..e1c05ee801 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/vpn-settings-route-object-model.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/vpn-settings-route-object-model.ts
@@ -1,5 +1,6 @@
import { Page } from 'playwright';
+import { RoutePath } from '../../../../src/shared/routes';
import { TestUtils } from '../../utils';
import { createSelectors } from './selectors';
@@ -14,6 +15,11 @@ export class VpnSettingsRouteObjectModel {
this.selectors = createSelectors(page);
}
+ async gotoWireguardSettings() {
+ await this.selectors.wireguardSettingsButton().click();
+ await this.utils.waitForRoute(RoutePath.wireguardSettings);
+ }
+
getAutoConnectSwitch() {
return this.selectors.autoConnectSwitch();
}
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/index.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/index.ts
new file mode 100644
index 0000000000..4378d9c067
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/index.ts
@@ -0,0 +1,2 @@
+export * from './wireguard-settings-route-object-model';
+export * from './selectors';
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/selectors.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/selectors.ts
new file mode 100644
index 0000000000..ff7621e637
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/selectors.ts
@@ -0,0 +1,10 @@
+import { Page } from 'playwright';
+
+export const createSelectors = (page: Page) => ({
+ udpOverTcpSettingsButton: () => page.getByRole('button', { name: 'UDP-over-TCP settings' }),
+ udpOverTcpOption: () => page.getByRole('option', { name: 'UDP-over-TCP' }),
+ automaticObfuscationOption: () =>
+ page
+ .getByRole('listbox', { name: 'Obfuscation' })
+ .getByRole('option', { name: 'Automatic', exact: true }),
+});
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/wireguard-settings-route-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/wireguard-settings-route-object-model.ts
new file mode 100644
index 0000000000..409c9ed725
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/wireguard-settings-route-object-model.ts
@@ -0,0 +1,37 @@
+import { Page } from 'playwright';
+
+import { RoutePath } from '../../../../src/shared/routes';
+import { TestUtils } from '../../utils';
+import { NavigationObjectModel } from '../navigation';
+import { createSelectors } from './selectors';
+
+export class WireguardSettingsRouteObjectModel extends NavigationObjectModel {
+ readonly selectors: ReturnType<typeof createSelectors>;
+
+ constructor(page: Page, utils: TestUtils) {
+ super(page, utils);
+
+ this.selectors = createSelectors(page);
+ }
+
+ async gotoUdpOverTcpSettings() {
+ await this.selectors.udpOverTcpSettingsButton().click();
+ await this.utils.waitForRoute(RoutePath.udpOverTcp);
+ }
+
+ getAutomaticObfuscationOption() {
+ return this.selectors.automaticObfuscationOption();
+ }
+
+ async selectAutomaticObfuscation() {
+ await this.getAutomaticObfuscationOption().click();
+ }
+
+ getUdpOverTcpOption() {
+ return this.selectors.udpOverTcpOption();
+ }
+
+ async selectUdpOverTcp() {
+ await this.getUdpOverTcpOption().click();
+ }
+}
diff --git a/test/test-manager/src/tests/tunnel_state.rs b/test/test-manager/src/tests/tunnel_state.rs
index 4a02ede39d..b6b22cfa12 100644
--- a/test/test-manager/src/tests/tunnel_state.rs
+++ b/test/test-manager/src/tests/tunnel_state.rs
@@ -4,7 +4,6 @@ use super::{
self, connect_and_wait, send_guest_probes, unreachable_wireguard_tunnel,
wait_for_tunnel_state,
},
- ui,
};
use crate::{
assert_tunnel_state,
@@ -146,13 +145,6 @@ pub async fn test_disconnected_state(
"did not see (all) outgoing packets to destination: {detected_probes:?}",
);
- // Test UI view
- //
-
- log::info!("UI: Test disconnected state");
- let ui_result = ui::run_test(&rpc, &["disconnected.spec"]).await.unwrap();
- assert!(ui_result.success());
-
Ok(())
}