From 84c1ba2209b452c991b1231afb4b3ca5e6b399a3 Mon Sep 17 00:00:00 2001 From: Oskar Date: Mon, 9 Sep 2024 21:50:08 +0200 Subject: [PATCH] Add settings test --- .../state-dependent/settings.spec.ts | 85 +++++++++++++++++++ gui/test/e2e/utils.ts | 11 +++ test/test-manager/src/tests/ui.rs | 8 ++ 3 files changed, 104 insertions(+) create mode 100644 gui/test/e2e/installed/state-dependent/settings.spec.ts diff --git a/gui/test/e2e/installed/state-dependent/settings.spec.ts b/gui/test/e2e/installed/state-dependent/settings.spec.ts new file mode 100644 index 000000000000..2b5643a310ca --- /dev/null +++ b/gui/test/e2e/installed/state-dependent/settings.spec.ts @@ -0,0 +1,85 @@ +import path from 'path'; +import { execSync } from 'child_process'; +import { expect, Page, test } from '@playwright/test'; +import { startInstalledApp } from '../installed-utils'; +import { fileExists, TestUtils } from '../../utils'; + +if (process.env.HOME === undefined) { + throw new Error('$HOME not set'); +} + +const AUTOSTART_PATH = path.join(process.env.HOME, '.config', 'autostart', 'mullvad-vpn.desktop'); + +let page: Page; +let util: TestUtils; + +test.beforeAll(async () => { + ({ page, util } = await startInstalledApp()); +}); + +test.afterAll(async () => { + await page.close(); +}); + +test.describe('VPN Settings', () => { + test('Auto-connect setting', async () => { + // Navigate to the VPN settings view + await util.waitForNavigation(async () => await page.click('button[aria-label="Settings"]')); + await util.waitForNavigation(async () => await page.click('text=VPN settings')); + + // Find the auto-connect toggle + const autoConnectToggle = page.getByText('Auto-connect').locator('..').getByRole('checkbox'); + + // Check initial state + const initialCliState = execSync('mullvad auto-connect get').toString().trim(); + expect(initialCliState).toMatch(/off$/); + await expect(autoConnectToggle).toHaveAttribute('aria-checked', 'false') + + // Toggle auto-connect + await autoConnectToggle.click(); + + // Verify the setting was applied correctly + await expect(autoConnectToggle).toHaveAttribute('aria-checked', 'true') + const newCliState = execSync('mullvad auto-connect get').toString().trim(); + expect(newCliState).toMatch(/off$/); + }); + + test('Launch on startup setting', async () => { + // Find the auto-connect toggle + const launchOnStartupToggle = + page.getByText('Launch app on start-up').locator('..').getByRole('checkbox'); + + // Check initial state + const initialCliState = execSync('mullvad auto-connect get').toString().trim(); + expect(initialCliState).toMatch(/off$/); + await expect(launchOnStartupToggle).toHaveAttribute('aria-checked', 'false') + expect(fileExists(AUTOSTART_PATH)).toBeFalsy(); + + // Toggle auto-connect + await launchOnStartupToggle.click(); + + // Verify the setting was applied correctly + await expect(launchOnStartupToggle).toHaveAttribute('aria-checked', 'true') + expect(fileExists(AUTOSTART_PATH)).toBeTruthy(); + const newCliState = execSync('mullvad auto-connect get').toString().trim(); + expect(newCliState).toMatch(/on$/); + }); + + test('LAN settings', async () => { + // Find the LAN toggle + const lanToggle = page.getByText('Local network sharing').locator('..').getByRole('checkbox'); + + // Check initial state + const initialCliState = execSync('mullvad lan get').toString().trim(); + expect(initialCliState).toMatch(/block$/); + await expect(lanToggle).toHaveAttribute('aria-checked', 'false') + + // Toggle LAN setting + await lanToggle.click(); + + // Verify the setting was applied correctly + await expect(lanToggle).toHaveAttribute('aria-checked', 'true') + const newState = execSync('mullvad lan get').toString().trim(); + expect(newState).toMatch(/allow$/); + }); +}); diff --git a/gui/test/e2e/utils.ts b/gui/test/e2e/utils.ts index 082ccfcf3f28..bb51885a86ec 100644 --- a/gui/test/e2e/utils.ts +++ b/gui/test/e2e/utils.ts @@ -1,3 +1,4 @@ +import fs from 'fs'; import { Locator, Page, _electron as electron, ElectronApplication } from 'playwright'; export interface StartAppResponse { @@ -127,3 +128,13 @@ export function anyOf(...values: string[]): RegExp { export function escapeRegExp(regexp: string): string { return regexp.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string } + + +export function fileExists(filePath: string): boolean { + try { + fs.accessSync(filePath); + return true; + } catch (e) { + return false; + } +} diff --git a/test/test-manager/src/tests/ui.rs b/test/test-manager/src/tests/ui.rs index e9008a5baf5e..4068d3b9a58d 100644 --- a/test/test-manager/src/tests/ui.rs +++ b/test/test-manager/src/tests/ui.rs @@ -276,3 +276,11 @@ pub async fn test_import_settings_ui(_: TestContext, rpc: ServiceClient) -> Resu assert!(ui_result.success()); Ok(()) } + +/// Test settings in the GUI +#[test_function] +pub async fn test_settings_ui(_: TestContext, rpc: ServiceClient) -> Result<(), Error> { + let ui_result = run_test(&rpc, &["settings.spec"]).await?; + assert!(ui_result.success()); + Ok(()) +}