Testing with @reticlehq/test — declarative, signal-bound specs
Driving Reticle interactively is reconnaissance. To turn it into a repeatable, CI-runnable suite, write declarative specs with @reticlehq/test. Specs bind to signals and testids — never DOM structure — so they inherit Reticle’s refactor-resistance.
The test context t
A thin, typed façade over Reticle’s tools — it resolves testids → refs for you, so specs never touch refs or DOM:
Any failed matcher throws with the structured evidence (near-miss, failure reason) so the runner reports why.
Deterministic + honest
t.clockbakesreticle_clockinto the spec, so time-gated UI (a 5s auto-dismiss, a 500ms hover dwell) is tested deterministically instead of racing real timers.t.expectInputModeReal()— a hover/drag spec asserts native input is active; if it’s running synthetic (no CDP), the spec is skipped with a reason, never silently passing on a no-op. Enable real input headless withreticle drive(see usage §18).
Run a suite (headless, the same path CI uses)
bootSession launches a headless real-input browser at your app and gives the runner a programmatic tool invoker (no MCP/stdio):
pass | fail (with evidence) | skip (with reason). For CI, emit JUnit:
Flows become specs
.reticle/ flows (see Flows) can be executed directly as specs — replayed with their expect/success predicates and skipping dynamic (LLM-output) regions — so the recorded map and the suite can’t drift apart: