Skip to content

Commit 226a0f7

Browse files
CodeGhost21claude
andcommitted
feat(e2e): move CI to Linux by default, keep macOS optional
Move desktop E2E from macOS-only (Appium Mac2) to Linux-default (tauri-driver) in CI, reducing cost and improving scalability. macOS E2E remains available for local dev and manual CI dispatch. - Add platform detection layer (platform.ts) for tauri-driver vs Mac2 - Make all E2E helpers cross-platform (element, app, deep-link) - Extract shared clickNativeButton/clickToggle/hasAppChrome helpers - Replace inline XCUIElementType selectors in specs with helpers - Update wdio.conf.ts with conditional capabilities per platform - Update build/run scripts for Linux (tauri-driver) and macOS (Appium) - Add e2e-linux CI job on ubuntu-22.04 (default, every push/PR) - Convert e2e-macos to workflow_dispatch (manual opt-in) - Add Docker support for running Linux E2E on macOS locally - Add docs/E2E-TESTING.md contributor guide Closes tinyhumansai#81 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d03dbb5 commit 226a0f7

24 files changed

Lines changed: 1014 additions & 638 deletions

.github/workflows/test.yml

Lines changed: 117 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ name: Test
33
on:
44
push:
55
pull_request:
6+
workflow_dispatch:
7+
inputs:
8+
run_macos_e2e:
9+
description: 'Run macOS E2E tests (Appium Mac2)'
10+
required: false
11+
default: 'false'
12+
type: choice
13+
options:
14+
- 'false'
15+
- 'true'
616

717
permissions:
818
contents: read
@@ -113,41 +123,110 @@ jobs:
113123
- name: Test Tauri shell (OpenHuman)
114124
run: cargo test --manifest-path app/src-tauri/Cargo.toml
115125

116-
# e2e-macos:
117-
# name: E2E (macOS / Appium)
118-
# runs-on: macos-latest
119-
# timeout-minutes: 90
120-
# steps:
121-
# - name: Checkout code
122-
# uses: actions/checkout@v4
123-
# with:
124-
# fetch-depth: 1
125-
# submodules: recursive
126-
127-
# - name: Setup Node.js 24.x
128-
# uses: actions/setup-node@v4
129-
# with:
130-
# node-version: 24.x
131-
# cache: "yarn"
132-
133-
# - name: Install Rust (rust-toolchain.toml)
134-
# uses: dtolnay/rust-toolchain@1.93.0
135-
136-
# - name: Install dependencies
137-
# run: yarn install --frozen-lockfile
138-
139-
# - name: Ensure .env exists for E2E build
140-
# run: |
141-
# touch .env
142-
# touch app/.env
143-
144-
# - name: Install Appium and mac2 driver
145-
# run: |
146-
# npm install -g appium
147-
# appium driver install mac2
148-
149-
# - name: Build E2E app bundle
150-
# run: yarn workspace openhuman-app test:e2e:build
151-
152-
# - name: Run all E2E flows
153-
# run: yarn workspace openhuman-app test:e2e:all:flows
126+
e2e-linux:
127+
name: E2E (Linux / tauri-driver)
128+
runs-on: ubuntu-22.04
129+
timeout-minutes: 60
130+
steps:
131+
- name: Checkout code
132+
uses: actions/checkout@v4
133+
with:
134+
fetch-depth: 1
135+
submodules: recursive
136+
137+
- name: Setup Node.js 24.x
138+
uses: actions/setup-node@v4
139+
with:
140+
node-version: 24.x
141+
cache: "yarn"
142+
143+
- name: Install Rust (rust-toolchain.toml)
144+
uses: dtolnay/rust-toolchain@1.93.0
145+
146+
- name: Install system dependencies
147+
run: |
148+
sudo apt-get update
149+
sudo apt-get install -y \
150+
libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev \
151+
librsvg2-dev patchelf \
152+
xvfb at-spi2-core dbus-x11
153+
154+
- name: Cargo.lock fingerprint (deps only)
155+
id: cargo-lock-fingerprint
156+
shell: bash
157+
run: |
158+
echo "hash=$(tail -n +8 Cargo.lock | openssl dgst -sha256 | awk '{print $2}')" >> "$GITHUB_OUTPUT"
159+
160+
- name: Cache Cargo registry and build
161+
uses: actions/cache@v4
162+
with:
163+
path: |
164+
~/.cargo/registry
165+
~/.cargo/git
166+
target
167+
key: ${{ runner.os }}-e2e-cargo-${{ steps.cargo-lock-fingerprint.outputs.hash }}
168+
restore-keys: |
169+
${{ runner.os }}-e2e-cargo-
170+
171+
- name: Install tauri-driver
172+
run: cargo install tauri-driver
173+
174+
- name: Install JS dependencies
175+
run: yarn install --frozen-lockfile
176+
177+
- name: Ensure .env exists for E2E build
178+
run: |
179+
touch .env
180+
touch app/.env
181+
182+
- name: Build E2E app
183+
run: yarn workspace openhuman-app test:e2e:build
184+
185+
- name: Run E2E tests under Xvfb
186+
run: |
187+
export DISPLAY=:99
188+
Xvfb :99 -screen 0 1280x1024x24 &
189+
sleep 2
190+
# dbus session is required by webkit2gtk
191+
eval $(dbus-launch --sh-syntax)
192+
yarn workspace openhuman-app test:e2e:all:flows
193+
194+
e2e-macos:
195+
name: E2E (macOS / Appium)
196+
if: github.event_name == 'workflow_dispatch' && github.event.inputs.run_macos_e2e == 'true'
197+
runs-on: macos-latest
198+
timeout-minutes: 90
199+
steps:
200+
- name: Checkout code
201+
uses: actions/checkout@v4
202+
with:
203+
fetch-depth: 1
204+
submodules: recursive
205+
206+
- name: Setup Node.js 24.x
207+
uses: actions/setup-node@v4
208+
with:
209+
node-version: 24.x
210+
cache: "yarn"
211+
212+
- name: Install Rust (rust-toolchain.toml)
213+
uses: dtolnay/rust-toolchain@1.93.0
214+
215+
- name: Install dependencies
216+
run: yarn install --frozen-lockfile
217+
218+
- name: Ensure .env exists for E2E build
219+
run: |
220+
touch .env
221+
touch app/.env
222+
223+
- name: Install Appium and mac2 driver
224+
run: |
225+
npm install -g appium
226+
appium driver install mac2
227+
228+
- name: Build E2E app bundle
229+
run: yarn workspace openhuman-app test:e2e:build
230+
231+
- name: Run all E2E flows
232+
run: yarn workspace openhuman-app test:e2e:all:flows

CLAUDE.md

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,32 +114,45 @@ yarn mock:api
114114
curl -s http://127.0.0.1:18473/__admin/health
115115
```
116116

117-
### E2E tests (WDIO + Appium mac2)
117+
### E2E tests (WDIO — dual platform)
118+
119+
Full guide: [`docs/E2E-TESTING.md`](docs/E2E-TESTING.md).
120+
121+
Two automation backends:
122+
- **Linux (CI default)**: `tauri-driver` (WebDriver, port 4444) — drives the debug binary directly
123+
- **macOS (local dev)**: Appium Mac2 (XCUITest, port 4723) — drives the `.app` bundle
118124

119125
- **Where specs live**: `app/test/e2e/specs/*.spec.ts`
120126
- **Shared harness**:
121-
- Helpers: `app/test/e2e/helpers/*`
127+
- Platform detection: `app/test/e2e/helpers/platform.ts`
128+
- Element helpers: `app/test/e2e/helpers/element-helpers.ts`
129+
- Deep link helpers: `app/test/e2e/helpers/deep-link-helpers.ts`
130+
- App lifecycle: `app/test/e2e/helpers/app-helpers.ts`
122131
- Mock backend: `app/test/e2e/mock-server.ts`
123-
- WDIO config: `app/test/wdio.conf.ts`
132+
- WDIO config: `app/test/wdio.conf.ts` (auto-detects platform)
124133

125134
- **Build + run**:
126135

127136
```bash
128-
# Build desktop app bundle + stage core sidecar
137+
# Build app + stage core sidecar (detects macOS vs Linux automatically)
129138
yarn test:e2e:build
130139

131140
# Run one spec
132141
bash app/scripts/e2e-run-spec.sh test/e2e/specs/smoke.spec.ts smoke
133142

134143
# Run all flow specs
135144
yarn test:e2e:all:flows
145+
146+
# Docker on macOS (run Linux E2E locally)
147+
docker compose -f e2e/docker-compose.yml run --rm e2e
136148
```
137149

138150
- **Authoring rules**:
139151
- Ensure each spec is runnable in isolation.
140-
- Use helper waits (`waitForAppReady`, `waitForWebView`, etc.) instead of ad hoc long sleeps.
152+
- Use helpers from `element-helpers.ts` — never use raw `XCUIElementType*` selectors in specs.
153+
- Use `clickNativeButton()`, `hasAppChrome()`, `waitForWebView()`, `clickToggle()` for cross-platform element interaction.
141154
- Assert both UI outcomes and backend/mock effects when relevant.
142-
- Add failure diagnostics (request logs, accessibility tree dump) for faster debugging by agents.
155+
- Add failure diagnostics (request logs, `dumpAccessibilityTree()`) for faster debugging by agents.
143156

144157
### Deterministic core-sidecar reset
145158

app/scripts/e2e-build.sh

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#!/usr/bin/env bash
22
#
3-
# Build the .app bundle for E2E tests with the mock server URL baked in.
3+
# Build the app for E2E tests with the mock server URL baked in.
4+
#
5+
# - macOS: builds a .app bundle (Appium Mac2)
6+
# - Linux: builds a debug binary (tauri-driver)
7+
#
48
# Cargo incremental builds are used by default for faster iteration.
59
#
610
set -euo pipefail
@@ -14,7 +18,7 @@ cd "$APP_DIR"
1418

1519
export VITE_BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT:-18473}"
1620

17-
echo "Building E2E app bundle with VITE_BACKEND_URL=$VITE_BACKEND_URL"
21+
echo "Building E2E app with VITE_BACKEND_URL=$VITE_BACKEND_URL"
1822

1923
if [ -n "${E2E_FORCE_CARGO_CLEAN:-}" ]; then
2024
echo "Forcing cargo clean (E2E_FORCE_CARGO_CLEAN is set)."
@@ -39,6 +43,16 @@ node "$REPO_ROOT/scripts/stage-core-sidecar.mjs"
3943
TAURI_CONFIG_OVERRIDE='{"bundle":{"createUpdaterArtifacts":false}}'
4044
# Tauri CLI maps env CI to --ci and only accepts true|false; some runners set CI=1.
4145
case "${CI:-}" in 1) export CI=true ;; 0) export CI=false ;; esac
42-
npx tauri build -c "$TAURI_CONFIG_OVERRIDE" --bundles app --debug
46+
47+
OS="$(uname)"
48+
if [ "$OS" = "Linux" ]; then
49+
# Linux: build debug binary only (no bundle needed for tauri-driver)
50+
echo "Building for Linux (debug binary, no bundle)..."
51+
npx tauri build -c "$TAURI_CONFIG_OVERRIDE" --debug
52+
else
53+
# macOS: build .app bundle for Appium Mac2
54+
echo "Building for macOS (.app bundle)..."
55+
npx tauri build -c "$TAURI_CONFIG_OVERRIDE" --bundles app --debug
56+
fi
4357

4458
echo "E2E build complete."

0 commit comments

Comments
 (0)