Files
openhuman/gitbooks/developing/e2e-testing.zh-CN.md
T
JAYcodrGitHubagent:skill-master <skill-master@openclaw>
3299c16933 Docs/i18n batch c1 developing foundation (#2504)
Co-authored-by: agent:skill-master <skill-master@openclaw>
2026-05-22 15:44:59 -07:00

257 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
description: 使用 WDIO + tauri-driver / Appium 进行端到端测试。CI 和本地设置。
icon: vials
lang: zh-CN
---
# E2E 测试指南
## 概述
桌面 E2E 测试使用 **WebDriverIO (WDIO)** 通过两个自动化后端驱动 Tauri 应用:
| 平台 | 驱动 | 端口 | 应用格式 | 选择器 |
|----------|--------|------|------------|-----------|
| **Linux / CEF 状态** | `tauri-driver` | 4444 | Debug 二进制文件 | CSS / DOM |
| **macOS / Appium** | Appium Mac2 | 4723 | `.app` 包 | XPath / 辅助功能 |
OpenHuman 桌面应用目前使用 CEF 运行时(`tauri-runtime-cef`)。Linux `tauri-driver` 与 WebKitWebDriver / webkit2gtk 通信,无法驱动 CEF -backed WebView,因此 Linux CEF E2E 在 CI 中被禁用,直到存在 CEF 兼容的驱动或替代 harness。目前支持的路径是 macOS/Appium 用于本地运行,以及在该工作流启用时手动触发 macOS/Appium 工作流运行。
---
## 快速开始
### Linux / CEF 状态
```bash
# 安装 tauri-driver(一次性)
cargo install tauri-driver
# 构建 E2E 应用
pnpm --filter openhuman-app test:e2e:build
# 运行所有流程
pnpm --filter openhuman-app test:e2e:all:flows
# 运行单个 spec
bash app/scripts/e2e-run-spec.sh test/e2e/specs/smoke.spec.ts smoke
```
在无头 Linux 上,harness 在 **Xvfb** 虚拟显示下运行。此路径目前仅对非 CEF / WebKit 兼容调试有用;默认 CEF 应用无法被 WebKitWebDriver 自动化。
### macOS / Appium
```bash
# 安装 Appium + Mac2 驱动(一次性,需要 Node 24+)
npm install -g appium
appium driver install mac2
# 构建 .app 包
pnpm --filter openhuman-app test:e2e:build
# 运行所有流程
pnpm --filter openhuman-app test:e2e:all:flows
```
### macOS 上的 Docker(本地运行 Linux harness
使用 Docker 从 macOS 运行相同的基于 Linux 的 harness。同样的 CEF 限制适用:在存在 CEF 兼容驱动之前,这不是默认 CEF 运行时的支持路径。
```bash
# 构建 + 运行所有 E2E 流程
docker compose -f e2e/docker-compose.yml run --rm e2e
# 先构建应用(如需要)
docker compose -f e2e/docker-compose.yml run --rm e2e \
pnpm --filter openhuman-app test:e2e:build
# 运行单个 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
```
需要 Docker Desktop 或 Colima。仓库通过 bind mount 挂载,因此构建在运行之间持久化。
---
## 架构
### 平台检测
`app/test/e2e/helpers/platform.ts` 导出:
- `isTauriDriver()``true` 表示 Linuxtauri-driver session
- `isMac2()``true` 表示 macOSAppium Mac2 session
- `supportsExecuteScript()``true``browser.execute()` 可用时(仅 tauri-driver
### 元素辅助函数
`app/test/e2e/helpers/element-helpers.ts` 提供统一 API
| 辅助函数 | Mac2 (macOS) | tauri-driver (Linux) |
|--------|-------------|---------------------|
| `waitForText(text)` | @label/@value/@title 上的 XPath | DOM 文本内容上的 XPath |
| `waitForButton(text)` | XCUIElementTypeButton XPath | `button` / `[role="button"]` XPath |
| `clickText(text)` | W3C 指针动作 | 标准 `el.click()` |
| `clickNativeButton(text)` | XCUIElementTypeButton 上的 W3C 指针动作 | button 上的标准 `el.click()` |
| `clickToggle()` | XCUIElementTypeSwitch / XCUIElementTypeCheckBox | `[role="switch"]` / `input[type="checkbox"]` |
| `waitForWindowVisible()` | XCUIElementTypeWindow | 窗口句柄检查 |
| `waitForWebView()` | XCUIElementTypeWebView | `document.readyState` 检查 |
| `hasAppChrome()` | XCUIElementTypeMenuBar | 窗口句柄检查 |
| `dumpAccessibilityTree()` | 辅助功能 XML | HTML 页面源码 |
### 稳定的测试 ID
优先为 E2E spec 点击或轮询的 UI affordance 使用稳定的 `data-testid` hook。使用分类法 `<surface>-<element>-<id?>`,例如:
- `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`
当 spec 瞄准这些 hook 之一时,使用 `element-helpers.ts` 中的 `waitForTestId(testId)``clickTestId(testId)`。对行/动作发现保留文本选择器,对用户可见文案断言也保留文本选择器。
### 深度链接辅助函数
`app/test/e2e/helpers/deep-link-helpers.ts` 处理 auth 深度链接:
- **tauri-driver**`browser.execute(window.__simulateDeepLink(url))`(主要),`xdg-open`(备用)
- **Appium Mac2**`macos: deepLink` 扩展命令(主要),`open -a ...`(备用)
对于发布候选版,在触碰 CEF preflight、单实例或深度链接启动代码时,还要在 Linux 或 macOS 上运行一次手动 secondary-instance 冒烟测试:
1. 正常启动 OpenHuman 并保持运行。
2. 通过 OS opener 触发 `openhuman://auth?token=e2e-token&key=auth`
3. 确认已运行的窗口接收到回调,且不会启动第二个完整的 CEF 实例。
4. 确认 secondary 进程干净退出,没有 CEF 缓存锁错误。
这捕捉了一类回归:secondary 进程在 Tauri 的深度链接转发路径安装之前,于 CEF 缓存 preflight 期间退出。
### 编写跨平台 spec
1. 在 spec 中使用 `element-helpers.ts` 中的**辅助函数**,永远不要使用原始的 `XCUIElementType*` 选择器
2. 使用 **`clickNativeButton(text)`** 代替内联 button-clicking 代码
3. 使用 **`hasAppChrome()`** 代替检查 `XCUIElementTypeMenuBar`
4. 使用 **`waitForWebView()`** 代替检查 `XCUIElementTypeWebView`
5. 对于仅 macOS 的测试,使用 `process.platform` 守卫或单独的 spec 文件
6. 对 hash 路由使用 `navigateViaHash(route)`;它等待 hash、`document.readyState` 和挂载的 React root 后返回。在 onboarding 之后,`walkOnboarding()` 也等待 `#/home` 加上 Home 页面标记,然后 spec 才会导航到别处。
---
## 环境变量
| 变量 | 默认值 | 说明 |
|----------|---------|-------------|
| `TAURI_DRIVER_PORT` | `4444` | tauri-driver WebDriver 端口 |
| `APPIUM_PORT` | `4723` | Appium 服务器端口 |
| `E2E_MOCK_PORT` | `18473` | Mock 后端服务器端口 |
| `OPENHUMAN_WORKSPACE` | (临时目录) | 应用工作区目录 |
| `OPENHUMAN_SERVICE_MOCK` | `0` | 启用服务 mock 模式 |
| `OPENHUMAN_E2E_MODE` | 未设置 | 启用破坏性测试支持 RPC;E2E runner 将其设为 `1` |
| `OPENHUMAN_E2E_AUTH_BYPASS` | 未设置 | 启用 JWT 绕过认证 |
| `DEBUG_E2E_DEEPLINK` | (verbose) | 设为 `0` 以静默深度链接日志 |
| `E2E_FORCE_CARGO_CLEAN` | 未设置 | E2E 构建前强制 cargo clean |
---
## CI 工作流
### Push / PR 检查
默认的 `test.yml` 工作流运行前端单元测试和 Rust 检查。其 Linux `tauri-driver` E2E job 被注释掉了,因为 WebKitWebDriver 无法驱动 CEF-backed WebView。
被禁用的 Linux E2E job 过去会:
1. 安装系统依赖(webkit2gtk、Xvfb、dbus
2. 通过 cargo 安装 `tauri-driver`
3. 用 mock 服务器 URL 构建应用
4. 在 Xvfb 下运行所有 E2E 流程
### macOS / Appium
macOS/Appium 是当前 CEF 桌面应用支持的自动化后端。在本地运行,或在该工作流启用时通过手动触发的 macOS 工作流运行:
1. 安装 Appium + Mac2 驱动
2. 构建 `.app`
3. 运行所有 E2E 流程
---
## 故障排除
### Linux"WebView not ready" 超时
对于默认 CEF 运行时,这通常意味着不支持的 Linux `tauri-driver` 路径正试图通过 WebKitWebDriver 驱动 CEF-backed WebView。请使用 macOS/Appium,或等待 CEF 兼容的 Linux 驱动。
确保 `DISPLAY` 已设置且 Xvfb 正在运行:
```bash
export DISPLAY=:99
Xvfb :99 -screen 0 1280x1024x24 &
```
还要确保 dbus 已启动(webkit2gtk 需要):
```bash
eval $(dbus-launch --sh-syntax)
```
### Linux:找不到 tauri-driver
```bash
cargo install tauri-driver
```
### macOS:深度链接在 `tauri dev` 中不工作
深度链接需要 `.app` 包。请改用 `pnpm tauri build --debug --bundles app`
### Docker:首次运行构建很慢
首次 Docker 构建从源码编译 Rust + tauri-driver。后续运行使用缓存层。Cargo registry 和 git 源通过 Docker volume 缓存。
## SpecNotifications
**文件**`app/test/e2e/specs/notifications.spec.ts`
通过实时 core sidecar 和 Notifications UI 页面测试 notification RPC 方法:
- `notification_ingest`,通过 core RPC 创建新通知
- `notification_list`,验证摄入的通知被返回
- `notification_mark_read`,将通知标记为已读
- `notification_stats`,检查聚合统计形状
- UINotifications 页面渲染集成通知部分(`[data-testid="integration-notifications-section"]`
- UINotifications 页面显示 System Events 部分(`[data-testid="system-events-section"]`
**运行**
```bash
bash app/scripts/e2e-run-spec.sh test/e2e/specs/notifications.spec.ts notifications
```
**平台说明**RPC 测试(`notification_ingest``notification_list``notification_mark_read``notification_stats`)为 Linux/tauri-driver 和 macOS/Appium Mac2 编写,但默认 CEF 运行时的 Linux 执行被禁用,直到存在 CEF 兼容驱动。UI 断言(Notifications 页面部分)需要 `browser.execute()` 支持,因此当 `supportsExecuteScript()` 返回 `false` 时,它们在 Mac2 上自动跳过。
---
## Agent 可观测的工件流
对于一种规范的、可检查的 run,将截图、页面源码 dump 和 mock 请求日志写入磁盘:
```bash
bash app/scripts/e2e-agent-review.sh
```
工件落在 `app/test/e2e/artifacts/<timestamp>-agent-review/`。完整详情 + 辅助 API[`AGENT-OBSERVABILITY.md`](agent-observability.md)。任何失败的测试都会触发 `wdio.conf.ts``afterTest` hook,将 `failure-*.png` + `failure-*.source.xml` 写入同一运行目录。
---
## Rust 推理提供商 E2E
这些测试(`tests/inference_provider_e2e.rs`)使用 **wiremock** 模拟 HTTP upstream,不需要实时 LLM API 调用。它们覆盖 OpenAI 兼容聊天、Anthropic 认证风格、每模型温度抑制、Ollama 本地提供商和 `/v1` HTTP 端点认证层。
```bash
# 本地:
bash scripts/test-rust-inference-e2e.sh
# 通过 DockerLinux,与 CI 相同镜像):
docker compose -f e2e/docker-compose.yml run --rm inference-e2e
```