Tests
- Full testing kit (suites, live, Docker): Testing
-
pnpm test:force: Kills any lingering gateway process holding the default control port, then runs the full Vitest suite with an isolated gateway port so server tests don’t collide with a running instance. Use this when a prior gateway run left port 18789 occupied. -
pnpm test:coverage: Runs the unit suite with V8 coverage (viavitest.unit.config.ts). Global thresholds are 70% lines/branches/functions/statements. Coverage excludes integration-heavy entrypoints (CLI wiring, gateway/telegram bridges, webchat static server) to keep the target focused on unit-testable logic. -
pnpm testruns two stages: firstpnpm test:scripts(node --test "scripts/**/*.test.mjs", the release/CI policy suites), and only if that passes,node scripts/test-parallel.mjs. Atest:scriptsfailure short-circuits the&&and no Vitest lane runs at all. -
scripts/test-parallel.mjsthen runs the enabled lanes in two groups. Parallel: unit, core, channels, extensions, and gateway (gateway is serial unlessOPENCLAW_TEST_PARALLEL_GATEWAY=1or a high-memory local host). Serial, after the parallel group: e2e, plus gateway when it is not parallelized. Every lane is default-on; setOPENCLAW_TEST_INCLUDE_CORE=0,OPENCLAW_TEST_INCLUDE_CHANNELS=0,OPENCLAW_TEST_INCLUDE_EXTENSIONS=0,OPENCLAW_TEST_INCLUDE_GATEWAY=0, orOPENCLAW_TEST_INCLUDE_E2E=0to skip one. The parallel lanes all run to completion, then the runner exits with the first nonzero lane code before starting the serial group. So a failing run with no e2e output either failedtest:scriptsbefore any lane started, or failed in the parallel group — e2e was never reached, not skipped. -
Dedicated commands still exist for a single lane:
pnpm test:channels,pnpm test:extensions,pnpm test:gateway,pnpm test:e2e. -
pnpm test:e2e(also the serial e2e lane insidepnpm test): gateway end-to-end smoke (multi-instance WS/HTTP/node pairing).vitest.e2e.config.tsusespool: "forks"— notvmForks, because vmForks leaked thevi.mockmodule registry across files in a shared worker — with 1 worker locally and at most 2 in CI, silent unlessOPENCLAW_E2E_VERBOSE=1. Tune withOPENCLAW_E2E_WORKERS=<n>(capped at 16). Files come fromtest/**,src/**, andextensions/**matching*.e2e.test.ts. -
pnpm teston Node 24+: OpenClaw auto-disables VitestvmForksand usesforksto avoidERR_VM_MODULE_LINK_FAILURE/module is already linked. You can force behavior withOPENCLAW_TEST_VM_FORKS=0|1. -
pnpm test:live: Runs provider live tests (minimax/zai). Requires API keys andLIVE=1(or provider-specific*_LIVE_TEST=1) to unskip.
Local PR gate
For local PR land/gate checks, run:pnpm checkpnpm buildpnpm testpnpm check:docs
pnpm test flakes on a loaded host, rerun once before treating it as a regression, then isolate with pnpm vitest run <path/to/test>. For memory-constrained hosts, use:
OPENCLAW_TEST_PROFILE=low OPENCLAW_TEST_SERIAL_GATEWAY=1 pnpm test
Model latency bench (local keys)
Script:scripts/bench-model.ts
Usage:
source ~/.profile && pnpm tsx scripts/bench-model.ts --runs 10- Optional env:
MINIMAX_API_KEY,MINIMAX_BASE_URL,MINIMAX_MODEL,ANTHROPIC_API_KEY - Default prompt: “Reply with a single word: ok. No punctuation or extra text.”
- minimax median 1279ms (min 1114, max 2431)
- opus median 2454ms (min 1224, max 3170)
CLI startup bench
Script:scripts/bench-cli-startup.ts
Usage:
pnpm tsx scripts/bench-cli-startup.tspnpm tsx scripts/bench-cli-startup.ts --runs 12pnpm tsx scripts/bench-cli-startup.ts --entry dist/entry.js --timeout-ms 45000
--version--helphealth --jsonstatus --jsonstatus
Onboarding E2E (Docker)
Docker is optional; this is only needed for containerized onboarding smoke tests. Full cold-start flow in a clean Linux container:openclaw health.
QR import smoke (Docker)
Ensuresqrcode-terminal loads under Node 24+ in Docker: