Skip to content

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:

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:

  • fixtures generate values once per run and are shared by every case via ${name}, so login reuses exactly the user signup created — no second account.
  • depends_on skips login if signup didn't pass; logging in as a user that was never created would just be noise.
  • check makes 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:

bash
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):

bash
cd backend && ANTHROPIC_API_KEY=sk-ant-... \
  python -m app.cli run ../signup-login.tripwire.yaml

You 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:

  1. Reads the live DOM (title, URL, text, numbered interactive elements).
  2. Performs the action ("Open the sign-up page", "Click 'Create account'").
  3. After all steps, evaluates each expect and records a forced pass / fail verdict with the reason — deterministically when a check is 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_id and you've connected server logs, the issue also carries the backend error and a suggested fix. Triage it on the Issues board.

Next steps

Tripwire — AI-native, self-healing E2E testing. Terms · Privacy · Legal Notice