Advanced / Workflow

Testing & Dogfood

Even though both drive a browser, testing comes in two very different flavors: one freezes repetitive manual checks into a rerunnable regression suite, like frontend unit tests; the other systematically walks the whole app like a real user, digging out bugs and UX problems and bringing along complete reproduction evidence. chrome-use does both — the former with chrome-use test, the latter with a dogfood exploratory flow.

Two flavors of testing

First figure out which one you're doing, then pick the section below. Their goals, outputs, and how they run are all different.


Write a rerunnable test suite

Turn the repetitive manual chore of "open it, click around, confirm it's right" into a rerunnable suite, just like frontend unit tests. Every time you find a regression, add a case — the more you use it, the more the suite is worth.

Run a suite
$ chrome-use test <suite.yaml> [--launch | --session <name>] [--json]

Suite format (YAML)

A suite is made of an optional setup (run once before all cases) and a list of cases. Each case has steps (the actions to perform) and assert (the checks that must hold).

chatgpt-smoke.yaml
suite: chatgpt smoke               # label (optional)
setup:                             # run once before all cases (optional)
  - account: chatgpt/huayue        # inject a cookie-use saved login (optional)
  - open: https://chatgpt.com/     # …or any normal step
cases:
  - name: home loads logged in
    steps:                         # steps reuse chrome-use's own commands
      - open: https://chatgpt.com/
      - wait: { load: networkidle }
    assert:                        # every assertion must hold for the case to pass
      - url: { contains: chatgpt.com }
      - visible: "#prompt-textarea"
  - name: composer takes text
    steps:
      - fill: { sel: "#prompt-textarea", text: "hi" }
    assert:
      - text: { sel: "#prompt-textarea", contains: hi }
      - eval: "!!window.__NEXT_DATA__"

Steps — actions

Each step is a "single-key map" whose key is a chrome-use command.

StepMeaning
open: <url>navigate
click: <selector|@ref>click
fill: { sel: <s>, text: <t> }clear then type
type: { sel: <s>, text: <t> }type (without clearing)
press: <key>key press (e.g. Enter)
wait: <ms> / wait: { load: networkidle } / wait: <selector>wait
scroll: <up|down|...> or { dir: down, px: 500 }scroll
eval: "<js>"run JS

Assertions — checks

Every assertion ultimately compiles down to a truthy eval.

AssertPasses when
url: { contains|equals|matches: <v> }page URL matches
visible: <selector>element exists and is laid out
hidden: <selector>element is absent / not laid out
text: { sel: <s>, contains|equals|matches: <v> }element text matches
count: { sel: <s>, eq: <n> }exactly N elements match
eval: "<js>"the JS expression is truthy
ℹ️ How assertions relate to steps
steps all run in order first, then assert is evaluated one by one, independently. For more ways to write wait and assertions, see Waiting & Asserting; every command used in steps is covered in the Command Reference.
✅ Outside a suite: the expect verb
Don't want a whole YAML suite, just an assertion inside a string of commands? chrome-use expect <condition> is the command-line sibling of a suite's assert: — same contract, exit 0 when it holds, 1 when it doesn't, so it chains straight into a shell: chrome-use click @save && chrome-use expect "#toast" visible. It polls until the condition holds or it times out. To write a whole "click this, fill that, assert" flow as a single pass, see Single-pass scripting.

Login and multiple accounts

account: <id> injects a cookie-use saved login into the test session. It can be used in two places:

rbac.yaml — permission comparison
setup:
  - account: myapp/admin           # start as admin
cases:
  - name: admin sees the settings tab
    steps:
      - open: https://app.example.com/
    assert:
      - visible: "#settings-tab"
  - name: member does NOT see it
    steps:
      - account: myapp/member      # switch account; takes effect on next open
      - open: https://app.example.com/
    assert:
      - hidden: "#settings-tab"
  - name: back to admin
    steps:
      - account: myapp/admin
      - open: https://app.example.com/
    assert:
      - visible: "#settings-tab"
⚠️ Requires cookie-use
account: relies on an installed cookie-use; if you don't use it, just leave the line out. A failed account: switch (wrong id, or cookie-use not installed) fails that case and gives a clear reason. For more account details see Login & Credentials.

Workflow

  1. First do it by hand with open/snapshot/eval to nail down the selectors.
  2. Write it up as a case and put it in a *.yaml suite.
  3. chrome-use test suite.yaml — green means all good; red shows the failing assertion + a screenshot.
  4. Find another regression later? Add a case. Run the whole suite in CI.
ℹ️ v1 limitations
Assertions are evaluated independently after the steps run. For now there is no per-case retry, no parallel cases, and no snapshot/screenshot baseline diff (use an eval assertion against known content instead). Steps run in order, and a failing step fails the case immediately.

Exploratory testing & bug hunting (dogfood)

The other kind of testing has no predefined script; instead it systematically walks a web app end to end, finding bugs, UX issues, and other glitches, and producing complete reproduction evidence for each finding — step-by-step screenshots, a reproduction recording, detailed repro steps — so the results can be handed straight to the relevant team.

✅ Only a target URL is required
Everything else can take a default: name the session after the domain slug (vercel.comvercel-com), put output under ./dogfood-output/, and let the scope be the whole app. Pick a target URL and you're ready to go; only sites that need a login call for account credentials. The examples below all use the session dogfood, the directory dogfood-output/, and the target https://vercel.com — swap in your own.
⚠️ Use chrome-use, not npx chrome-use
Always call chrome-use directly — the binary uses the fast Rust client; npx detours through Node.js and is noticeably slower.

The six-step flow

StepWhat it does
1. Initializecreate the session, output directory, report file
2. Authenticatelog in if needed, save the state
3. Orientnavigate to the starting point, take the first snapshot
4. Exploresystematically visit pages, test features
5. Documentscreenshot + record every issue as you find it
6. Wrap upupdate the summary counts, close the session

Initialize and log in

Initialize + start the session
$ mkdir -p dogfood-output/screenshots dogfood-output/videos

# start a named session, navigate to the target
$ chrome-use --session dogfood open https://vercel.com
$ chrome-use --session dogfood wait --load networkidle

When login is required, use snapshot -i to find the form's @ref, fill it in and submit, then save the state for reuse. For OTP / email verification codes, ask the user and only enter them after they reply.

Log in and save state
$ chrome-use --session dogfood snapshot -i
# find the login form's refs, fill in the credentials
$ chrome-use --session dogfood fill @e1 "you@example.com"
$ chrome-use --session dogfood fill @e2 "your-password"
$ chrome-use --session dogfood click @e3
$ chrome-use --session dogfood wait --load networkidle

# after a successful login, save the state for reuse
$ chrome-use --session dogfood state save dogfood-output/auth-state.json

Explore and gather evidence

Start from the main navigation and visit the top-level sections one by one; within each section test the interactive elements (click buttons, fill forms, open dropdowns/dialogs); check empty states, error handling, boundary inputs; and run real end-to-end flows (create, update, delete).

⚠️ console / errors are empty by default
This stealth fork disables console and error capture by default. To use console/errors, start the session with AGENT_BROWSER_CAPTURE_CONSOLE=1, for example AGENT_BROWSER_CAPTURE_CONSOLE=1 chrome-use --session dogfood open <url>, otherwise they return empty.
The four-hit combo for every page
$ chrome-use --session dogfood snapshot -i
$ chrome-use --session dogfood screenshot --annotate dogfood-output/screenshots/dashboard.png
$ chrome-use --session dogfood errors
$ chrome-use --session dogfood console
✅ Pick the right snapshot mode
snapshot -i — find clickable/fillable elements (buttons, inputs, links); snapshot (no flag) — read page content (text, headings, data lists).

Repro first: interactive vs static

Exploring and documenting happen in the same pass: when you find an issue, stop and record it immediately, then continue. Match the evidence granularity to the issue type.

Interactive / behavioral issues

These need user interaction to reproduce (features, UX, action-triggered console errors) — use full repro with a recording and step-by-step screenshots: start recording first, then walk the steps at a human pace, screenshot each step, and finally capture the broken state.

Recording + step-by-step screenshots
# 1. start recording before the repro
$ chrome-use --session dogfood record start dogfood-output/videos/issue-001-repro.webm

# 2. walk the steps at a human pace, pause 1-2s between actions, screenshot each step
$ chrome-use --session dogfood screenshot dogfood-output/screenshots/issue-001-step-1.png
$ sleep 1
# perform the action (click / fill etc.), sleep 1, then step-2 screenshot…

# 3. capture the broken state (pause first so the viewer can see it)
$ sleep 2
$ chrome-use --session dogfood screenshot --annotate dogfood-output/screenshots/issue-001-result.png

# 4. stop recording
$ chrome-use --session dogfood record stop

Static / visible-on-load issues

These are visible without interaction (typos, placeholder text, truncated text, misalignment, console errors thrown on load) — a single annotated screenshot is enough, no recording, no multi-step repro; set "reproduction recording" to N/A.

Static issue: one annotated screenshot
$ chrome-use --session dogfood screenshot --annotate dogfood-output/screenshots/issue-002.png

What the report looks like

Every finding collects into one Markdown report (say dogfood-output/report.md): a severity-bucketed summary count at the top, then one ### ISSUE- block per issue carrying its severity, page, repro steps, and evidence file paths.

dogfood-output/report.md
# Dogfood report · vercel.com

## Summary
- Critical: 0
- Major: 1
- Minor: 1

### ISSUE-001 · [Major] Toast never dismisses after save
- Page: /dashboard/settings
- Repro:
  1. Open Settings, rename, click Save
  2. Wait 5s
- Expected: toast dismisses after ~3s
- Actual: toast stays forever
- Evidence: screenshots/issue-001-result.png, videos/issue-001-repro.webm

### ISSUE-002 · [Minor] Footer copyright year still says 2019
- Page: /
- Evidence: screenshots/issue-002.png (repro recording: N/A)

Wrap up

The goal is to find 5–10 well-documented issues and stop — depth of evidence matters more than count; 5 with full repro beat 20 vague ones. Then reread the report, update the severity counts at the top (every ### ISSUE- block must be reflected in the summary totals), and finally close the session.

Close the session
$ chrome-use --session dogfood close

A few hard rules

⚠️ Don't read the app under test's source
You're testing as a user, not auditing code. Don't read the tested app's HTML/JS/config. Every finding must come from what you observe in the browser.

What's next