Repository navigation
refactor(mock-api): domain split + OAuth + Composio + e2e workflow + macOS mega-spec scaffold - #1532
Conversation
The 1500-line scripts/mock-api-core.mjs is now a thin re-export shim over
scripts/mock-api/, organized by domain:
state.mjs — mockBehavior, request log, tunnels, user/team factories
http.mjs — CORS, json/html senders, body parsing, header redaction
socket.mjs — engine.io polling + WebSocket upgrade
admin.mjs — /__admin/{health,requests,behavior,reset}
server.mjs — http server lifecycle + route dispatch
routes/
auth.mjs — /auth/*, /telegram/login-tokens/*
user.mjs — /settings, /teams*, /rewards/me, /referral/*, /users
invites.mjs — /invite/*
payments.mjs — /payments/*, /billing/*
integrations.mjs — /agent-integrations/*, /gmail/*, /notion/*, /telegram/*, /openai/v1/*
webhooks.mjs — /webhooks/core/*, /webhooks/ingress/*
conversations.mjs — /conversations, /messages*, /channels*, /notifications
version.mjs — /version-check
cron.mjs — /settings/cron-jobs, /settings/webhooks-triggers
Gap-fill stubs added for routes the app/core call but the mock never
implemented: /version-check, /auth/email/send-link, /auth/telegram,
/users, /teams/join, /conversations*, /messages*, /channels*,
/notifications, /webhooks/ingress*, /settings/cron-jobs*,
/settings/webhooks-triggers*, /payments/credits/{top-up,transactions,
auto-recharge/cards/setup-intent,auto-recharge/cards/:id},
/agent-integrations/composio/{github/repos,tools}, /agent-integrations/apify/runs/*.
All 2042 vitest unit tests pass; manual curl smoke against the split
server confirms admin endpoints, existing routes, and new gap routes
all respond. Existing import paths (scripts/mock-api-server.mjs,
app/test/e2e/mock-server.ts) keep working unchanged.
Core has been compiled in-process since PR tinyhumansai#1061, so the sidecar staging script was removed but app/scripts/e2e-build.sh still tried to invoke it and crashed with MODULE_NOT_FOUND. Drop the dead call so e2e builds succeed again.
The mock previously handed back an oauthUrl pointing at /mock-<provider>-oauth
but that page just rendered `<h1>Mock OAuth</h1>` and went nowhere, so any
e2e spec that exercised the real OAuth click-through hung.
Replace with a proper mock provider:
GET /mock-oauth/<provider> — landing page that auto-redirects to
GET /mock-<provider>-oauth (legacy) `openhuman://oauth/success?integrationId=...&provider=...`
via <meta refresh> + JS, with a
visible "Continue" link as fallback.
GET /auth/<provider>/callback — 302 straight to the success/error
deep link (skips the HTML page).
POST /auth/<provider>/exchange — code-for-token JSON exchange for
backend-mediated flows.
Behavior knobs (settable via /__admin/behavior):
oauthAutoRedirectMs — delay before redirect ("manual" to disable)
oauthIntegrationId — integrationId emitted in the deep link
oauthForceError — flip the whole flow to the error deep link
oauthErrorCode — error code passed along
Per-request overrides via query string: ?integrationId, ?provider, ?error,
?manual=1.
Smoke-tested all four flows (success page, error page, callback 302,
exchange POST) against a running mock; all 2042 vitest tests still pass.
E2E run failures dump screenshots + source.xml to app/test/e2e/artifacts/, and pnpm caches its store at .pnpm-store/ when network-restricted hosts prefer an in-repo cache. Neither belongs in version control.
A single Mac2 session walks login → Gmail OAuth → Composio in one app
launch, driving everything through deep links + mock state and asserting
via the mock request log + core RPC. Between-scenario reset uses
openhuman.config_reset_local_data (mirrors the production "Clear app
data + log out" flow) plus re-writing ~/.openhuman/config.toml so the
mock URL survives the reset.
Three pieces:
* app/src-tauri/src/core_process.rs — when built with debug_assertions,
write the embedded core's bearer token to
${tmpdir}/openhuman-e2e-rpc-token. Release builds never touch this
file. Gives the e2e harness (a separate Node process) a way to
authenticate against the in-process RPC server — the token otherwise
lives only inside the Tauri host.
* app/test/e2e/helpers/core-rpc-node.ts — read the token file before
every probe + call, include Authorization: Bearer …. Falls through
cleanly when the file is missing.
* app/test/e2e/specs/mega-flow.spec.ts — six scenarios in one session:
login (consume), bypass login, Gmail OAuth success, Composio trigger
lifecycle via RPC, Gmail OAuth error path, post-reset re-login.
Known gap (blocks the spec from passing as-is): the app's BootCheckGate
shows a Local/Cloud "core mode picker" on first launch and won't start
the embedded core until the user picks. CEF WebView is inaccessible to
XCUITest on macOS, so the picker can't be dismissed from Mac2. A
follow-up patch needs to either pre-seed localStorage with
openhuman_core_mode=local in debug builds, or have the Tauri host
auto-default to local mode behind a debug-only env/marker check. Once
that lands the mega-spec should run end-to-end.
Mock backend, OAuth deep-link pages, Composio handlers, and the token
bridge are all in place and validated independently.
Single workflow file (.github/workflows/e2e.yml) runs WDIO desktop e2e
on three OSes simultaneously. All three legs are continue-on-error so
known-flaky platforms don't block PRs; macOS is the source of truth.
- e2e-linux containerized in ghcr.io/tinyhumansai/openhuman_ci:latest
(reuses the project's CI image — Xvfb, dbus, webkit2gtk-
driver, tauri-driver, Rust 1.93.0, Node 24 all preinstalled).
Smoke-only because tauri-driver/webkit2gtk can't drive CEF's
DOM.
- e2e-macos bare runner, Appium Mac2 driver. Canonical e2e runner.
Smoke + mega-flow on every PR; full spec suite via
workflow_dispatch with `full=true`.
- e2e-windows bare runner, tauri-driver via WebView2. Smoke only;
Windows hasn't been validated against the broader suite.
Linux/Windows reuse the same Rust target cache key shape as the existing
unit-tests jobs; macOS gets its own cache. Failure-only artifact upload
on each leg for triage.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a multi-OS E2E GitHub Actions workflow and build script changes, writes a debug-only per-launch RPC token file with Node helper support, refactors the mock API into modular state/http/server/socket/route modules, and adds a single-session mega-flow E2E spec exercising login, OAuth, integrations, and reset flows. ChangesE2E Testing Infrastructure Setup
Mock API Backend Refactor & Implementation
Comprehensive E2E Test Coverage
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
app/test/e2e/specs/mega-flow.spec.ts (1)
225-244: 💤 Low valueConsider simplifying the result extraction pattern.
The nested fallback chain (
before.result?.triggers ?? before.value?.result?.triggers ?? []) suggests uncertainty about the response shape. If the RPC response schema is well-defined, a single access path would be clearer and less fragile.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/test/e2e/specs/mega-flow.spec.ts` around lines 225 - 244, The tests use a fragile nested fallback chain to read triggers (before.result?.triggers ?? before.value?.result?.triggers ?? []) which makes the spec unclear; simplify by using the defined RPC response shape from callOpenhumanRpc for composio_list_triggers and read a single, explicit path (e.g., before.result.triggers) into beforeList/afterList after asserting before.ok/after.ok, and update both occurrences (beforeList and afterList) accordingly so the code assumes one canonical response shape instead of the three-way fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src-tauri/src/core_process.rs`:
- Around line 197-211: The debug-only write of the RPC bearer token (token_path
/ self.rpc_token in the debug block) currently uses std::fs::write which leaves
default OS permissions; change this to create the file with restrictive
permissions: on Unix use std::fs::OpenOptions +
std::os::unix::fs::OpenOptionsExt and set .mode(0o600) before writing
(create/write/truncate), and on Windows apply a platform-specific ACL (e.g., use
winapi/Windows API to set security descriptor or SetFileInformationByHandle) or
at minimum mark the file read-only only for the owner after creation; ensure you
still log the same debug/warn messages and handle/report any permission-setting
errors when writing the token.
In `@app/test/e2e/helpers/core-rpc-node.ts`:
- Around line 33-38: The buildHeaders function is currently returning an
Authorization header unconditionally when readBearerToken() exists, and
tryPingRpc (the blind port-probing loop around lines 67-68) uses it and can leak
the bearer token to arbitrary localhost services; modify the code so
buildHeaders accepts an option (e.g., includeAuth: boolean) or add a separate
buildAuthHeaders that only adds Authorization when explicitly requested, then
update tryPingRpc to call the headers builder with includeAuth=false (or use the
non-auth headers helper) while probing candidate ports and only include
Authorization for requests to the known, trusted RPC endpoint.
In `@scripts/mock-api/http.mjs`:
- Around line 32-37: readBody currently resolves only on the stream "end" event
and never rejects, so request errors or aborts hang callers; update the readBody
function to accept (req) and return a Promise that registers "data" to push
chunks, and also listens for "error" and "aborted" (or "close" with aborted
check) to reject the Promise, and ensure all listeners
("data","end","error","aborted"/"close") are removed in each terminal path to
avoid leaks; keep using Buffer.concat(chunks).toString() on successful "end"
resolution and reject with the original error or an AbortError when aborted.
In `@scripts/mock-api/routes/invites.mjs`:
- Around line 17-18: The route matcher in invites.mjs uses /^\/invite\/status/
which over-catches any path starting with /invite/status; update the condition
that checks method and url (the if that calls json(res, 200, { success: true,
data: { valid: true } })) to only match the exact status endpoint — e.g. change
the regex to require end-of-path (and allow an optional query string) such as
matching "/invite/status" exactly so unrelated routes are not intercepted by
this mock.
In `@scripts/mock-api/routes/payments.mjs`:
- Around line 191-199: The amount parsing currently uses
Number(parsedBody?.amountUsd ?? 0) || 10 which turns an explicit 0 into 10;
change the logic in the POST /payments/credits/top-up handler so you parse
amount with Number(parsedBody?.amountUsd ?? 0) into the amount variable and then
set amount = Number.isFinite(amount) ? amount : 10 (or similar finite-check
fallback), preserving 0 while only defaulting to 10 for non-finite or invalid
inputs; update the variable named amount used in the json(res, 200, { data: {
amountUsd: amount }}) response accordingly.
---
Nitpick comments:
In `@app/test/e2e/specs/mega-flow.spec.ts`:
- Around line 225-244: The tests use a fragile nested fallback chain to read
triggers (before.result?.triggers ?? before.value?.result?.triggers ?? []) which
makes the spec unclear; simplify by using the defined RPC response shape from
callOpenhumanRpc for composio_list_triggers and read a single, explicit path
(e.g., before.result.triggers) into beforeList/afterList after asserting
before.ok/after.ok, and update both occurrences (beforeList and afterList)
accordingly so the code assumes one canonical response shape instead of the
three-way fallback.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 244a495d-ac4e-4432-94e5-0bcb62c2ca60
📒 Files selected for processing (23)
.github/workflows/e2e.yml.gitignoreapp/scripts/e2e-build.shapp/src-tauri/src/core_process.rsapp/test/e2e/helpers/core-rpc-node.tsapp/test/e2e/specs/mega-flow.spec.tsscripts/mock-api-core.mjsscripts/mock-api/admin.mjsscripts/mock-api/http.mjsscripts/mock-api/index.mjsscripts/mock-api/routes/auth.mjsscripts/mock-api/routes/conversations.mjsscripts/mock-api/routes/cron.mjsscripts/mock-api/routes/integrations.mjsscripts/mock-api/routes/invites.mjsscripts/mock-api/routes/oauth.mjsscripts/mock-api/routes/payments.mjsscripts/mock-api/routes/user.mjsscripts/mock-api/routes/version.mjsscripts/mock-api/routes/webhooks.mjsscripts/mock-api/server.mjsscripts/mock-api/socket.mjsscripts/mock-api/state.mjs
Three fixes from the first CI run: * `pnpm/action-setup@v4` rejected both an explicit `version: 10` AND the `packageManager` field in package.json (ERR_PNPM_BAD_PM_VERSION). Removed `version:` from the macOS and Windows steps — the action now reads the version exclusively from `packageManager`. * The Linux job tried to drive the .deb binary with tauri-driver, which speaks WebKitWebDriver / webkit2gtk and cannot drive the CEF-backed WebView (session timed out on POST /session). That's the same incompatibility the project documents in test.yml's commented-out block. Stripped the spec-run step — the Linux job now builds the debug binary only, so a Linux-breaking dep / config / Rust change still fails the PR but we don't pretend to drive specs we can't. Renamed to `E2E (Linux build only)` so the surface is honest. * No change needed for macOS Mac2 step content yet — its setup failure was upstream of the actual driver.
`uname` on Windows GitHub runners (git-bash) returns MINGW64_NT-* / MSYS_NT-* / Windows_NT, which fell through to the script's macOS else branch and tried `--bundles app` — that's the macOS .app bundle and errors on Windows. wdio.conf launches the bare .exe at src-tauri/target/debug/OpenHuman.exe via tauri-driver, so `--no-bundle` is what we want there (same as Linux). Replaced the binary if/else with an explicit case so any future OS mismatch fails fast with a clear error instead of silently picking the wrong bundle target.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
.github/workflows/e2e.yml (1)
217-217: ⚡ Quick winAdd
--lockedtocargo installfor reproducible CI builds.
cargo install tauri-driver --version 2.0.5 --lockedwill use the crate's packagedCargo.lockand prevent transitive dependency drift during CI runs. Since tauri-driver 2.0.5 includes aCargo.lockfile, this flag is safe to use and improves reproducibility.Suggested change
- run: cargo install tauri-driver --version 2.0.5 + run: cargo install tauri-driver --version 2.0.5 --locked🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/e2e.yml at line 217, Update the CI step that runs the cargo install for tauri-driver by adding the --locked flag to the existing command; specifically modify the run command string "cargo install tauri-driver --version 2.0.5" to include "--locked" so it becomes "cargo install tauri-driver --version 2.0.5 --locked" in the e2e workflow run step that installs tauri-driver.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/e2e.yml:
- Around line 151-155: The workflow step "Install Appium and mac2 driver"
currently installs unpinned moving targets; define APPIUM_VERSION and
APPIUM_MAC2_VERSION environment variables and use them when installing to
guarantee compatibility (e.g. npm install -g appium@${APPIUM_VERSION} and appium
driver install mac2@${APPIUM_MAC2_VERSION}). Ensure the chosen
APPIUM_MAC2_VERSION is from the 1.x line if you are targeting Appium 2, or pick
compatible 2.x+ versions if you upgrade to Appium 3, and update the step that
runs "npm install -g appium" and "appium driver install mac2" to reference these
variables.
- Around line 163-172: Add an explicit id to the mega-flow step (e.g., id:
mega-flow) since it currently uses continue-on-error: true, and update the
artifact upload step's condition to also check that step's outcome (e.g., change
the if to include || steps.mega-flow.outcome == 'failure') so failures from the
mega-flow step will trigger Upload e2e artifacts on failure even when
continue-on-error is set.
---
Nitpick comments:
In @.github/workflows/e2e.yml:
- Line 217: Update the CI step that runs the cargo install for tauri-driver by
adding the --locked flag to the existing command; specifically modify the run
command string "cargo install tauri-driver --version 2.0.5" to include
"--locked" so it becomes "cargo install tauri-driver --version 2.0.5 --locked"
in the e2e workflow run step that installs tauri-driver.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 05a22e83-9279-4daf-8e8a-7724d83f99aa
📒 Files selected for processing (1)
.github/workflows/e2e.yml
Five small correctness/security fixes from CodeRabbit's first pass: * app/src-tauri/src/core_process.rs — write the debug-only e2e token file with mode 0600 on Unix and sync_all before close. Default umask could leave the bearer credential world-readable on shared dev hosts. * app/test/e2e/helpers/core-rpc-node.ts — strip the Authorization header from the port-probe path so a non-core HTTP service that happens to be bound to one of the candidate ports (7788–7793) doesn't receive our bearer as a side effect of discovery. 401 is now treated as a positive port match (endpoint exists, auth required) so the real call retries with auth attached. * scripts/mock-api/http.mjs — reject the readBody promise on stream error / aborted so a wedged request can't hang the dispatcher. * scripts/mock-api/routes/invites.mjs — tighten /invite/status to ^/invite/status(?:/[^/?]+)?/?(?:\?.*)?$ so it doesn't swallow unrelated /invite/status* paths and hide missing mocks. * scripts/mock-api/routes/payments.mjs — preserve explicit 0 in POST /payments/credits/top-up. The previous `n || 10` coerced a legitimate 0 into the default; use Number.isFinite + range check so non-numeric bodies still fall back but 0 stays 0.
The script previously only had Linux and macOS branches:
- Linux → tauri-driver
- else (macOS) → Appium Mac2 (sourced e2e-resolve-node-appium.sh)
On Windows runners `uname` returns MINGW64_NT-* / MSYS_NT-* / Windows_NT
which fell into the macOS else and failed with
"ERROR: appium not found. Install with: npm install -g appium".
Replaced the if/else with a case that:
- Linux + Windows/MINGW/MSYS/CYGWIN → start tauri-driver
(tauri-driver.exe on Windows, picked up from %USERPROFILE%\.cargo\bin),
log to $TMP on Windows, /tmp on Linux.
- Darwin → Appium Mac2 (unchanged).
- anything else → fail fast with a clear message.
Same approach as the e2e-build.sh case-style branching added in
47361e1. Windows e2e smoke (which fails fast on the WebView driver
incompatibility today) is still gated by `continue-on-error: true`
in the workflow so it doesn't block the PR.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/scripts/e2e-run-spec.sh`:
- Around line 144-149: The fallback for resolving TAURI_DRIVER_BIN can end up
using a Windows-style USERPROFILE path that fails POSIX -x checks; update the
logic around TAURI_DRIVER_BIN and TAURI_DRIVER_NAME so you try the POSIX
$HOME/.cargo/bin path first, and only if that isn't executable fall back to
USERPROFILE (or converted path) as a secondary option; change the branch that
currently sets
TAURI_DRIVER_BIN="${USERPROFILE:-$HOME}/.cargo/bin/$TAURI_DRIVER_NAME" to prefer
HOME (e.g., set TAURI_DRIVER_BIN="${HOME}/.cargo/bin/$TAURI_DRIVER_NAME" then
check -x and only then try
"${USERPROFILE:-$HOME}/.cargo/bin/$TAURI_DRIVER_NAME"), keeping the same -x
checks afterward.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ddfbe5cc-67ed-4690-8e6f-5895f1daf965
📒 Files selected for processing (1)
app/scripts/e2e-run-spec.sh
CodeRabbit caught that the Windows fallback
TAURI_DRIVER_BIN="${USERPROFILE:-$HOME}/.cargo/bin/$TAURI_DRIVER_NAME"
would expand to a Windows-style backslash path that bash's `-x` test
can't evaluate, so the script would falsely conclude the binary
"doesn't exist" even when it's installed.
Prefer $HOME (POSIX-friendly under git-bash) first. Only fall back to
$USERPROFILE if $HOME doesn't have the binary, converting via cygpath
when available so the result is still a POSIX path bash can stat.
Windows runs hit ECONNREFUSED on port 4723 because the config only
branched Linux vs default-to-Mac2:
- Capabilities: Windows fell through to the macOS Mac2 block and got
`platformName: mac` + Appium app caps, which Mac2 doesn't accept
and which wouldn't match a tauri-driver session anyway.
- Port: `isLinuxDriver ? 4444 : 4723` sent Windows to Appium's 4723
instead of tauri-driver's 4444.
Group Windows with Linux as a tauri-driver host:
- Capabilities → `[{ 'tauri:options': { application: getAppPath() } }]`
(the existing `getAppPath()` win32 branch already returns
`src-tauri/target/debug/OpenHuman.exe`).
- Driver port → 4444 (TAURI_DRIVER_PORT honoured as before).
- connectionRetry* → use the more generous Linux/CEF values since
Windows cold session creation has the same shape.
Renamed `isLinuxDriver` to `isTauriDriverHost` so the gate name matches
what it actually means now.
CI Prettier flagged the multi-line `const isTauriDriverHost = ...` declaration — the joined `process.platform === 'linux' || process.platform === 'win32'` expression is 78 chars, well under the 100-col print width, so Prettier collapses it to a single line. No behavior change.
The Windows tauri-driver session creation failed with `session not created: Microsoft Edge failed to start: crashed.` Root cause: on Windows, tauri-driver delegates to MSEdgeDriver to drive WebView2 — but OpenHuman's runtime is CEF (Chromium Embedded Framework), not WebView2. msedgedriver tries to launch Edge to attach to a WebView2 host that doesn't exist, and crashes. Same architectural incompatibility as Linux's webkit2gtk-driver ↔ CEF. Drop the smoke-spec run step (and the now-unused `cargo install tauri-driver`); keep the build step so Windows-breaking dep/config/Rust changes still fail the PR. Renamed to "E2E (Windows build only)" so the surface is honest, matching the existing Linux build-only leg.
Windows build kept failing with error[E0061]: sys.refresh_processes(...) takes 2 args but 1 was supplied --> src/openhuman/local_ai/install.rs:26:9 but neither `refresh_processes` nor `sysinfo` appears anywhere in src/openhuman/local_ai/install.rs on this branch (or in main). The file at line 26 is `String::from_utf8_lossy(&output.stderr),`. Diagnosis: Swatinem/rust-cache@v2 restored a target/ from an earlier state where `local_ai/install.rs` *did* call refresh_processes, and cargo cross-referenced that stale .rmeta during the fresh compile, producing a diagnostic that points at the new line text but with the old call's signature mismatch. Bumped the cache key to `e2e-windows-v2` so this run starts cold and the cache repopulates from the actual current sources.
…s (Windows build) sysinfo 0.33 changed the signature of refresh_processes to require a second bool arg (remove_dead_processes). The missing arg caused a compile error on the Windows e2e leg in GitHub Actions. Pass false to preserve the previous behaviour (dead-process entries are not pruned between calls).
# Conflicts: # src/openhuman/local_ai/install.rs
…macOS mega-spec scaffold (tinyhumansai#1532)
…macOS mega-spec scaffold (tinyhumansai#1532)\n
Summary
scripts/mock-api-core.mjsinto domain modules underscripts/mock-api/(state, http, socket, admin, server, plus 10 per-domain route files). Old path becomes a re-export shim — every existing caller (scripts/mock-api-server.mjs,app/test/e2e/mock-server.ts,scripts/test-rust-with-mock.sh) keeps working unchanged./version-check,/auth/email/send-link,/auth/telegram,/users,/teams/join,/conversations*,/messages*,/channels*,/notifications,/webhooks/ingress*,/settings/cron-jobs*,/settings/webhooks-triggers*,/payments/credits/{top-up,transactions,auto-recharge/cards/*},/agent-integrations/composio/{github/repos,tools},/agent-integrations/apify/runs/*./mock-oauth/<provider>(+/mock-<provider>-oauthlegacy alias) render a meta-refresh + JS auto-redirect toopenhuman://oauth/success?integrationId=…&provider=…, the desktop deep linkdesktopDeepLinkListeneralready handles. Plus/auth/<provider>/{callback,exchange}for backend-mediated flows. Knobs:oauthAutoRedirectMs,oauthIntegrationId,oauthForceError,oauthErrorCode; per-request overrides via?integrationId,?provider,?error,?manual=1.e2e-build.shinvoked the deletedscripts/stage-core-sidecar.mjs(removed in fix(core,cef): run core in-process and stop orphaning CEF helpers on Cmd+Q #1061 when core went in-process). Dropped the deadnodecall so e2e builds succeed.app/test/e2e/specs/mega-flow.spec.ts) + RPC token file handoff inapp/src-tauri/src/core_process.rs(debug-build only): writes the embedded core's bearer token to${tmpdir}/openhuman-e2e-rpc-tokenso the WDIO Node process can authenticate against the in-process RPC server.core-rpc-node.tsreads it and sendsAuthorization: Bearer …..github/workflows/e2e.ymlruns linux/macos/windows e2e in parallel — Linux reuses the existingghcr.io/tinyhumansai/openhuman_ci:latestimage (same oneunit-testsande2e/docker-compose.ymluse), macOS uses Appium Mac2 (canonical e2e runner), Windows uses tauri-driver/WebView2. All legscontinue-on-errorso flaky platforms don't block PRs.Problem
/mock-<provider>-oauth) returned a static<h1>and never completed the flow, so any spec that drives the OAuth click-through hung.pnpm test:e2e:buildcrashed withMODULE_NOT_FOUNDbecause it called a script deleted in fix(core,cef): run core in-process and stop orphaning CEF helpers on Cmd+Q #1061.test.yml(Linux + macOS) hadn't been touched since the CEF migration, and there was no Windows leg at all.Solution
trueif it consumed the request; the server walks them in order and 404s with aUNHANDLEDconsole log on miss (preserving the existing fail-fast contract).setMockBehavior.<meta http-equiv="refresh">and asetTimeoutJS redirect so it works whether the e2e harness drives the embedded webview, an external browser, or just inspects the URL via the OS.test.yml(unchanged) so the e2e cadence and the unit/rust cadence can evolve independently. Linux uses the existing CI image so we don't reinstall Xvfb/dbus/webkit2gtk-driver/tauri-driver on every run.Submission Checklist
pnpm test:unit(2042 tests) passes; manual curl smoke against the live mock covers admin + every route + every OAuth variant + the full Composio enable→list cycle; macOS smoke spec (smoke.spec.ts) passes 3/3 on Mac2.scripts/mock-api/**) which is exercised by every e2e spec that runs, plus the existing unit-test surface that imports throughmock-server.ts. The newcore-rpc-node.tsBearer plumbing is exercised by the mega-flow spec; the Tauri-side token write is debug-build-only and not in the release coverage gate.## Related— N/A per above.Impact
core_process.rsis new in shipped binaries; the#[cfg(debug_assertions)]gate means release builds never write the token file or reference the path.${tmpdir}/openhuman-e2e-rpc-tokenis gated by#[cfg(debug_assertions)]and never touched in release builds. Local-only access (tmpdir is per-user on macOS/Linux).scripts/mock-api-core.mjsis a re-export shim — every external caller still works without changes.Related
openhuman_core_mode = localin debug builds (or via an e2e marker file) soBootCheckGateskips the Local/Cloud picker on first launch. Without that, the mega-flow spec's deep-link consume call can't reach the mock because the embedded core never starts. Estimated ~15-line TS change inBootCheckGate.tsxto default tolocalwhenimport.meta.env.DEVis true.AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
feat/mock-api-split-and-gap-fillba1360ff7f3072fabab4a7d0b176ac35828f093dValidation Run
pnpm --filter openhuman-app format:check— passes (pre-push hook ran)pnpm typecheck— passes (pre-push hook ran)pnpm test:unit→ 2042 passed / 3 skipped (218 files)cargo fmt --checkon both manifests — clean (pre-push hook ran)Validation Blocked
command:bash app/scripts/e2e-run-spec.sh test/e2e/specs/mega-flow.spec.ts mega-flow(on macOS Mac2)error:mega-flow spec scenarios assert on mock request log, but the in-process core RPC server doesn't start becauseBootCheckGateshows a Local/Cloud picker on first launch (localStorage wiped by the e2e script every run), and CEF WebView is inaccessible to XCUITest on macOS so the picker can't be dismissed from the driver.impact:mega-flow.spec.ts will not pass until the BootCheckGate auto-default-to-local follow-up lands. Smoke spec (smoke.spec.ts) still passes 3/3 on Mac2 and proves the bundle + driver + mock all work. Documented in commitfeat(e2e): mega-spec scaffoldand in the## Relatedfollow-up note above.Behavior Changes
Parity Contract
scripts/mock-api-core.mjskeeps every existing import path working byte-identically. Unit tests confirm.Duplicate / Superseded PR Handling
Summary by CodeRabbit
Tests
Chores