Compose fixtures and readable scenarios
Human verified
A human reviewed this page, but it may be out of date. Later edits may not have been reviewed.
Overview
Build test fixtures and write scenarios with clear inputs, actions, and expected results. See the test audit for coverage selection.
Build inputs without deciding expectations
Use builders for fresh data with explicit variations. Keep identities consistent and obtain opaque handles from their owners. For rejection cases, pass invalid input unchanged. Specify expectations independently: do not use the production classifier, or a copy of it, to calculate expected results. Fixtures may emulate an external protocol but must not replace the authorization or lifecycle behavior under test.
Captured state must be keyless. The released Gateway fixture
has device identity and config version keys removed; regenerate it the same
way using the image identified in its test.
The workspace node fixture
is a dedicated Harness's node state and workspace from the OpenClaw f8386bc7
runtime image (shared state schema 20). To record it, run openclaw setup --baseline
and one openclaw node run on that image as uid 1000. Then copy the database with
VACUUM INTO, delete its device_identities rows, vacuum it again and archive it
without the Git sample hooks. Each test run saves a new identity in the older row format.
Make cases easy to add and diagnose
Use named cases with independent mutable state. Share a contract suite when implementations promise the same behavior; keep implementation-specific cases separate. Register contract suites explicitly so fixture imports do not run unrelated tests. Start helpers in their owning domain and share them when another consumer needs the same contract.
Own resources and time
Register cleanup on acquisition, including partial setup. Stop admission, drain operations, then close dependencies and remove owned files. Attempt remaining cleanup after failure and preserve both setup and cleanup errors. Before remote creation, establish a cleanup or reconciliation obligation; a lost response does not prove failure or authorize replay. Bound cleanup and join processes and sockets; a timeout is not disposal.
Inject clocks for long-duration cases and use a real-time teardown watchdog. Preserve source-versus-built selection and real process or container boundaries in packaging tests. See the credential fixtures and credential testing guide for examples.
Hash fixture passwords cheaply
Build controllers in tests through the constructors in
tests/helpers/password-hasher.mjs. They inject a
salted SHA-256 hasher in place of the controller's scrypt, which costs about 0.1 CPU-second
per hash or sign-in. It still verifies scrypt hashes that production entry points wrote, such
as the bootstrap administrator's. Pass scryptPasswordHasher where hashing cost, timing or the
stored format is under test. Deployments cannot select another hasher: only code passes one.
Add properties where they improve coverage
Use constrained inputs, independent properties, execution with a time limit, reproducible counterexamples, and fresh state. Use an established library for generation and shrinking. Keep heavyweight Git and container workflows as selected integration scenarios.
