Files
openhuman/gitbooks/developing/e2e-testing.md
T
0f5e91421b test(e2e): use stable cron test ids
## 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 -->

[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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>
2026-05-20 16:51:38 -07:00

246 lines
9.4 KiB
Markdown

---
description: End-to-end testing with WDIO + tauri-driver / Appium. CI and local setup.
icon: 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
```bash
# 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
```bash
# 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.
```bash
# 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()`, `true` on Linux (tauri-driver session)
- `isMac2()`, `true` on macOS (Appium Mac2 session)
- `supportsExecuteScript()`, `true` when `browser.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-refresh`
- `cron-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-button`
- `onboarding-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: deepLink` extension command (primary), `open -a ...` (fallback)
### Writing cross-platform specs
1. **Use helpers** from `element-helpers.ts`, never use raw `XCUIElementType*` selectors in specs
2. **Use `clickNativeButton(text)`** instead of inline button-clicking code
3. **Use `hasAppChrome()`** instead of checking for `XCUIElementTypeMenuBar`
4. **Use `waitForWebView()`** instead of checking for `XCUIElementTypeWebView`
5. For macOS-only tests, use `process.platform` guards 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:
1. Installs system deps (webkit2gtk, Xvfb, dbus)
2. Installs `tauri-driver` via cargo
3. Builds the app with mock server URL baked in
4. 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:
1. Installs Appium + Mac2 driver
2. Builds the `.app` bundle
3. 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:
```bash
export DISPLAY=:99
Xvfb :99 -screen 0 1280x1024x24 &
```
Also ensure dbus is started (required by webkit2gtk):
```bash
eval $(dbus-launch --sh-syntax)
```
### Linux: tauri-driver not found
```bash
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 RPC
- `notification_list`, verifies the ingested notification is returned
- `notification_mark_read`, marks a notification as read
- `notification_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
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
bash app/scripts/e2e-agent-review.sh
```
Artifacts land in `app/test/e2e/artifacts/<timestamp>-agent-review/`. Full details + helper API: [`AGENT-OBSERVABILITY.md`](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.
```bash
# 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
```