Browser Flow Tester
Unit tests prove functions work; they say nothing about whether a human can actually sign up, pay, or export their data. This skill drives a real browser through a user flow end to end — clicking what a user clicks, typing what a user types — and reports what actually happened, with evidence. It exists to answer one question with confidence: does the flow work right now, in this build, from the user's side of the screen?
When to use this skill
- Verifying a UI change actually works before it ships ("log in, add to cart, check out")
- Reproducing a bug report that only manifests through real interaction
- Smoke-testing critical paths after a deploy or a dependency upgrade
- Writing or repairing automated end-to-end tests around a flow
Workflow
- Write the flow as a script of user intentions first — "reach the dashboard as a new user", not "click the fourth button". Each step gets an expected, observable outcome. This script is the contract; the browser session merely executes it.
- Start from a known state: fresh session or explicit login, seeded or documented test data, viewport size stated. A flow test that inherits mystery state produces mystery results.
- Interact like a user, assert like an engineer. Prefer selectors tied to visible text, labels, or roles over brittle DOM positions. After every action, verify the expected outcome before proceeding — URL, visible text, element state. Never assume an action worked because no error was thrown.
- Wait on conditions, not clocks. Await the element, the network response, or the URL change. Fixed sleeps are how flaky tests are born; if one is unavoidable, log it as a defect in the test, not as a solution.
- Collect evidence as you go: a screenshot at meaningful checkpoints, console errors, and failed network requests. When a step fails, capture the state before retrying — evidence first, recovery second.
- On failure, localize before reporting. Distinguish: the app is broken (bug), the flow changed (test is stale), the environment is wrong (data or config), or the harness raced (timing). Re-run once to separate deterministic from flaky, and label which one you saw.
- Report the flow as a step table with pass or fail per step, evidence attached, and — for failures — the smallest reproduction: the step, the state, and the selector or response that diverged from expectation.
Output format
Flow: <name> Build/URL: <where> Viewport: <size>
1. <intention> — PASS (<observed outcome>)
2. <intention> — PASS
3. <intention> — FAIL: expected <outcome>, observed <actual>
Evidence: <screenshot ref>, console: <error>, network: <failed request>
Classification: app bug | stale flow | environment | flaky (reran: same/different)
Verdict: <flow works | broken at step N> — one-line summary
Guardrails
- Never mark a step passed on the absence of an error; passing requires the positive observation the script promised.
- Keep destructive actions (deletes, purchases, sends) inside test accounts and test data only. If you cannot confirm the account is disposable, stop and ask.
- One flow per report. "Login, checkout, and settings all mostly work" is three reports.
- Console errors during a passing flow are still findings — attach them as warnings rather than discarding them.
- When the markup forces brittle positional selectors, record it as UI testability debt in the report; the next person deserves the warning.