summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar <oskar@mullvad.net>2025-09-30 12:12:00 +0200
committerOskar <oskar@mullvad.net>2025-09-30 12:12:00 +0200
commitc7feb62a4e74c6f5f58c267ea76ee56c40a55fea (patch)
tree8099d01800c7e5947dade2b2c287b7a29c9ae12d
parente58b5ee1a8db4d5cf68826301daa8380ed1249bf (diff)
parent1be072d3168e1799224d7d3930943df9853d5987 (diff)
downloadmullvadvpn-c7feb62a4e74c6f5f58c267ea76ee56c40a55fea.tar.xz
mullvadvpn-c7feb62a4e74c6f5f58c267ea76ee56c40a55fea.zip
Merge branch 'quick-access-feature-setting-state-e2e-tests'
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/wireguard-settings/components/obfuscation-settings/ObfuscationSettings.tsx4
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/obfuscation.spec.ts86
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/selectors.ts2
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/selectors.ts2
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/routes-object-model.ts3
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/index.ts2
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/selectors.ts13
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/shadowsocks-settings-route-object-model.ts22
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/udp-over-tcp-settings/selectors.ts4
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/vpn-settings/selectors.ts6
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/selectors.ts2
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/wireguard-settings/wireguard-settings-route-object-model.ts9
12 files changed, 97 insertions, 58 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/wireguard-settings/components/obfuscation-settings/ObfuscationSettings.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/wireguard-settings/components/obfuscation-settings/ObfuscationSettings.tsx
index 0ac893db9e..aa9b1e7835 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/views/wireguard-settings/components/obfuscation-settings/ObfuscationSettings.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/wireguard-settings/components/obfuscation-settings/ObfuscationSettings.tsx
@@ -83,7 +83,7 @@ export function ObfuscationSettings() {
</SettingsListbox.SplitOption.Item>
<SettingsListbox.SplitOption.NavigateButton
to={RoutePath.shadowsocks}
- aria-description={messages.pgettext('accessibility', 'Shadowsocks settings')}
+ aria-label={messages.pgettext('accessibility', 'Shadowsocks settings')}
/>
</SettingsListbox.SplitOption>
<SettingsListbox.SplitOption value={ObfuscationType.udp2tcp}>
@@ -101,7 +101,7 @@ export function ObfuscationSettings() {
</SettingsListbox.SplitOption.Item>
<SettingsListbox.SplitOption.NavigateButton
to={RoutePath.udpOverTcp}
- aria-description={messages.pgettext('accessibility', 'UDP-over-TCP settings')}
+ aria-label={messages.pgettext('accessibility', 'UDP-over-TCP settings')}
/>
</SettingsListbox.SplitOption>
<SettingsListbox.BaseOption value={ObfuscationType.quic}>
diff --git a/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/obfuscation.spec.ts b/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/obfuscation.spec.ts
index 9c2f3c3348..b0d81a7f54 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/obfuscation.spec.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/obfuscation.spec.ts
@@ -2,8 +2,8 @@ import { expect, test } from '@playwright/test';
import { execSync } from 'child_process';
import { Page } from 'playwright';
-import { colorTokens } from '../../../../src/renderer/lib/foundations';
import { RoutePath } from '../../../../src/shared/routes';
+import { RoutesObjectModel } from '../../route-object-models';
import { TestUtils } from '../../utils';
import { startInstalledApp } from '../installed-utils';
@@ -15,10 +15,15 @@ const UDPOVERTCP_PORT = '80';
let page: Page;
let util: TestUtils;
+let routes: RoutesObjectModel;
test.beforeAll(async () => {
({ page, util } = await startInstalledApp());
+ routes = new RoutesObjectModel(page, util);
await util.expectRoute(RoutePath.main);
+ await routes.main.gotoSettings();
+ await routes.settings.gotoVpnSettings();
+ await routes.vpnSettings.gotoWireguardSettings();
});
test.afterAll(async () => {
@@ -26,22 +31,10 @@ test.afterAll(async () => {
});
test('App should have automatic obfuscation', async () => {
- await page.click('button[aria-label="Settings"]');
- await util.expectRoute(RoutePath.settings);
+ const automaticObfuscationOption =
+ routes.wireguardSettings.selectors.automaticObfuscationOption();
- await page.getByText('VPN settings').click();
- await util.expectRoute(RoutePath.vpnSettings);
-
- await page.getByText('WireGuard settings').click();
- await util.expectRoute(RoutePath.wireguardSettings);
-
- const obfuscationListbox = page.getByRole('listbox', { name: 'Obfuscation' });
- await obfuscationListbox.highlight();
- const automaticOption = obfuscationListbox.getByRole('option', {
- name: 'Automatic',
- exact: true,
- });
- await expect(automaticOption).toHaveAttribute('aria-selected', 'true');
+ await expect(automaticObfuscationOption).toHaveAttribute('aria-selected', 'true');
const cliObfuscation = execSync('mullvad obfuscation get').toString().split('\n');
expect(cliObfuscation[0]).toEqual('Obfuscation mode: auto');
@@ -50,61 +43,52 @@ test('App should have automatic obfuscation', async () => {
});
test('App should set obfuscation to shadowsocks with custom port', async () => {
- await page.click('button[aria-label="Shadowsocks settings"]');
- await util.expectRoute(RoutePath.shadowsocks);
+ await routes.wireguardSettings.gotoShadowSocksSettings();
+ const automaticOption = routes.shadowsocksSettings.selectors.automaticPortOption();
- const automatic = page.locator('button', { hasText: 'Automatic' });
- await expect(automatic).toHaveCSS('background-color', colorTokens.green);
+ await expect(automaticOption).toHaveAttribute('aria-selected', 'true');
- const customInput = page.locator('input[type="text"]');
- await customInput.click();
- await customInput.fill(`${SHADOWSOCKS_PORT}`);
- await customInput.blur();
+ await routes.shadowsocksSettings.fillPortInput(SHADOWSOCKS_PORT);
- const customItem = page.locator('div[role="option"]', { hasText: 'Custom' });
- await expect(customItem).toHaveCSS('background-color', colorTokens.green);
+ const customPortOption = routes.shadowsocksSettings.selectors.customPortOption();
+ await expect(customPortOption).toHaveAttribute('aria-selected', 'true');
- await page.click('button[aria-label="Back"]');
- await util.expectRoute(RoutePath.wireguardSettings);
+ await routes.shadowsocksSettings.goBack();
- const shadowsocksItem = page.locator('button', { hasText: 'Shadowsocks' });
- await shadowsocksItem.click();
- await expect(shadowsocksItem).toHaveCSS('background-color', colorTokens.green);
- await expect(shadowsocksItem).toContainText(`Port: ${SHADOWSOCKS_PORT}`);
+ const shadowsocksOption = routes.wireguardSettings.selectors.shadowsocksOption();
+ await expect(shadowsocksOption).toContainText(`Port: ${SHADOWSOCKS_PORT}`);
+
+ await routes.wireguardSettings.selectShadowsocks();
+ await expect(shadowsocksOption).toHaveAttribute('aria-selected', 'true');
const cliObfuscation = execSync('mullvad obfuscation get').toString().split('\n')[2];
expect(cliObfuscation).toEqual(`Shadowsocks settings: port ${SHADOWSOCKS_PORT}`);
});
test('App should still have shadowsocks custom port', async () => {
- await page.click('button[aria-label="Shadowsocks settings"]');
- await util.expectRoute(RoutePath.shadowsocks);
+ await routes.wireguardSettings.gotoShadowSocksSettings();
- const customItem = page.locator('div[role="option"]', { hasText: 'Custom' });
- await expect(customItem).toHaveCSS('background-color', colorTokens.green);
+ const customPortOption = routes.shadowsocksSettings.selectors.customPortOption();
+ await expect(customPortOption).toHaveAttribute('aria-selected', 'true');
- await page.click('button[aria-label="Back"]');
- await util.expectRoute(RoutePath.wireguardSettings);
+ await routes.shadowsocksSettings.goBack();
});
test('App should set obfuscation to UDP-over-TCP with port', async () => {
- await page.click('button[aria-label="UDP-over-TCP settings"]');
- await util.expectRoute(RoutePath.udpOverTcp);
-
- const automatic = page.locator('button', { hasText: 'Automatic' });
- await expect(automatic).toHaveCSS('background-color', colorTokens.green);
+ await routes.wireguardSettings.gotoUdpOverTcpSettings();
- const portButton = page.locator('button', { hasText: UDPOVERTCP_PORT });
- await portButton.click();
+ const automaticOption = routes.udpOverTcpSettings.selectors.automaticPortOption();
+ await expect(automaticOption).toHaveAttribute('aria-selected', 'true');
- await expect(portButton).toHaveCSS('background-color', colorTokens.green);
+ await routes.udpOverTcpSettings.selectPort(parseInt(UDPOVERTCP_PORT));
+ const portButton = routes.udpOverTcpSettings.selectors.portNumber(parseInt(UDPOVERTCP_PORT));
+ await expect(portButton).toHaveAttribute('aria-selected', 'true');
- await page.click('button[aria-label="Back"]');
- await util.expectRoute(RoutePath.wireguardSettings);
+ await routes.udpOverTcpSettings.goBack();
- const udpOverTcpItem = page.locator('button', { hasText: 'UDP-over-TCP' });
- await udpOverTcpItem.click();
- await expect(udpOverTcpItem).toHaveCSS('background-color', colorTokens.green);
+ const udpOverTcpItem = routes.wireguardSettings.selectors.udpOverTcpOption();
+ await routes.wireguardSettings.selectUdpOverTcp();
+ await expect(udpOverTcpItem).toHaveAttribute('aria-selected', 'true');
await expect(udpOverTcpItem).toContainText(`Port: ${UDPOVERTCP_PORT}`);
const cliObfuscation = execSync('mullvad obfuscation get').toString().split('\n')[1];
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/selectors.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/selectors.ts
index 4c8f8c51bd..ece73c4c72 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/selectors.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/selectors.ts
@@ -1,5 +1,5 @@
import { Page } from 'playwright';
export const createSelectors = (page: Page) => ({
- enableDaitaSwitch: () => page.getByLabel('Enable'),
+ enableDaitaSwitch: () => page.getByRole('switch', { name: 'Enable' }),
});
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/selectors.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/selectors.ts
index 217ed920a2..333a436574 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/selectors.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/selectors.ts
@@ -1,5 +1,5 @@
import { Page } from 'playwright';
export const createSelectors = (page: Page) => ({
- enableMultihopSwitch: () => page.getByRole('checkbox', { name: 'Enable' }),
+ enableMultihopSwitch: () => page.getByRole('switch', { name: 'Enable' }),
});
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 9cf32e5caf..997247d2fa 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
@@ -10,6 +10,7 @@ import { MultihopSettingsRouteObjectModel } from './multihop-settings';
import { SelectLanguageRouteObjectModel } from './select-language';
import { SelectLocationRouteObjectModel } from './select-location';
import { SettingsRouteObjectModel } from './settings/settings-route-object-model';
+import { ShadowsocksSettingsRouteObjectModel } from './shadowsocks-settings';
import { SplitTunnelingSettingsRouteObjectModel } from './split-tunneling-settings';
import { UdpOverTcpSettingsRouteObjectModel } from './udp-over-tcp-settings';
import { UserInterfaceSettingsRouteObjectModel } from './user-interface-settings';
@@ -31,6 +32,7 @@ export class RoutesObjectModel {
readonly multihopSettings: MultihopSettingsRouteObjectModel;
readonly daitaSettings: DaitaSettingsRouteObjectModel;
readonly splitTunnelingSettings: SplitTunnelingSettingsRouteObjectModel;
+ readonly shadowsocksSettings: ShadowsocksSettingsRouteObjectModel;
constructor(page: Page, utils: TestUtils) {
this.selectLanguage = new SelectLanguageRouteObjectModel(page, utils);
@@ -47,5 +49,6 @@ export class RoutesObjectModel {
this.multihopSettings = new MultihopSettingsRouteObjectModel(page, utils);
this.daitaSettings = new DaitaSettingsRouteObjectModel(page, utils);
this.splitTunnelingSettings = new SplitTunnelingSettingsRouteObjectModel(page, utils);
+ this.shadowsocksSettings = new ShadowsocksSettingsRouteObjectModel(page, utils);
}
}
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/index.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/index.ts
new file mode 100644
index 0000000000..ee8499fbda
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/index.ts
@@ -0,0 +1,2 @@
+export * from './shadowsocks-settings-route-object-model';
+export * from './selectors';
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/selectors.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/selectors.ts
new file mode 100644
index 0000000000..6d7844396d
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/selectors.ts
@@ -0,0 +1,13 @@
+import { Page } from 'playwright';
+
+export const createSelectors = (page: Page) => ({
+ automaticPortOption: () =>
+ page
+ .getByRole('listbox', { name: 'Port' })
+ .getByRole('option', { name: 'Automatic', exact: true }),
+ customPortOption: () =>
+ page
+ .getByRole('listbox', { name: 'Port' })
+ .getByRole('option', { name: 'Custom', exact: true }),
+ portInput: () => page.getByPlaceholder('Port'),
+});
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/shadowsocks-settings-route-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/shadowsocks-settings-route-object-model.ts
new file mode 100644
index 0000000000..3c56fa5bc0
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/shadowsocks-settings/shadowsocks-settings-route-object-model.ts
@@ -0,0 +1,22 @@
+import { Page } from 'playwright';
+
+import { TestUtils } from '../../utils';
+import { NavigationObjectModel } from '../navigation';
+import { createSelectors } from './selectors';
+
+export class ShadowsocksSettingsRouteObjectModel extends NavigationObjectModel {
+ readonly selectors: ReturnType<typeof createSelectors>;
+
+ constructor(page: Page, utils: TestUtils) {
+ super(page, utils);
+
+ this.selectors = createSelectors(page);
+ }
+
+ async fillPortInput(port: number) {
+ const input = this.selectors.portInput();
+ await input.click();
+ await input.fill(`${port}`);
+ await input.press('Enter');
+ }
+}
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
index f993e501ca..ca2e4ad402 100644
--- 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
@@ -2,4 +2,8 @@ import { Page } from 'playwright';
export const createSelectors = (page: Page) => ({
portNumber: (port: number) => page.getByRole('option', { name: `${port}` }),
+ automaticPortOption: () =>
+ page
+ .getByRole('listbox', { name: 'Port' })
+ .getByRole('option', { name: 'Automatic', exact: true }),
});
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 607756d76f..29e32ff9b6 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
@@ -2,8 +2,8 @@ import { Page } from 'playwright';
export const createSelectors = (page: Page) => ({
heading: () => page.getByRole('heading', { name: 'VPN settings' }),
- launchAppOnStartupSwitch: () => page.getByLabel('Launch app on start-up'),
- autoConnectSwitch: () => page.getByLabel('Auto-connect'),
- lanSwitch: () => page.getByLabel('Local network sharing'),
+ launchAppOnStartupSwitch: () => page.getByRole('switch', { name: 'Launch app on start-up' }),
+ autoConnectSwitch: () => page.getByRole('switch', { name: 'Auto-connect' }),
+ lanSwitch: () => page.getByRole('switch', { name: 'Local network sharing' }),
wireguardSettingsButton: () => page.getByRole('button', { name: 'WireGuard settings' }),
});
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
index ff7621e637..d7b3ed004c 100644
--- 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
@@ -7,4 +7,6 @@ export const createSelectors = (page: Page) => ({
page
.getByRole('listbox', { name: 'Obfuscation' })
.getByRole('option', { name: 'Automatic', exact: true }),
+ shadowsocksSettingsButton: () => page.getByRole('button', { name: 'Shadowsocks settings' }),
+ shadowsocksOption: () => page.getByRole('option', { name: 'Shadowsocks' }),
});
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
index fa568fd9cc..cfaae197d3 100644
--- 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
@@ -34,4 +34,13 @@ export class WireguardSettingsRouteObjectModel extends NavigationObjectModel {
async selectUdpOverTcp() {
await this.getUdpOverTcpOption().click();
}
+
+ async selectShadowsocks() {
+ await this.selectors.shadowsocksOption().click();
+ }
+
+ async gotoShadowSocksSettings() {
+ await this.selectors.shadowsocksSettingsButton().click();
+ await this.utils.expectRoute(RoutePath.shadowsocks);
+ }
}