Your first test
With the backend and frontend running, let's author a suite and run it. We'll write the classic flow: a new user signs up, then logs in as that same user.
1. Author the suite
In the dashboard, open Tests and create a new suite — or PUT it through the API. A suite is plain-English YAML:
suite: "Signup & Login"
id: signup-login
base_url: http://localhost:8500
fixtures: # generated ONCE per run, shared across cases
email: { gen: unique_email }
password: { gen: password }
cases:
- id: signup
title: "A new user can sign up"
tags: [auth, smoke, p0]
steps:
- { id: s1, do: "Open the sign-up page" }
- { id: s2, do: "Enter ${email} and ${password}", secret: true }
- { id: s3, do: "Click 'Create account'" }
expect:
- { id: a1, assert: "a confirmation 'Account created' is shown",
check: { kind: visible_text, contains: "Account created" } }
- id: login
title: "That same user can log in"
tags: [auth, p0]
depends_on: signup # skipped if signup didn't pass
steps:
- { id: s1, do: "Open the login page" }
- { id: s2, do: "Enter ${email} and ${password}" } # the SAME generated user
- { id: s3, do: "Click 'Sign in'" }
expect:
- { id: a1, assert: "a welcome message is shown",
check: { kind: visible_text, contains: "Welcome back" } }Save this as signup-login.tripwire.yaml. (This is the real examples/suites/sample-signup-login.tripwire.yaml, runnable against the sample app.)
A few things worth noticing — all covered in Writing Tests:
fixturesgenerate values once per run and are shared by every case via${name}, sologinreuses exactly the usersignupcreated — no second account.depends_onskipsloginifsignupdidn't pass; logging in as a user that was never created would just be noise.checkmakes an assertion deterministic — verified directly against the page with no model call. Omit it and the model adjudicates a forced pass/fail.
Saving validates the YAML — an invalid suite is rejected with a 400 before it can run.
2. Run it
From the dashboard's Tests view, hit Run. Or start a run via the API:
curl -X POST http://127.0.0.1:8400/api/v1/runs \
-H 'Content-Type: application/json' \
-d '{"suite": "signup-login.tripwire.yaml"}'Or from the CLI (also the CI gate — see CI):
cd backend && ANTHROPIC_API_KEY=sk-ant-... \
python -m app.cli run ../signup-login.tripwire.yamlYou can pass file_issues (API) or --file-issues github (CLI) to file failures to a tracker for this run — see Filing issues.
3. Watch it run
Open the run in Runs. Cases execute in sequence in one shared browser session, streaming live progress. For each step the agent:
- Reads the live DOM (title, URL, text, numbered interactive elements).
- Performs the action ("Open the sign-up page", "Click 'Create account'").
- After all steps, evaluates each
expectand records a forced pass / fail verdict with the reason — deterministically when acheckis present, otherwise via the model adjudicating the page text + a screenshot.
How runs and assertions work in detail: Runs & assertions.
4. Read the report
When the run finishes you get a report of what worked, what failed, and why, plus report.json, junit.xml, and report.html artifacts.
- A passing suite stays green even through harmless UI churn, because the agent self-heals.
- A failing assertion produces a root-caused, deduped issue, filed to your configured destinations (built-in tracker, GitHub, GitLab, Jira). If the failing request carried a
trace_idand you've connected server logs, the issue also carries the backend error and a suggested fix. Triage it on the Issues board.
Next steps
- Master the suite format → Writing Tests
- See every check kind → Checks reference
- Test your own deployed app fast → Quick test a URL
- Understand the engine → Architecture
- Wire up your tracker → Filing issues