--- name: browser-flows description: Use when asked to test a web app, find bugs, verify a fix or a deploy in a real browser, or when a bug report says "I tapped X and the screen didn't change". Drives headless Chrome over the DevTools Protocol at phone width as a throwaway user, comparing the DOM with the API after every action and again after a reload. Also use when writing a regression test for a UI bug that unit tests cannot reach. --- # Browser flows Read-only walks of an app miss action bugs. The bugs worth finding sit between the UI, the cache, the router and the server: *the click worked but the screen didn't change*, *it saved but vanished on reload*, *the next user saw the last user's data*. A flow catches them by checking three things after every action: **the DOM, the API, and the DOM again after a reload.** The full method, with the step wrapper and a trap table, is `workflows/browser-flow-testing.md`. This skill is the short version plus the tools. ## Tools in this skill - `scripts/cdp.mjs` — a ~150-line CDP driver, no dependencies (Node 22+ and Chrome). Headless, fresh profile, 390 × 844, attaches to Web Workers too. API: `goto reload eval waitFor clickText type screenshot block offline requests problems close`. - `scripts/example-flow.mjs` — signup → create → API check → reload → offline queue. Copy it and change the selectors and routes. Copy both into the target repo at `scripts/browser-flows/` and add a README listing each flow, what it covers, and whether it is safe on production. ## Rules 1. **Headless and isolated.** A fresh `mktemp -d` profile per run; never drive the user's own browser window or account. 2. **Fresh user per run** (`flow-@example.com`). If a flow must run on production, use one dedicated test account and refuse any login that is not `@example.com`. 3. **Destructive or dev-only flows refuse the production origin** (password changes, deletes, anything that reads a dev-only field like `devCode`). 4. **DOM → API → reload → DOM** after every write. 5. **Wait on the element that changes**, never on toast text. 6. **Print `problems()` after every step** — console errors, exceptions and HTTP ≥ 400 are findings even when the step passed. 7. **A regression flow must fail on the old code.** Prove it once by reverting the fix. 8. Always cover: 390 px width (no sideways scroll, targets ≥ 40 px), network cut, navigate-away-and-back, logout then login as someone else, every view toggle, light/dark. ## Traps (the short list) - Headless Chrome **paints only when asked**: rAF callbacks and lazy images wait for a frame. Call `screenshot()` to force one, then wait. - Radix-style menus/tabs open on **pointerdown/mousedown** — `clickText` sends those before `click()`. - "Today" in test data: use `toLocaleDateString("en-CA")`, not `toISOString()` (UTC) — otherwise every flow fails after local midnight. - Auth rate limits: space signup-heavy flows about a minute apart, or raise the limit on the dev server only. - A worker's requests don't show on the page target — the driver auto-attaches. - After a deploy, a service worker may serve the previous build: fresh profile. - Check API URLs that have a file extension with a cookie-less `curl -sI`: a CDN may cache them (`cf-cache-status: HIT` on user data is a leak). - Parallel runs: distinct `CDP_PORT` and profile directory each.