## Summary - Adds shared `waitForTestId` and `clickTestId` E2E helpers for stable DOM hooks. - Adds missing `cron-jobs-panel` and `cron-refresh` hooks to the Cron Jobs settings panel. - Migrates the reference cron E2E flow away from Tailwind class/DOM walking to cron row/action test IDs. - Documents the E2E `data-testid` naming taxonomy in the E2E guide. ## Problem - #1861 calls out `cron-jobs-flow.spec.ts` as the concrete example of brittle selectors: it found `morning_briefing` via Tailwind class strings and `closest('div.p-4')`. - That breaks on harmless class/layout refactors and makes the reference spec a weak template for future E2E work. ## Solution - Use existing `CoreJobList` cron row/action hooks directly from the spec. - Add the missing panel/refresh hooks so the whole cron flow can avoid text/button discovery for row actions. - Centralize test ID waiting/clicking in `element-helpers.ts` instead of keeping local DOM snippets in specs. ## Submission Checklist - [x] Tests added or updated (happy path + at least one failure / edge case) per [Testing Strategy](../gitbooks/developing/testing-strategy.md#failure-path-requirement) - updated the reference cron E2E spec and helper path. - [x] **Diff coverage >= 80%** - N/A locally: E2E helper/spec/doc change; CI diff coverage is authoritative. - [x] Coverage matrix updated - N/A: E2E selector-hardening change, no feature row added/removed/renamed. - [x] All affected feature IDs from the matrix are listed in the PR description under `## Related` - N/A: no matrix feature ID applies. - [x] No new external network dependencies introduced (mock backend used per [Testing Strategy](../gitbooks/developing/testing-strategy.md#mock-policy)) - [x] Manual smoke checklist updated if this touches release-cut surfaces ([`docs/RELEASE-MANUAL-SMOKE.md`](../docs/RELEASE-MANUAL-SMOKE.md)) - N/A: no release-cut surface. - [x] Linked issue closed via `Closes #NNN` in the `## Related` section - N/A: this is a scoped slice that references #1861 without closing the broader audit issue. ## Impact - Runtime impact: none outside stable `data-testid` attributes on the Cron Jobs panel. - Test impact: cron E2E is less coupled to Tailwind classes and container structure. - Compatibility: `waitForTestId` is documented as tauri-driver/DOM-backed; Mac2 specs should keep accessibility/text helpers unless IDs are mirrored into accessible labels. ## Related - Refs #1861 - Follow-up PR(s)/TODOs: add stable hooks/migrations for the remaining settings, skills, conversation, onboarding, and notification E2E surfaces tracked by #1861. --- ## AI Authored PR Metadata (required for Codex/Linear PRs) ### Linear Issue - Key: N/A - URL: N/A ### Commit & Branch - Branch: `codex/1861-cron-e2e-testids` - Commit SHA: `28eca40a3d2e3a75b61105887e4faf58d4c0866e` ### Validation Run - [x] `pnpm --filter openhuman-app exec prettier --check src/components/settings/panels/CronJobsPanel.tsx test/e2e/helpers/element-helpers.ts test/e2e/specs/cron-jobs-flow.spec.ts` - passed - [x] `pnpm typecheck` - passed - [x] Focused tests: N/A, E2E spec migration not run locally - [x] Rust fmt/check (if changed): `cargo fmt --all --check` - passed; `git diff --check` - passed - [x] Tauri fmt/check (if changed): N/A ### Validation Blocked - `command:` `pnpm --filter openhuman-app exec tsc -p test/tsconfig.e2e.json --noEmit` - `error:` local command could not find `tsc` / `@wdio/globals/types` via that invocation - `impact:` app-wide `pnpm typecheck` passes; remote E2E/TS jobs remain authoritative for the E2E tsconfig ### Behavior Changes - Intended behavior change: none for users; E2E selectors now target stable hooks. - User-visible effect: none. ### Parity Contract - Legacy behavior preserved: cron load, refresh, pause/resume, run-history, and remove behavior unchanged. - Guard/fallback/dispatch parity checks: spec still asserts the same UI and sidecar persistence behavior. ### Duplicate / Superseded PR Handling - Duplicate PR(s): N/A - Canonical PR: this PR - Resolution (closed/superseded/updated): N/A <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Added E2E helpers and updated cron-jobs flow to use stable test identifiers for more reliable UI interactions and polling. * **Documentation** * Added guidance on stable test ID naming and how to use the new E2E helpers in the testing guide. * **Maintenance** * Cron Jobs panel and controls now expose stable identifiers for testing (no user-facing behavior changes). <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/tinyhumansai/openhuman/pull/2301?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: aqilaziz <gonzes7@gmail.com> Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
9.4 KiB
description, icon
| description | icon |
|---|---|
| End-to-end testing with WDIO + tauri-driver / Appium. CI and local setup. | vials |
E2E Testing Guide
Overview
Desktop E2E tests use WebDriverIO (WDIO) to drive the Tauri app via two automation backends:
| Platform | Driver | Port | App format | Selectors |
|---|---|---|---|---|
| Linux / CEF status | tauri-driver |
4444 | Debug binary | CSS / DOM |
| macOS / Appium | Appium Mac2 | 4723 | .app bundle |
XPath / accessibility |
OpenHuman's desktop app currently uses the CEF runtime (tauri-runtime-cef). Linux tauri-driver talks to WebKitWebDriver / webkit2gtk and cannot drive a CEF-backed WebView, so Linux CEF E2E is disabled in CI until a CEF-compatible driver or replacement harness exists. The supported path today is macOS/Appium for local runs, with manual macOS/Appium workflow runs when that workflow is enabled.
Quick start
Linux / CEF status
# Install tauri-driver (one-time)
cargo install tauri-driver
# Build the E2E app
pnpm --filter openhuman-app test:e2e:build
# Run all flows
pnpm --filter openhuman-app test:e2e:all:flows
# Run a single spec
bash app/scripts/e2e-run-spec.sh test/e2e/specs/smoke.spec.ts smoke
On headless Linux, the harness runs under Xvfb for a virtual display. This path is currently useful only for non-CEF / WebKit-compatible debugging; the default CEF app cannot be automated by WebKitWebDriver.
macOS / Appium
# Install Appium + Mac2 driver (one-time, needs Node 24+)
npm install -g appium
appium driver install mac2
# Build the .app bundle
pnpm --filter openhuman-app test:e2e:build
# Run all flows
pnpm --filter openhuman-app test:e2e:all:flows
Docker on macOS (Linux harness locally)
Run the same Linux-based harness from macOS using Docker. The same CEF limitation applies: this is not a supported path for the default CEF runtime until a CEF-compatible driver exists.
# Build + run all E2E flows
docker compose -f e2e/docker-compose.yml run --rm e2e
# Build the app first (if needed)
docker compose -f e2e/docker-compose.yml run --rm e2e \
pnpm --filter openhuman-app test:e2e:build
# Run a single spec
docker compose -f e2e/docker-compose.yml run --rm e2e \
bash app/scripts/e2e-run-spec.sh test/e2e/specs/smoke.spec.ts smoke
Requires Docker Desktop or Colima. The repo is bind-mounted so builds persist between runs.
Architecture
Platform detection
app/test/e2e/helpers/platform.ts exports:
isTauriDriver(),trueon Linux (tauri-driver session)isMac2(),trueon macOS (Appium Mac2 session)supportsExecuteScript(),truewhenbrowser.execute()works (tauri-driver only)
Element helpers
app/test/e2e/helpers/element-helpers.ts provides a unified API:
| Helper | Mac2 (macOS) | tauri-driver (Linux) |
|---|---|---|
waitForText(text) |
XPath over @label/@value/@title | XPath over DOM text content |
waitForButton(text) |
XCUIElementTypeButton XPath | button / [role="button"] XPath |
clickText(text) |
W3C pointer actions | Standard el.click() |
clickNativeButton(text) |
W3C pointer actions on XCUIElementTypeButton | Standard el.click() on button |
clickToggle() |
XCUIElementTypeSwitch / XCUIElementTypeCheckBox | [role="switch"] / input[type="checkbox"] |
waitForWindowVisible() |
XCUIElementTypeWindow | Window handle check |
waitForWebView() |
XCUIElementTypeWebView | document.readyState check |
hasAppChrome() |
XCUIElementTypeMenuBar | Window handle check |
dumpAccessibilityTree() |
Accessibility XML | HTML page source |
Stable test IDs
Prefer stable data-testid hooks for UI affordances that E2E specs click or poll. Use the taxonomy <surface>-<element>-<id?>, for example:
cron-jobs-panel,cron-refreshcron-job-row-<jobId>,cron-job-toggle-<jobId>,cron-job-run-<jobId>,cron-job-view-runs-<jobId>,cron-job-remove-<jobId>settings-nav-<routeId>skill-row-<skillId>,skill-install-<skillId>,skill-uninstall-<skillId>thread-row-<threadId>,new-thread-button,send-message-buttononboarding-next-button
Use waitForTestId(testId) and clickTestId(testId) from element-helpers.ts when a spec targets one of these hooks. Keep text selectors for user-visible copy assertions, not row/action discovery.
Deep link helpers
app/test/e2e/helpers/deep-link-helpers.ts handles auth deep links:
- tauri-driver:
browser.execute(window.__simulateDeepLink(url))(primary),xdg-open(fallback) - Appium Mac2:
macos: deepLinkextension command (primary),open -a ...(fallback)
Writing cross-platform specs
- Use helpers from
element-helpers.ts, never use rawXCUIElementType*selectors in specs - Use
clickNativeButton(text)instead of inline button-clicking code - Use
hasAppChrome()instead of checking forXCUIElementTypeMenuBar - Use
waitForWebView()instead of checking forXCUIElementTypeWebView - For macOS-only tests, use
process.platformguards or separate spec files
Environment variables
| Variable | Default | Description |
|---|---|---|
TAURI_DRIVER_PORT |
4444 |
tauri-driver WebDriver port |
APPIUM_PORT |
4723 |
Appium server port |
E2E_MOCK_PORT |
18473 |
Mock backend server port |
OPENHUMAN_WORKSPACE |
(temp dir) | App workspace directory |
OPENHUMAN_SERVICE_MOCK |
0 |
Enable service mock mode |
OPENHUMAN_E2E_MODE |
unset | Enables destructive test-support RPCs; the E2E runner sets this to 1 |
OPENHUMAN_E2E_AUTH_BYPASS |
unset | Enable JWT bypass auth |
DEBUG_E2E_DEEPLINK |
(verbose) | Set to 0 to silence deep link logs |
E2E_FORCE_CARGO_CLEAN |
unset | Force cargo clean before E2E build |
CI workflows
Push / PR checks
The default test.yml workflow runs frontend unit tests and Rust checks. Its Linux tauri-driver E2E job is commented out because WebKitWebDriver cannot drive the CEF-backed WebView.
The disabled Linux E2E job used to:
- Installs system deps (webkit2gtk, Xvfb, dbus)
- Installs
tauri-drivervia cargo - Builds the app with mock server URL baked in
- Runs all E2E flows under Xvfb
macOS / Appium
macOS/Appium is the supported automation backend for the current CEF desktop app. Run it locally, or through a manually dispatched macOS workflow when that workflow is enabled:
- Installs Appium + Mac2 driver
- Builds the
.appbundle - Runs all E2E flows
Troubleshooting
Linux: "WebView not ready" timeout
For the default CEF runtime, this usually means the unsupported Linux tauri-driver path is trying to drive a CEF-backed WebView through WebKitWebDriver. Use macOS/Appium, or wait for a CEF-compatible Linux driver.
Ensure DISPLAY is set and Xvfb is running:
export DISPLAY=:99
Xvfb :99 -screen 0 1280x1024x24 &
Also ensure dbus is started (required by webkit2gtk):
eval $(dbus-launch --sh-syntax)
Linux: tauri-driver not found
cargo install tauri-driver
macOS: Deep links not working in tauri dev
Deep links require a .app bundle. Use pnpm tauri build --debug --bundles app instead.
Docker: Build is slow on first run
The first Docker build compiles Rust + tauri-driver from source. Subsequent runs use cached layers. Cargo registry and git sources are cached via Docker volumes.
Spec: Notifications
File: app/test/e2e/specs/notifications.spec.ts
Tests notification RPC methods via the live core sidecar and the Notifications UI page:
notification_ingest, creates a new notification via core RPCnotification_list, verifies the ingested notification is returnednotification_mark_read, marks a notification as readnotification_stats, checks aggregate statistics shape- UI: Notifications page renders the integration notifications section (
[data-testid="integration-notifications-section"]) - UI: Notifications page shows the System Events section (
[data-testid="system-events-section"])
Run:
bash app/scripts/e2e-run-spec.sh test/e2e/specs/notifications.spec.ts notifications
Platform note: RPC tests (notification_ingest, notification_list, notification_mark_read, notification_stats) are written for both Linux/tauri-driver and macOS/Appium Mac2, but Linux execution is disabled for the default CEF runtime until a CEF-compatible driver exists. UI assertions (Notifications page sections) require browser.execute() support, so they auto-skip on Mac2 when supportsExecuteScript() returns false.
Agent-observable artifact flow
For a canonical, inspectable run that drops screenshots, page-source dumps, and mock request logs on disk:
bash app/scripts/e2e-agent-review.sh
Artifacts land in app/test/e2e/artifacts/<timestamp>-agent-review/. Full details + helper API: AGENT-OBSERVABILITY.md. Any failing test triggers wdio.conf.ts's afterTest hook, which writes failure-*.png + failure-*.source.xml into the same run dir.
Rust inference provider E2E
These tests (tests/inference_provider_e2e.rs) use wiremock to mock HTTP upstreams and require no live LLM API calls. They cover OpenAI-compat chat, Anthropic auth style, per-model temperature suppression, Ollama local provider, and the /v1 HTTP endpoint auth layer.
# Local:
bash scripts/test-rust-inference-e2e.sh
# Via Docker (Linux, same image as CI):
docker compose -f e2e/docker-compose.yml run --rm inference-e2e