Files
elizaos--eliza/packages/app/docs/EXTERNAL_API_MOCK_VALIDATION.md
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

5.6 KiB

External-API mock validation — ledger + pattern

The app's keyless ui-smoke lane mocks every external-API BFF endpoint with inline page.route fixtures in test/ui-smoke/helpers.ts. Those fixtures are hand-authored, so without a tie to the real API they silently drift from it. This is the standing answer to "are the external-API mocks validated against the real API?" and the pattern for making a new one validated.

The two boundaries

An external-API view plugin has two contract boundaries:

  1. UI ⇄ BFF — the DTO the view consumes. The helpers.ts mock emulates this.
  2. BFF ⇄ provider — the plugin's route handler parsing the real provider response into that DTO. This is the boundary that actually breaks when a provider changes its wire format.

A mock is only "validated" when the BFF parser is proven to produce the same contract-shaped DTO from a real recorded provider response — and ideally a live drift check confirms the recording is current.

The validated pattern (per plugin)

  1. src/__fixtures__/<api>-real.recorded.json — a real provider response captured from the live API (documented _source / _captured).
  2. src/__fixtures__/contract.ts — structural validators for each BFF DTO (stricter than the TS interface where it matters, e.g. numeric strings).
  3. src/routes.contract.test.tskeyless: replays the recorded real response through the actual route handler (injected fetchImpl) and asserts a contract-shaped DTO. Runs in every PR lane.
  4. src/routes.real.test.tsgated (<API>_LIVE_TEST=1 or TEST_LANE=post-merge): re-fetches the live API and asserts it still conforms, catching drift from the recording.
  5. The helpers.ts mock fixture must produce a DTO that passes the same validator.

Requirement for the pattern: the route handler must accept an injectable fetchImpl (Polymarket/Hyperliquid *RouteState). Plugins whose provider call is not injectable need that refactor first.

Tiers

  • validated — a recorded-real contract test (replays a captured real response through the real parser) AND a live-drift test (re-fetches the live API). The strongest tier; needs a public API.
  • contract-tested — a recorded-real contract test only (the parser is proven against a captured real response). No live-drift yet (key-gated, or the live call is awkward to make in CI).
  • researched-fixed — the shape was verified against the provider's current docs/schema and a real bug fixed, but there's no recorded-replay harness yet (the call isn't injectable).
  • validated-elsewhere — covered by a different real-backend harness.
  • unvalidated — inline fixtures only; no tie to the real API. The debt set.

Ledger

External API Provider host Public? Tier Evidence / next step
Polymarket gamma/clob/data-api.polymarket.com yes validated plugin-polymarket/src/routes.{contract,real}.test.ts. Fixed UI mock liquidity format.
Hyperliquid api.hyperliquid.xyz/info yes validated plugin-hyperliquid/src/routes.{contract,real}.test.ts.
Shopify Admin GraphQL 2025-04 no (store token) contract-tested plugin-shopify/src/routes.contract.test.ts + customer fields fixed to numberOfOrders/amountSpent (verified vs live 2025-04 docs). Next: gated live-refresh.
CoinGecko api.coingecko.com yes validated plugin-wallet/src/routes/wallet-market-overview.{contract,real}.test.ts — recorded /coins/markets replayed through the real route + live-drift.
Eliza Cloud cloud-api worker n/a validated-elsewhere packages/test/cloud-e2e boots the real cloud-api worker.
Block explorers bscscan/etherscan/solscan yes (key for some) unvalidated plugin-wallet. Public read endpoints → recorded contract test (next cheapest win).
Wallet RPC EVM/Solana RPC + token providers partial unvalidated Inline DTO fixtures, no recorded-real tie.
ElevenLabs api.elevenlabs.io no (key) unvalidated TTS/STT; gated recorded fixture + live-refresh.
Calendly api.calendly.com no (key) unvalidated plugin-calendly; gated recorded fixture.
Calendly api.calendly.com no (token) validated plugin-calendly/src/calendly-client.{contract,real}.test.ts — recorded v2 {resource}/{collection} shapes through the real normalizers + gated live (CALENDLY_LIVE_TEST=1 + token).
Strava www.strava.com no (OAuth) unvalidated gated recorded fixture.
Google (Calendar/Gmail/Drive/YouTube) googleapis.com no (OAuth) unvalidated gated recorded fixtures per surface.
ElevenLabs api.elevenlabs.io no (key) unvalidated TTS returns binary audio (no JSON parse); the /voices JSON list is the validation target.
Tavily web search @tavily/core SDK no (key) validated plugin-web-search/.../webSearchService.{contract,real}.test.ts — fixture typed as the SDK's TavilySearchResponse (compile-time drift guard) through the real normalizer + gated live (TAVILY_LIVE_TEST=1 + key).

Ratchet

test/external-api-mock-validation.test.ts enforces three things:

  1. every validated API keeps its routes.contract.test.ts + routes.real.test.ts;
  2. every contract-tested API keeps its recorded-contract test file; and
  3. the unvalidated debt set only shrinks.

To advance an API a tier: capture a real response, add the recorded-contract test (→ contract-tested), then add a live-drift/refresh test (→ validated), updating the sets in the gate. Public + injectable APIs (CoinGecko, block explorers) are the cheapest next wins.