summaryrefslogtreecommitdiffhomepage
path: root/desktop
diff options
context:
space:
mode:
authorOskar <oskar@mullvad.net>2025-09-16 08:09:36 +0200
committerOskar <oskar@mullvad.net>2025-10-01 13:19:43 +0200
commit5e208df04089b553dc09fb64544e7e3da3ee6b17 (patch)
tree7533d7a840875878a8fd9ffde2e6b8223fd95874 /desktop
parent73f89bce2f4120bbbd52218722f78583a6cb3925 (diff)
downloadmullvadvpn-5e208df04089b553dc09fb64544e7e3da3ee6b17.tar.xz
mullvadvpn-5e208df04089b553dc09fb64544e7e3da3ee6b17.zip
Handle too many devices view in getNavigationBase
Diffstat (limited to 'desktop')
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/app.tsx9
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/StateTriggeredNavigation.tsx4
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/functions/navigation-base.ts11
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/mocked/too-many-devices.spec.ts68
-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/too-many-devices/index.ts2
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/selectors.ts5
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/too-many-devices-route-object-model.ts24
8 files changed, 119 insertions, 7 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/app.tsx b/desktop/packages/mullvad-vpn/src/renderer/app.tsx
index c6384f5e35..85e6d80687 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/app.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/app.tsx
@@ -54,7 +54,7 @@ import { ModalContainer } from './components/Modal';
import { AppContext } from './context';
import { Theme } from './lib/components';
import { getNavigationBase } from './lib/functions/navigation-base';
-import History, { TransitionType } from './lib/history';
+import History from './lib/history';
import { loadTranslations } from './lib/load-translations';
import IpcOutput from './lib/logging';
import accountActions from './redux/account/actions';
@@ -499,8 +499,6 @@ export default class AppRenderer {
actions.account.loginTooManyDevices();
this.loginState = 'too many devices';
-
- this.history.reset(RoutePath.tooManyDevices, { transition: TransitionType.push });
} catch {
log.error('Failed to fetch device list');
actions.account.loginFailed('list-devices');
@@ -517,9 +515,8 @@ export default class AppRenderer {
this.loginState = 'none';
};
- public logout = async (transition = TransitionType.dismiss) => {
+ public logout = async () => {
try {
- this.history.reset(RoutePath.login, { transition });
await IpcRendererEventChannel.account.logout();
} catch (e) {
const error = e as Error;
@@ -528,7 +525,7 @@ export default class AppRenderer {
};
public leaveRevokedDevice = async () => {
- await this.logout(TransitionType.pop);
+ await this.logout();
await this.disconnectTunnel();
};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/StateTriggeredNavigation.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/StateTriggeredNavigation.tsx
index 0187bda865..3a275e2f61 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/StateTriggeredNavigation.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/StateTriggeredNavigation.tsx
@@ -74,6 +74,7 @@ function getNavigationTransition(currentPath: RoutePath, nextPath: RoutePath) {
[RoutePath.launch]: TransitionType.push,
[RoutePath.main]: TransitionType.pop,
[RoutePath.deviceRevoked]: TransitionType.pop,
+ [RoutePath.tooManyDevices]: TransitionType.pop,
'*': TransitionType.dismiss,
},
[RoutePath.main]: {
@@ -96,6 +97,9 @@ function getNavigationTransition(currentPath: RoutePath, nextPath: RoutePath) {
[RoutePath.deviceRevoked]: {
'*': TransitionType.pop,
},
+ [RoutePath.tooManyDevices]: {
+ [RoutePath.login]: TransitionType.push,
+ },
};
return navigationTransitions[nextPath]?.[currentPath] ?? navigationTransitions[nextPath]?.['*'];
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/functions/navigation-base.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/functions/navigation-base.ts
index 96f92d483e..7802ace1e9 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/functions/navigation-base.ts
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/functions/navigation-base.ts
@@ -5,7 +5,16 @@ export function getNavigationBase(connectedToDaemon: boolean, loginState: LoginS
if (connectedToDaemon) {
if (loginState.type === 'none' && loginState.deviceRevoked) {
return RoutePath.deviceRevoked;
- } else if (loginState.type === 'none' || loginState.type === 'logging in') {
+ } else if (
+ loginState.type === 'too many devices' ||
+ (loginState.type === 'failed' && loginState.error === 'too-many-devices')
+ ) {
+ return RoutePath.tooManyDevices;
+ } else if (
+ loginState.type === 'none' ||
+ loginState.type === 'logging in' ||
+ loginState.type === 'failed'
+ ) {
return RoutePath.login;
} else if (loginState.type === 'ok' && loginState.expiredState === 'expired') {
return RoutePath.expired;
diff --git a/desktop/packages/mullvad-vpn/test/e2e/mocked/too-many-devices.spec.ts b/desktop/packages/mullvad-vpn/test/e2e/mocked/too-many-devices.spec.ts
new file mode 100644
index 0000000000..76e3fddee3
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/mocked/too-many-devices.spec.ts
@@ -0,0 +1,68 @@
+import { test } from '@playwright/test';
+import { Page } from 'playwright';
+
+import { RoutesObjectModel } from '../route-object-models';
+import { MockedTestUtils, startMockedApp } from './mocked-utils';
+
+let page: Page;
+let util: MockedTestUtils;
+let routes: RoutesObjectModel;
+
+test.describe('Too many devices', () => {
+ test.beforeAll(async () => {
+ ({ page, util } = await startMockedApp());
+ routes = new RoutesObjectModel(page, util);
+ await routes.main.waitForRoute();
+
+ await util.ipc.account.device.notify({
+ type: 'logged out',
+ deviceState: { type: 'logged out' },
+ });
+
+ await routes.login.waitForRoute();
+ });
+
+ test.afterAll(async () => {
+ await page.close();
+ });
+
+ test.describe('Navigation', () => {
+ test('App should navigate to too many devices view', async () => {
+ await util.ipc.account.login.handle({ type: 'error', error: 'too-many-devices' });
+ await util.ipc.account.listDevices.handle([
+ {
+ id: '1',
+ name: 'Device 1',
+ created: new Date(),
+ },
+ {
+ id: '2',
+ name: 'Device 2',
+ created: new Date(),
+ },
+ ]);
+
+ await routes.login.fillAccountNumber('1234123412341234');
+ await routes.login.loginByPressingEnter();
+
+ await routes.tooManyDevices.waitForRoute();
+ });
+
+ test('App should navigate to main via login', async () => {
+ await util.ipc.account.login.handle(undefined);
+
+ await routes.tooManyDevices.waitForRoute();
+
+ await routes.tooManyDevices.continue();
+ await routes.login.waitForRoute();
+
+ await util.ipc.account.device.notify({
+ type: 'logged in',
+ deviceState: { type: 'logged in', accountAndDevice: { accountNumber: '1234123412341234' } },
+ });
+ await util.ipc.account[''].notify({ expiry: new Date(Date.now() + 60 * 1000).toISOString() });
+
+ await routes.main.waitForRoute();
+ });
+ });
+});
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 34951bad8a..77ec121306 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
@@ -17,6 +17,7 @@ import { SetupFinishedRouteObjectModel } from './setup-finished';
import { ShadowsocksSettingsRouteObjectModel } from './shadowsocks-settings';
import { SplitTunnelingSettingsRouteObjectModel } from './split-tunneling-settings';
import { TimeAddedRouteObjectModel } from './time-added';
+import { TooManyDevicesRouteObjectModel } from './too-many-devices';
import { UdpOverTcpSettingsRouteObjectModel } from './udp-over-tcp-settings';
import { UserInterfaceSettingsRouteObjectModel } from './user-interface-settings';
import { VoucherSuccessRouteObjectModel } from './voucher-success';
@@ -33,6 +34,7 @@ export class RoutesObjectModel {
readonly timeAdded: TimeAddedRouteObjectModel;
readonly setupFinished: SetupFinishedRouteObjectModel;
readonly deviceRevoked: DeviceRevokedRouteObjectModel;
+ readonly tooManyDevices: TooManyDevicesRouteObjectModel;
readonly settings: SettingsRouteObjectModel;
readonly userInterfaceSettings: UserInterfaceSettingsRouteObjectModel;
readonly selectLanguage: SelectLanguageRouteObjectModel;
@@ -57,6 +59,7 @@ export class RoutesObjectModel {
this.timeAdded = new TimeAddedRouteObjectModel(page, utils);
this.setupFinished = new SetupFinishedRouteObjectModel(page, utils);
this.deviceRevoked = new DeviceRevokedRouteObjectModel(utils);
+ this.tooManyDevices = new TooManyDevicesRouteObjectModel(page, utils);
this.settings = new SettingsRouteObjectModel(page, utils);
this.userInterfaceSettings = new UserInterfaceSettingsRouteObjectModel(page, utils);
this.filter = new FilterRouteObjectModel(page, utils);
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/index.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/index.ts
new file mode 100644
index 0000000000..47ab585d08
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/index.ts
@@ -0,0 +1,2 @@
+export * from './too-many-devices-route-object-model';
+export * from './selectors';
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/selectors.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/selectors.ts
new file mode 100644
index 0000000000..12474f3ad9
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/selectors.ts
@@ -0,0 +1,5 @@
+import { Page } from 'playwright';
+
+export const createSelectors = (page: Page) => ({
+ continueButton: () => page.getByRole('button', { name: 'Continue' }),
+});
diff --git a/desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/too-many-devices-route-object-model.ts b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/too-many-devices-route-object-model.ts
new file mode 100644
index 0000000000..fe0f8c10ed
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/test/e2e/route-object-models/too-many-devices/too-many-devices-route-object-model.ts
@@ -0,0 +1,24 @@
+import { Page } from 'playwright';
+
+import { RoutePath } from '../../../../src/shared/routes';
+import { TestUtils } from '../../utils';
+import { createSelectors } from './selectors';
+
+export class TooManyDevicesRouteObjectModel {
+ readonly selectors: ReturnType<typeof createSelectors>;
+
+ constructor(
+ private readonly page: Page,
+ private readonly utils: TestUtils,
+ ) {
+ this.selectors = createSelectors(this.page);
+ }
+
+ async waitForRoute() {
+ await this.utils.expectRoute(RoutePath.tooManyDevices);
+ }
+
+ async continue() {
+ await this.selectors.continueButton().click();
+ }
+}