Skip to content

Browser-only test mode for Tauri and Electron services #260

@goosewobbler

Description

@goosewobbler

Summary

Run Tauri and Electron frontend tests in plain Chrome against a dev server, with native IPC intercepted at the JS boundary. No binary, no native driver, no display server — fast feedback loop for UI-focused tests on CI.

Today every test requires a built native binary, a platform-specific driver, and a real OS window. Many tests only exercise the web UI and mock the backend anyway. Browser-only mode collapses the inner/outer mock boundary into a single window context and eliminates the entire driver/binary chain.

Phase 1 — Tauri

@wdio/native-spy

  • TauriAdapter.buildBrowserIpcInjectionScript() — one-shot IIFE that sets up window.__wdio_spy__, window.__wdio_mocks__, and patches window.__TAURI_INTERNALS__.invoke to route through __wdio_mocks__[cmd] or throw 'unmocked Tauri command in browser mode: <cmd>'
  • IpcInterceptor interface gains buildBrowserIpcInjectionScript()

@wdio/tauri-service — types

  • TauriServiceOptions.mode?: 'native' | 'browser'
  • TauriServiceOptions.devServerUrl?: string (required when mode === 'browser')

Launcher — short-circuit driver/binary setup

  • onPrepare early-returns in browser mode: sets browserName: 'chrome', removes tauri:options, skips ensureTauriDriver, ensureMsEdgeDriver, embedded server spawn, version detection
  • onWorkerStart / onWorkerEnd skip per-worker driver lifecycle

Worker — inject IPC layer

  • before() branches on mode === 'browser': navigates to devServerUrl, executes injection script, exposes browser.tauri with the single-context mock factory
  • browser.tauri.execute() throws a clear error; switchWindow/listWindows throw
  • browser.url() is patched post-init to re-inject the IPC script after every navigation (page reload wipes window state)

Single-context mock factory

  • createMock in browser mode skips the outer/inner dual-mock path; all call data lives in window.__wdio_mocks__[cmd] and is read back via parseCallData over a browser.execute round-trip
  • mock.update() remains callable as a no-op for users migrating from native mode

Phase 2 — Electron (follow-up PR)

Mirrors Phase 1 with:

  • ElectronAdapter.buildBrowserIpcInjectionScript() wraps window.electron.ipcRenderer.invoke (and .send/.sendSync) — the contextBridge-exposed surface
  • ElectronServiceOptions.mode / devServerUrl additions
  • Launcher skips resolveAppPaths, getAppBuildInfo, Chromium version detection, --inspect allocation, AppArmor patches
  • Worker skips initCdpBridge; browser.electron.execute() throws

contextBridge-only support (no nodeIntegration: true). Documented with a link to Electron's security guidance.

Design decisions

Decision Rationale
Dev server is user-managed Matches tauri-playwright; simplest contract
execute() throws No silent semantic change between modes
Tauri ships first Proven end-to-end slice; Electron follows the same template
IPC re-injection on browser.url() Page reload wipes window state; patching url keeps the infrastructure alive
Multiremote: patch each instance Root browser url() and per-instance url() both need re-injection

Out of scope (v1)

  • Auto-start of dev server (devServerCommand option deferred)
  • Multi-window (switchWindow throws with a clear message)
  • Tauri events (listen/emit)
  • Non-contextBridge Electron preloads

Acceptance criteria

Functional

  • Browser-mode E2E suites pass on Linux CI with no display server
  • All existing native-mode unit, integration, package, and E2E suites pass unchanged
  • No tauri-driver, msedgedriver, or Electron app process appears in ps
  • Misconfiguration surfaces a clear, actionable error (missing devServerUrl, dev server unreachable, mode: 'browser' + non-chrome browserName)

Coverage — 80%+ on all touched packages; each test tier owns only the bugs it can catch:

  • Unit: logic, error paths, every branch of mode === 'browser'
  • Integration: launcher→worker handshake, capability flow, no-driver assertion
  • Package: ESM/CJS import surface via wdio.browser.conf.ts added to existing fixtures
  • E2E: happy-path real-Chrome + ps-based process-presence regression

Performance

  • Browser-mode E2E suite (~5 specs) completes in under 30 seconds on CI Linux (warm)
  • Per-test browser-mode runtime is at least 5× faster than equivalent native-mode on the same hardware

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:mockingIssues affecting API mockingarea:performanceIssues affecting performancescope:electronElectron service and CDP bridgescope:sharedShared utilities and infrastructurescope:tauriTauri service and pluginstype:enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions