verstak-desktop/docs/GUI_TESTING.md

4.7 KiB

GUI Testing

Overview

Verstak Desktop uses Playwright for frontend E2E tests that run in a real Chromium browser with mocked Wails bindings. This tests the Svelte component logic, user interactions, and UI state transitions — without needing the actual Wails desktop shell.

What is tested

Frontend E2E (Playwright)

Located in frontend/e2e/, run via npm run test:e2e.

These tests:

  • Launch a Vite dev server with mock Wails bindings
  • Open the app in a real Chromium browser via Playwright
  • Simulate user clicks, wait for UI transitions, assert DOM state
  • Collect console errors and page errors on failure
  • Capture screenshots on failure

Test suites

File Suite Tests Status
plugin-manager-disable-enable.spec.js A: Disable/Enable refresh 4 3 pass, 1 fail*
sidebar-opens-view.spec.js B: Sidebar → view routing 3 3 pass
reload-updates-state.spec.js C: Reload updates UI 3 2 pass, 1 fail*

* Failing tests document known bugs (see below).

Known bugs detected by tests

Bug M5-1: Sidebar does not update when plugin state changes

Symptom: After disabling a plugin in Plugin Manager, the sidebar item for that plugin remains visible. After re-enabling, it stays visible (doesn't disappear then reappear — it was never gone).

Root cause: Sidebar.svelte loads plugin/contribution data once in onMount and stores it in local sidebarItems. When PluginManager disables/enables a plugin and calls ReloadPlugins, the PluginManager component re-fetches data, but Sidebar does not react to the change — it still holds the stale list.

Affected tests:

  • A: Disable plugin: button changes to Enable, sidebar item disappears
  • A: Disable → Enable full flow in sequence
  • C: Reload after mock state change reflects new plugin status

Fix needed: Sidebar must either:

  1. Re-fetch contributions when it receives a custom event (e.g. verstak:plugins-reloaded), or
  2. Read plugin state reactively from a shared store that both PluginManager and Sidebar subscribe to.

What is NOT tested

Real desktop GUI (WebKitGTK + Wails native shell)

The Playwright tests run the frontend in a standard Chromium browser with mocked Wails bindings. They do not test:

  • Actual WebKitGTK rendering (Wails uses WebKitGTK, not Chromium)
  • Native window management (minimize, maximize, resize)
  • Native file dialogs (SelectDirectory, SelectVaultForOpen)
  • Clipboard integration
  • System tray / menu bar
  • Plugin frontend bundle loading from real filesystem
  • Wails event system (window.runtime.EventsOn/Emit)

For real Wails smoke tests, a separate layer is needed using:

  • AT-SPI2 (Linux accessibility tree inspection)
  • xdotool / ydotool (input simulation)
  • scrot / import (screenshot capture)

Running tests

cd frontend

# Run all E2E tests (headless)
npm run test:e2e

# Run with Playwright UI (interactive)
npm run test:e2e:ui

# Run in headed browser (visible)
npm run test:e2e:headed

Test infrastructure

Mock bridge (src/lib/test/wails-mock.js)

Replaces window['go']['api']['App'] with in-memory mock implementations of all Wails backend methods. Provides:

  • Mutable plugin state (enable/disable/status)
  • Mutable vault state
  • Mutable contributions (views, commands, sidebar items, settings panels)
  • Test helpers via window.__wailsMock:
    • reset() — reset all state to defaults
    • setPluginStatus(id, status, enabled) — change plugin state
    • getPluginState(id) — read current state
    • setVaultStatus(status) — change vault state

Test harness (index.html)

The same index.html is used for both production and test. It detects whether the Wails runtime (window['go']) is present. If not (i.e. running in a plain browser), it loads the mock bridge before the Svelte app.

Playwright config (playwright.config.js)

  • Dev server: vite --mode test --port 5174
  • Browser: Chromium headless
  • Timeouts: 30s test, 10s expect
  • Workers: 1 (sequential)
  • Screenshots: on failure
  • Traces: on first retry
  • Results: e2e-results/test-results.json

Adding new tests

  1. Create e2e/your-test.spec.js
  2. Import helpers from ./helpers.js
  3. Use test.beforeEach to reset mock state and navigate to /
  4. Use test.afterEach to assert no console errors
  5. Write scenarios as user actions + assertions
  6. Run with npm run test:e2e

Selector conventions

  • Plugin cards: .plugin-card filtered by text
  • Buttons: .btn-disable, .btn-enable, .btn-settings, .reload-btn
  • Sidebar items: .sidebar .plugin-item
  • View container: .view-container
  • View header: .view-header h2
  • Status badges: .status-badge
  • Toast: .toast