diff options
| author | David Lönnhager <david.l@mullvad.net> | 2025-07-31 13:25:12 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2025-07-31 13:25:12 +0200 |
| commit | aecbd37675e8517354f73c0bccb25b38d885e9bb (patch) | |
| tree | a402dd2f20798bf91ae605eac451b2c94d085afd | |
| parent | 466d3d3e386518d0945945d78dce63bfed7326ab (diff) | |
| parent | 0ab44b55ae30db9f32f7893096bf30acde2aa18f (diff) | |
| download | mullvadvpn-aecbd37675e8517354f73c0bccb25b38d885e9bb.tar.xz mullvadvpn-aecbd37675e8517354f73c0bccb25b38d885e9bb.zip | |
Merge branch 'automate-remaining-parts-of-daitamultihop-manual-test-card-des-2210'
20 files changed, 395 insertions, 88 deletions
diff --git a/desktop/packages/mullvad-vpn/src/main/index.ts b/desktop/packages/mullvad-vpn/src/main/index.ts index 457a192a1a..9c354f4dd4 100644 --- a/desktop/packages/mullvad-vpn/src/main/index.ts +++ b/desktop/packages/mullvad-vpn/src/main/index.ts @@ -157,6 +157,7 @@ class ApplicationMain } if (process.platform === 'linux') { + // NOTE: Keep in sync with mocked-utils.ts app.commandLine.appendSwitch('gtk-version', '3'); } diff --git a/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/daita-settings/daita-settings.spec.ts b/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/daita-settings/daita-settings.spec.ts new file mode 100644 index 0000000000..dd3335059f --- /dev/null +++ b/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/daita-settings/daita-settings.spec.ts @@ -0,0 +1,44 @@ +import { expect, test } from '@playwright/test'; +import { Page } from 'playwright'; + +import { RoutesObjectModel } from '../../../route-object-models'; +import { TestUtils } from '../../../utils'; +import { startInstalledApp } from '../../installed-utils'; + +let page: Page; +let util: TestUtils; +let routes: RoutesObjectModel; + +test.describe('DAITA settings', () => { + const startup = async () => { + ({ page, util } = await startInstalledApp()); + routes = new RoutesObjectModel(page, util); + + await routes.main.waitForRoute(); + await routes.main.gotoSettings(); + await routes.settings.gotoDaitaSettings(); + await routes.daitaSettings.setEnableDaitaSwitch(false); + }; + + test.beforeAll(async () => { + await startup(); + }); + + test.afterAll(async () => { + await page.close(); + }); + + test.afterEach(async () => { + await routes.daitaSettings.setEnableDaitaSwitch(false); + const daitaSwitch = routes.daitaSettings.getEnableDaitaSwitch(); + + await expect(daitaSwitch).toHaveAttribute('aria-checked', 'false'); + }); + + test('Should enable DAITA when clicking switch', async () => { + await routes.daitaSettings.setEnableDaitaSwitch(true); + const daitaSwitch = routes.daitaSettings.getEnableDaitaSwitch(); + + await expect(daitaSwitch).toHaveAttribute('aria-checked', 'true'); + }); +}); diff --git a/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/multihop-settings/multihop-settings.spec.ts b/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/multihop-settings/multihop-settings.spec.ts new file mode 100644 index 0000000000..0cc819828b --- /dev/null +++ b/desktop/packages/mullvad-vpn/test/e2e/installed/state-dependent/multihop-settings/multihop-settings.spec.ts @@ -0,0 +1,43 @@ +import { expect, test } from '@playwright/test'; +import { Page } from 'playwright'; + +import { RoutesObjectModel } from '../../../route-object-models'; +import { TestUtils } from '../../../utils'; +import { startInstalledApp } from '../../installed-utils'; + +let page: Page; +let util: TestUtils; +let routes: RoutesObjectModel; + +test.describe('Multihop settings', () => { + const startup = async () => { + ({ page, util } = await startInstalledApp()); + routes = new RoutesObjectModel(page, util); + + await routes.main.waitForRoute(); + await routes.main.gotoSettings(); + await routes.settings.gotoMultihopSettings(); + }; + + test.beforeAll(async () => { + await startup(); + }); + + test.afterAll(async () => { + await page.close(); + }); + + test.afterEach(async () => { + await routes.multihopSettings.setEnableMultihopSwitch(false); + const multihopSwitch = routes.multihopSettings.getEnableMultihopSwitch(); + + await expect(multihopSwitch).toHaveAttribute('aria-checked', 'false'); + }); + + test('Should enable multihop when clicking switch', async () => { + await routes.multihopSettings.setEnableMultihopSwitch(true); + const multihopSwitch = routes.multihopSettings.getEnableMultihopSwitch(); + + await expect(multihopSwitch).toHaveAttribute('aria-checked', 'true'); + }); +}); diff --git a/desktop/packages/mullvad-vpn/test/e2e/mocked/select-location/mock-data.ts b/desktop/packages/mullvad-vpn/test/e2e/mock-data.ts index f3039c2537..efbac88f83 100644 --- a/desktop/packages/mullvad-vpn/test/e2e/mocked/select-location/mock-data.ts +++ b/desktop/packages/mullvad-vpn/test/e2e/mock-data.ts @@ -1,4 +1,4 @@ -import { IRelayList } from '../../../../src/shared/daemon-rpc-types'; +import { IRelayList } from '../../src/shared/daemon-rpc-types'; const relayList: IRelayList = { countries: [ @@ -13,7 +13,7 @@ const relayList: IRelayList = { longitude: 12, relays: [ { - hostname: 'my-test-relay1', + hostname: 'mullvad-wireguard-1', provider: 'mullvad', ipv4AddrIn: '10.0.0.1', includeInCountry: true, @@ -24,7 +24,7 @@ const relayList: IRelayList = { daita: true, }, { - hostname: 'my-test-relay2', + hostname: 'mullvad-wireguard-23', provider: 'mullvad', ipv4AddrIn: '10.0.0.2', includeInCountry: true, @@ -35,7 +35,7 @@ const relayList: IRelayList = { daita: true, }, { - hostname: 'se-got-wg-103', + hostname: 'another-provider-wireguard-1', provider: 'another-provider', ipv4AddrIn: '10.0.0.3', includeInCountry: true, @@ -46,7 +46,7 @@ const relayList: IRelayList = { daita: true, }, { - hostname: 'se-got-wg-104', + hostname: 'mullvad-wireguard-quic-1', provider: 'mullvad', ipv4AddrIn: '10.0.0.4', includeInCountry: true, @@ -61,6 +61,17 @@ const relayList: IRelayList = { token: '', }, }, + { + hostname: 'mullvad-openvpn-1', + provider: 'mullvad', + ipv4AddrIn: '10.0.0.2', + includeInCountry: true, + active: true, + weight: 0, + owned: true, + endpointType: 'openvpn', + daita: true, + }, ], }, ], diff --git a/desktop/packages/mullvad-vpn/test/e2e/mocked/mocked-utils.ts b/desktop/packages/mullvad-vpn/test/e2e/mocked/mocked-utils.ts index 474786aebc..171cc1cc50 100644 --- a/desktop/packages/mullvad-vpn/test/e2e/mocked/mocked-utils.ts +++ b/desktop/packages/mullvad-vpn/test/e2e/mocked/mocked-utils.ts @@ -21,6 +21,8 @@ export const startMockedApp = async (): Promise<StartMockedAppResponse> => { console.log('Running tests without chromium sandbox'); args.unshift('--no-sandbox'); } + // NOTE: Keep in sync with index.ts + args.push('--gtk-version=3'); const startAppResult = await startApp({ args }); const mockIpcHandle = generateMockIpcHandle(startAppResult.app); diff --git a/desktop/packages/mullvad-vpn/test/e2e/mocked/select-location/helpers.ts b/desktop/packages/mullvad-vpn/test/e2e/mocked/select-location/helpers.ts index d04dac2f3b..ccfa8289f2 100644 --- a/desktop/packages/mullvad-vpn/test/e2e/mocked/select-location/helpers.ts +++ b/desktop/packages/mullvad-vpn/test/e2e/mocked/select-location/helpers.ts @@ -6,6 +6,7 @@ import { IRelayListCity, IRelayListCountry, IRelayListHostname, + ISettings, Ownership, } from '../../../../src/shared/daemon-rpc-types'; import { RoutePath } from '../../../../src/shared/routes'; @@ -33,6 +34,16 @@ export const createHelpers = (page: Page, routes: RoutesObjectModel, utils: Mock } }; + const locateRelaysByHostnames = (relayList: IRelayList, hostnames: string[]): LocatedRelay[] => { + return relayList.countries.flatMap((country) => + country.cities.flatMap((city) => + city.relays + .filter((relay) => hostnames.includes(relay.hostname)) + .map((relay) => ({ country, city, relay })), + ), + ); + }; + const locateRelaysByProvider = (relayList: IRelayList, provider?: string): LocatedRelay[] => relayList.countries.flatMap((country) => country.cities.flatMap((city) => @@ -106,9 +117,62 @@ export const createHelpers = (page: Page, routes: RoutesObjectModel, utils: Mock }); }; + const updateMockSettings = async ( + { + daita, + directOnly, + multihop, + }: { + multihop?: boolean; + daita?: boolean; + directOnly?: boolean; + }, + settings?: ISettings, + ) => { + if (!settings) { + settings = getDefaultSettings(); + } + if ('normal' in settings.relaySettings && settings.tunnelOptions.wireguard.daita) { + if (multihop !== undefined) + settings.relaySettings.normal.wireguardConstraints.useMultihop = multihop; + if (daita !== undefined) settings.tunnelOptions.wireguard.daita.enabled = daita; + if (directOnly !== undefined) settings.tunnelOptions.wireguard.daita.directOnly = directOnly; + } + + await utils.sendMockIpcResponse<ISettings>({ + channel: 'settings-', + response: settings, + }); + + return settings; + }; + + const updateEntryLocation = async (relay: LocatedRelay, settings?: ISettings) => { + if (!settings) { + settings = getDefaultSettings(); + } + if ('normal' in settings.relaySettings && settings.tunnelOptions.wireguard.daita) { + settings.relaySettings.normal.wireguardConstraints.entryLocation = { + only: { + hostname: relay.relay.hostname, + country: relay.country.code, + city: relay.city.code, + }, + }; + } + + await utils.sendMockIpcResponse<ISettings>({ + channel: 'settings-', + response: settings, + }); + + return settings; + }; + return { areAllCheckboxesChecked, expandLocatedRelays, + locateRelaysByHostnames, locateRelaysByProvider, locateRelaysByOwner, locateRelaysByObfuscation, @@ -116,6 +180,8 @@ export const createHelpers = (page: Page, routes: RoutesObjectModel, utils: Mock resetProviders, resetView, updateMockRelayFilter, + updateMockSettings, + updateEntryLocation, }; }; diff --git a/desktop/packages/mullvad-vpn/test/e2e/mocked/select-location/select-location.spec.ts b/desktop/packages/mullvad-vpn/test/e2e/mocked/select-location/select-location.spec.ts index ab4cd3736d..2c0a413522 100644 --- a/desktop/packages/mullvad-vpn/test/e2e/mocked/select-location/select-location.spec.ts +++ b/desktop/packages/mullvad-vpn/test/e2e/mocked/select-location/select-location.spec.ts @@ -3,43 +3,33 @@ import { Page } from 'playwright'; import { getDefaultSettings } from '../../../../src/main/default-settings'; import { colorTokens } from '../../../../src/renderer/lib/foundations'; -import { - IRelayListWithEndpointData, - ISettings, - IWireguardEndpointData, - ObfuscationType, - Ownership, -} from '../../../../src/shared/daemon-rpc-types'; +import { ISettings, ObfuscationType, Ownership } from '../../../../src/shared/daemon-rpc-types'; import { RoutePath } from '../../../../src/shared/routes'; +import { mockData } from '../../mock-data'; import { RoutesObjectModel } from '../../route-object-models'; import { MockedTestUtils, startMockedApp } from '../mocked-utils'; import { createHelpers, SelectLocationHelpers } from './helpers'; -import { mockData } from './mock-data'; -const wireguardEndpointData: IWireguardEndpointData = { - portRanges: [], - udp2tcpPorts: [], -}; +const { relayList } = mockData; let page: Page; let util: MockedTestUtils; let routes: RoutesObjectModel; let helpers: SelectLocationHelpers; -const { relayList } = mockData; test.describe('Select location', () => { test.beforeAll(async () => { ({ page, util } = await startMockedApp()); routes = new RoutesObjectModel(page, util); helpers = createHelpers(page, routes, util); + await util.waitForRoute(RoutePath.main); - await page.getByLabel('Select location').click(); - await util.waitForRoute(RoutePath.selectLocation); + }); - await util.sendMockIpcResponse<IRelayListWithEndpointData>({ - channel: 'relays-', - response: { relayList, wireguardEndpointData }, - }); + test.beforeEach(async () => { + if ((await util.currentRoute()) === RoutePath.main) { + await routes.main.gotoSelectLocation(); + } }); test.afterAll(async () => { @@ -48,14 +38,8 @@ test.describe('Select location', () => { test.describe('Multihop enabled', () => { test.beforeAll(async () => { - const settings = getDefaultSettings(); - if ('normal' in settings.relaySettings) { - settings.relaySettings.normal.wireguardConstraints.useMultihop = true; - } - - await util.sendMockIpcResponse<ISettings>({ - channel: 'settings-', - response: settings, + await helpers.updateMockSettings({ + multihop: true, }); }); @@ -81,16 +65,10 @@ test.describe('Select location', () => { }); test("App shouldn't show entry selection when daita is enabled without direct only", async () => { - const settings = getDefaultSettings(); - if ('normal' in settings.relaySettings && settings.tunnelOptions.wireguard.daita) { - settings.relaySettings.normal.wireguardConstraints.useMultihop = true; - settings.tunnelOptions.wireguard.daita.enabled = true; - settings.tunnelOptions.wireguard.daita.directOnly = false; - } - - await util.sendMockIpcResponse<ISettings>({ - channel: 'settings-', - response: settings, + await helpers.updateMockSettings({ + multihop: true, + daita: true, + directOnly: false, }); const entryButton = routes.selectLocation.getEntryButton(); @@ -101,16 +79,10 @@ test.describe('Select location', () => { }); test('App should show entry selection when daita is enabled with direct only', async () => { - const settings = getDefaultSettings(); - if ('normal' in settings.relaySettings && settings.tunnelOptions.wireguard.daita) { - settings.relaySettings.normal.wireguardConstraints.useMultihop = true; - settings.tunnelOptions.wireguard.daita.enabled = true; - settings.tunnelOptions.wireguard.daita.directOnly = true; - } - - await util.sendMockIpcResponse<ISettings>({ - channel: 'settings-', - response: settings, + await helpers.updateMockSettings({ + multihop: true, + daita: true, + directOnly: true, }); const entryButton = routes.selectLocation.getEntryButton(); @@ -119,6 +91,78 @@ test.describe('Select location', () => { const sweden = page.getByText('Sweden'); await expect(sweden).toBeVisible(); }); + + test('Should show only wireguard servers in entry list', async () => { + const entryButton = routes.selectLocation.getEntryButton(); + await entryButton.click(); + + const wireguardRelays = relayList.countries[0].cities[0].relays.filter( + (relay) => relay.endpointType === 'wireguard', + ); + const hostnames = wireguardRelays.map((relay) => relay.hostname); + const locatedRelays = helpers.locateRelaysByHostnames(relayList, hostnames); + + await helpers.expandLocatedRelays(locatedRelays); + + const buttons = routes.selectLocation.getRelaysMatching(hostnames); + await expect(buttons).toHaveCount(wireguardRelays.length); + }); + + test('Should show only wireguard servers in exit list', async () => { + const exitButton = routes.selectLocation.getExitButton(); + await exitButton.click(); + + const wireguardRelays = relayList.countries[0].cities[0].relays.filter( + (relay) => relay.endpointType === 'wireguard', + ); + const hostnames = wireguardRelays.map((relay) => relay.hostname); + const locatedRelays = helpers.locateRelaysByHostnames(relayList, hostnames); + + await helpers.expandLocatedRelays(locatedRelays); + + const buttons = routes.selectLocation.getRelaysMatching(hostnames); + await expect(buttons).toHaveCount(wireguardRelays.length); + }); + + test('Should disable entry server in exit list', async () => { + const settings = await helpers.updateMockSettings({ + multihop: true, + daita: true, + directOnly: true, + }); + + const entryButton = routes.selectLocation.getEntryButton(); + await entryButton.click(); + + // Get first wireguard relay + const [entryRelay, exitRelay] = relayList.countries[0].cities[0].relays.filter( + (relay) => relay.endpointType === 'wireguard', + ); + + if (!entryRelay) { + throw new Error('No wireguard relay found in mocked data'); + } + + const locatedEntryRelay = helpers.locateRelaysByHostnames(relayList, [entryRelay.hostname]); + + await helpers.expandLocatedRelays(locatedEntryRelay); + + await routes.selectLocation.getRelaysMatching([entryRelay.hostname]).first().click(); + + await helpers.updateEntryLocation(locatedEntryRelay[0], settings); + + await helpers.expandLocatedRelays(locatedEntryRelay); + const entryRelayButton = routes.selectLocation.getRelaysMatching([entryRelay.hostname]); + await expect(entryRelayButton).toBeDisabled(); + + const locatedExitRelay = helpers.locateRelaysByHostnames(relayList, [exitRelay.hostname]); + await helpers.expandLocatedRelays(locatedExitRelay); + + // Clicking exit relay should navigate to main route + const exitRelayButton = routes.selectLocation.getRelaysMatching([exitRelay.hostname]); + await exitRelayButton.click(); + await util.waitForRoute(RoutePath.main); + }); }); test.describe('Filter', () => { @@ -143,9 +187,18 @@ test.describe('Select location', () => { await routes.filter.expandProviders(); await routes.filter.checkAllProvidersCheckbox(); expect(await helpers.areAllCheckboxesChecked()).toBe(false); + const wireguardRelays = { + countries: relayList.countries.map(({ cities, ...country }) => ({ + ...country, + cities: cities.map(({ relays, ...city }) => ({ + ...city, + relays: relays.filter((relay) => relay.endpointType === 'wireguard'), + })), + })), + }; // Select one provider - const provider = relayList.countries[0].cities[0].relays[0].provider; + const provider = wireguardRelays.countries[0].cities[0].relays[0].provider; await routes.filter.checkProviderCheckbox(provider); await helpers.updateMockRelayFilter({ @@ -157,7 +210,7 @@ test.describe('Select location', () => { const providerFilterChip = routes.selectLocation.getFilterChip('Providers: 1'); await expect(providerFilterChip).toBeVisible(); - const locatedRelays = helpers.locateRelaysByProvider(relayList, provider); + const locatedRelays = helpers.locateRelaysByProvider(wireguardRelays, provider); const relays = locatedRelays.map((locatedRelay) => locatedRelay.relay); const relayNames = relays.map((relay) => relay.hostname); diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/daita-settings-route-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/daita-settings-route-object-model.ts new file mode 100644 index 0000000000..ba9b73a019 --- /dev/null +++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/daita-settings-route-object-model.ts @@ -0,0 +1,29 @@ +import { Page } from 'playwright'; + +import { TestUtils } from '../../utils'; +import { createSelectors } from './selectors'; + +export class DaitaSettingsRouteObjectModel { + readonly page: Page; + readonly utils: TestUtils; + readonly selectors: ReturnType<typeof createSelectors>; + + constructor(page: Page, utils: TestUtils) { + this.page = page; + this.utils = utils; + this.selectors = createSelectors(page); + } + + getEnableDaitaSwitch() { + return this.selectors.enableDaitaSwitch(); + } + + async setEnableDaitaSwitch(enabled: boolean) { + const enableDaitaSwitch = this.selectors.enableDaitaSwitch(); + const ariaChecked = await enableDaitaSwitch.getAttribute('aria-checked'); + + if ((enabled && ariaChecked === 'false') || (!enabled && ariaChecked === 'true')) { + await enableDaitaSwitch.click(); + } + } +} diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/index.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/index.ts new file mode 100644 index 0000000000..458dc4cafc --- /dev/null +++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/index.ts @@ -0,0 +1 @@ +export * from './daita-settings-route-object-model'; 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 new file mode 100644 index 0000000000..4c8f8c51bd --- /dev/null +++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/daita-settings/selectors.ts @@ -0,0 +1,5 @@ +import { Page } from 'playwright'; + +export const createSelectors = (page: Page) => ({ + enableDaitaSwitch: () => page.getByLabel('Enable'), +}); 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 6e1c2bb099..ea76183ac3 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 @@ -23,4 +23,9 @@ export class MainRouteObjectModel { await this.selectors.settingsButton().click(); await this.utils.waitForRoute(RoutePath.settings); } + + async gotoSelectLocation() { + await this.selectors.selectLocationButton().click(); + await this.utils.waitForRoute(RoutePath.selectLocation); + } } 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 a2f120a4ef..077a34db2d 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 @@ -2,4 +2,5 @@ import { Page } from 'playwright'; export const createSelectors = (page: Page) => ({ settingsButton: () => page.locator('button[aria-label="Settings"]'), + selectLocationButton: () => page.getByLabel('Select location'), }); diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/index.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/index.ts new file mode 100644 index 0000000000..e9de351d62 --- /dev/null +++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/index.ts @@ -0,0 +1 @@ +export * from './multihop-settings-route-object-model'; diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/multihop-settings-route-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/multihop-settings-route-object-model.ts new file mode 100644 index 0000000000..402ff09d71 --- /dev/null +++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/multihop-settings-route-object-model.ts @@ -0,0 +1,29 @@ +import { Page } from 'playwright'; + +import { TestUtils } from '../../utils'; +import { createSelectors } from './selectors'; + +export class MultihopSettingsRouteObjectModel { + readonly page: Page; + readonly utils: TestUtils; + readonly selectors: ReturnType<typeof createSelectors>; + + constructor(page: Page, util: TestUtils) { + this.page = page; + this.utils = util; + this.selectors = createSelectors(page); + } + + getEnableMultihopSwitch() { + return this.selectors.enableMultihopSwitch(); + } + + async setEnableMultihopSwitch(enabled: boolean) { + const enableMultihopSwitch = this.selectors.enableMultihopSwitch(); + const ariaChecked = await enableMultihopSwitch.getAttribute('aria-checked'); + + if ((enabled && ariaChecked === 'false') || (!enabled && ariaChecked === 'true')) { + await enableMultihopSwitch.click(); + } + } +} 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 new file mode 100644 index 0000000000..217ed920a2 --- /dev/null +++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/multihop-settings/selectors.ts @@ -0,0 +1,5 @@ +import { Page } from 'playwright'; + +export const createSelectors = (page: Page) => ({ + enableMultihopSwitch: () => page.getByRole('checkbox', { 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 dbb0e39803..d85c698984 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 @@ -1,9 +1,11 @@ import { Page } from 'playwright'; import { TestUtils } from '../utils'; +import { DaitaSettingsRouteObjectModel } from './daita-settings'; import { FilterRouteObjectModel } from './filter'; import { LaunchRouteObjectModel } from './launch'; import { MainRouteObjectModel } from './main'; +import { MultihopSettingsRouteObjectModel } from './multihop-settings'; import { SelectLanguageRouteObjectModel } from './select-language'; import { SelectLocationRouteObjectModel } from './select-location'; import { SettingsRouteObjectModel } from './settings/settings-route-object-model'; @@ -19,6 +21,8 @@ export class RoutesObjectModel { readonly filter: FilterRouteObjectModel; readonly selectLocation: SelectLocationRouteObjectModel; readonly vpnSettings: VpnSettingsRouteObjectModel; + readonly multihopSettings: MultihopSettingsRouteObjectModel; + readonly daitaSettings: DaitaSettingsRouteObjectModel; constructor(page: Page, utils: TestUtils) { this.selectLanguage = new SelectLanguageRouteObjectModel(page, utils); @@ -29,5 +33,7 @@ export class RoutesObjectModel { this.filter = new FilterRouteObjectModel(page, utils); this.selectLocation = new SelectLocationRouteObjectModel(page, utils); this.vpnSettings = new VpnSettingsRouteObjectModel(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/settings/selectors.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/settings/selectors.ts index ac227d0732..abf5527eda 100644 --- a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/settings/selectors.ts +++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/settings/selectors.ts @@ -1,6 +1,8 @@ import { Page } from 'playwright'; export const createSelectors = (page: Page) => ({ + multihopSettingsButton: () => page.getByRole('button', { name: 'Multihop' }), + daitaSettingsButton: () => page.getByRole('button', { name: 'Daita' }), userInterfaceButton: () => page.getByRole('button', { name: 'User interface settings' }), vpnSettingsButton: () => page.getByRole('button', { name: 'VPN settings' }), }); diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/settings/settings-route-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/settings/settings-route-object-model.ts index e85af07bd2..59b8609260 100644 --- a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/settings/settings-route-object-model.ts +++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/settings/settings-route-object-model.ts @@ -24,4 +24,14 @@ export class SettingsRouteObjectModel { await this.selectors.vpnSettingsButton().click(); await this.utils.waitForRoute(RoutePath.vpnSettings); } + + async gotoMultihopSettings() { + await this.selectors.multihopSettingsButton().click(); + await this.utils.waitForRoute(RoutePath.multihopSettings); + } + + async gotoDaitaSettings() { + await this.selectors.daitaSettingsButton().click(); + await this.utils.waitForRoute(RoutePath.daitaSettings); + } } diff --git a/desktop/packages/mullvad-vpn/test/e2e/setup/main.ts b/desktop/packages/mullvad-vpn/test/e2e/setup/main.ts index d23d85cfa6..de46f5e578 100644 --- a/desktop/packages/mullvad-vpn/test/e2e/setup/main.ts +++ b/desktop/packages/mullvad-vpn/test/e2e/setup/main.ts @@ -9,13 +9,13 @@ import { IAccountData, IAppVersionInfo, ILocation, - IRelayList, IWireguardEndpointData, } from '../../../src/shared/daemon-rpc-types'; import { messages, relayLocations } from '../../../src/shared/gettext'; import { IGuiSettingsState } from '../../../src/shared/gui-settings-state'; import { ITranslations, MacOsScrollbarVisibility } from '../../../src/shared/ipc-schema'; import { ICurrentAppVersionInfo } from '../../../src/shared/ipc-types'; +import { mockData } from '../mock-data'; const DEBUG = false; @@ -74,36 +74,6 @@ class ApplicationMain { mullvadExitIp: false, }; - private relayList: IRelayList = { - countries: [ - { - name: 'Sweden', - code: 'se', - cities: [ - { - name: 'Gothenburg', - code: 'got', - latitude: 58, - longitude: 12, - relays: [ - { - hostname: 'se-got-wg-101', - provider: 'mullvad', - ipv4AddrIn: '127.0.0.1', - includeInCountry: true, - active: true, - weight: 0, - owned: true, - endpointType: 'wireguard', - daita: false, - }, - ], - }, - ], - }, - ], - }; - private wireguardEndpointData: IWireguardEndpointData = { portRanges: [], udp2tcpPorts: [], @@ -159,9 +129,8 @@ class ApplicationMain { settings: this.settings, isPerformingPostUpgrade: false, deviceState: this.deviceState, - relayListPair: { - relays: this.relayList, - bridges: this.relayList, + relayList: { + relayList: mockData.relayList, wireguardEndpointData: this.wireguardEndpointData, }, currentVersion: this.currentVersion, diff --git a/test/test-manager/src/tests/ui.rs b/test/test-manager/src/tests/ui.rs index 1260bfeadc..7790de9306 100644 --- a/test/test-manager/src/tests/ui.rs +++ b/test/test-manager/src/tests/ui.rs @@ -319,3 +319,27 @@ pub async fn test_settings_ui( assert!(ui_result.success()); Ok(()) } + +/// Test DAITA UI +#[test_function] +pub async fn test_daita_ui( + _: TestContext, + rpc: ServiceClient, + _: MullvadProxyClient, +) -> Result<(), Error> { + let ui_result = run_test(&rpc, &["daita-settings.spec"]).await?; + assert!(ui_result.success()); + Ok(()) +} + +/// Test multihop UI +#[test_function] +pub async fn test_multihop_ui( + _: TestContext, + rpc: ServiceClient, + _: MullvadProxyClient, +) -> Result<(), Error> { + let ui_result = run_test(&rpc, &["multihop-settings.spec"]).await?; + assert!(ui_result.success()); + Ok(()) +} |
