diff options
| author | Oliver <oliver@mohlin.dev> | 2025-09-13 14:40:18 +0200 |
|---|---|---|
| committer | Tobias Järvelöv <tobias.jarvelov@mullvad.net> | 2025-10-10 13:36:20 +0200 |
| commit | c6aedccfe52ab97b3030003639a9bf93a435b7f3 (patch) | |
| tree | 1dc34879daf89ebed231b6167a2a0246ce0b3254 | |
| parent | 2674ba6138cc45abcff092a7b136be75372702d9 (diff) | |
| download | mullvadvpn-c6aedccfe52ab97b3030003639a9bf93a435b7f3.tar.xz mullvadvpn-c6aedccfe52ab97b3030003639a9bf93a435b7f3.zip | |
Add tests for manage devices view
4 files changed, 110 insertions, 0 deletions
diff --git a/desktop/packages/mullvad-vpn/test/e2e/mocked/manage-devices/helpers.ts b/desktop/packages/mullvad-vpn/test/e2e/mocked/manage-devices/helpers.ts new file mode 100644 index 0000000000..f806732113 --- /dev/null +++ b/desktop/packages/mullvad-vpn/test/e2e/mocked/manage-devices/helpers.ts @@ -0,0 +1,29 @@ +import { IDevice } from '../../../../src/shared/daemon-rpc-types'; +import { MockedTestUtils } from '../mocked-utils'; + +export const createHelpers = (utils: MockedTestUtils) => { + const setCurrentDevice = async (currentDevice: IDevice) => { + await utils.ipc.account.device.notify({ + type: 'logged in', + deviceState: { + type: 'logged in', + accountAndDevice: { + accountNumber: '0000-0000-0000-0000', + device: { + id: currentDevice.id, + name: currentDevice.name, + created: currentDevice.created, + }, + }, + }, + }); + }; + + const setDevices = async (devices: IDevice[]) => { + await utils.ipc.account.devices.notify(devices); + }; + + return { setCurrentDevice, setDevices }; +}; + +export type MAnageDevicesHelpers = ReturnType<typeof createHelpers>; diff --git a/desktop/packages/mullvad-vpn/test/e2e/mocked/manage-devices/manage-devices.spec.ts b/desktop/packages/mullvad-vpn/test/e2e/mocked/manage-devices/manage-devices.spec.ts new file mode 100644 index 0000000000..04cc376451 --- /dev/null +++ b/desktop/packages/mullvad-vpn/test/e2e/mocked/manage-devices/manage-devices.spec.ts @@ -0,0 +1,75 @@ +import { expect, test } from '@playwright/test'; +import { Page } from 'playwright'; + +import { IDevice } from '../../../../src/shared/daemon-rpc-types'; +import { RoutesObjectModel } from '../../route-object-models'; +import { MockedTestUtils, startMockedApp } from '../mocked-utils'; +import { createHelpers, MAnageDevicesHelpers as ManageDevicesHelpers } from './helpers'; + +let page: Page; +let util: MockedTestUtils; +let routes: RoutesObjectModel; +let helpers: ManageDevicesHelpers; + +export const mockDevices: IDevice[] = [ + { id: '1', name: 'Sneaky dog', created: new Date('2024-12-05') }, + { id: '2', name: 'Wise cat', created: new Date('2025-01-14') }, + { id: '3', name: 'Cool panda', created: new Date('2025-03-22') }, + { id: '4', name: 'Strong fish', created: new Date('2025-06-01') }, + { id: '5', name: 'Magic elk', created: new Date('2025-09-10') }, +]; + +let devices = mockDevices; + +test.describe('Manage devices view', () => { + const currentDevice = mockDevices[0]; + + test.beforeAll(async () => { + ({ page, util } = await startMockedApp()); + routes = new RoutesObjectModel(page, util); + helpers = createHelpers(util); + + await routes.main.waitForRoute(); + + await util.ipc.account.listDevices.handle(devices); + await helpers.setCurrentDevice(currentDevice); + + await routes.main.gotoAccount(); + await routes.account.gotoManageDevices(); + }); + + test.beforeEach(() => { + devices = mockDevices; + }); + + test.afterAll(async () => { + await page.close(); + }); + + test('Should display all account devices', async () => { + const deviceListItems = routes.manageDevices.selectors.deviceListItems(); + for (const device of devices) { + await expect(deviceListItems.filter({ hasText: device.name })).toBeVisible(); + } + }); + + test('Should not be able to delete current device', async () => { + const deviceListItems = routes.manageDevices.selectors.removeDeviceButton(currentDevice.name); + await expect(deviceListItems).toHaveCount(0); + }); + + test('Should be able to delete non-current devices', async () => { + const nonCurrentDevices = devices.filter((device) => device.id !== currentDevice.id); + for (const device of nonCurrentDevices) { + const deviceItem = routes.manageDevices.selectors.deviceListItem(device.name); + const removeButton = routes.manageDevices.selectors.removeDeviceButton(device.name); + await removeButton.click(); + + const confirmButton = routes.manageDevices.selectors.confirmRemoveDeviceButton(); + await Promise.all([util.ipc.account.removeDevice.expect(), confirmButton.click()]); + devices = devices.filter((d) => d.name !== device.name); + await helpers.setDevices(devices); + await expect(deviceItem).toHaveCount(0); + } + }); +}); 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 2add02f601..e58895cf91 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 @@ -29,6 +29,11 @@ export class MainRouteObjectModel { await this.utils.expectRoute(RoutePath.selectLocation); } + async gotoAccount() { + await this.selectors.accountButton().click(); + await this.utils.expectRoute(RoutePath.account); + } + async expandConnectionPanel() { await this.selectors.connectionPanelChevronButton().click(); } 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 95f300c460..dd78ae4ae2 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,6 +2,7 @@ import { Page } from 'playwright'; export const createSelectors = (page: Page) => ({ settingsButton: () => page.locator('button[aria-label="Settings"]'), + accountButton: () => page.locator('button[aria-label="Account settings"]'), selectLocationButton: () => page.getByLabel('Select location'), connectionPanelChevronButton: () => page.getByTestId('connection-panel-chevron'), inIpLabel: () => page.getByTestId('in-ip'), |
