--- name: gstack version: 1.1.0 description: | Fast headless browser for QA testing and site dogfooding. Navigate any URL, interact with elements, verify page state, diff before/after actions, take annotated screenshots, check responsive layouts, test forms and uploads, handle dialogs, and assert element states. ~100ms per command. Use when you need to test a feature, verify a deployment, dogfood a user flow, or file a bug with evidence. allowed-tools: - Bash - Read --- # gstack browse: QA Testing & Dogfooding Persistent headless Chromium. First call auto-starts (~3s), then ~100-200ms per command. Auto-shuts down after 30 min idle. State persists between calls (cookies, tabs, sessions). ## SETUP (run this check BEFORE any browse command) ```bash B=$(browse/bin/find-browse 2>/dev/null || ~/.claude/skills/gstack/browse/bin/find-browse 2>/dev/null) if [ -n "$B" ]; then echo "READY: $B" else echo "NEEDS_SETUP" fi ``` If `NEEDS_SETUP`: 1. Tell the user: "gstack browse needs a one-time build (~10 seconds). OK to proceed?" Then STOP and wait. 2. Run: `cd && ./setup` 3. If `bun` is not installed: `curl -fsSL https://bun.sh/install | bash` ## IMPORTANT - Use the compiled binary via Bash: `$B ` - NEVER use `mcp__claude-in-chrome__*` tools. They are slow and unreliable. - Browser persists between calls — cookies, login sessions, and tabs carry over. - Dialogs (alert/confirm/prompt) are auto-accepted by default — no browser lockup. ## QA Workflows ### Test a user flow (login, signup, checkout, etc.) ```bash B=~/.claude/skills/gstack/browse/dist/browse # 1. Go to the page $B goto https://app.example.com/login # 2. See what's interactive $B snapshot -i # 3. Fill the form using refs $B fill @e3 "test@example.com" $B fill @e4 "password123" $B click @e5 # 4. Verify it worked $B snapshot -D # diff shows what changed after clicking $B is visible ".dashboard" # assert the dashboard appeared $B screenshot /tmp/after-login.png ``` ### Verify a deployment / check prod ```bash $B goto https://yourapp.com $B text # read the page — does it load? $B console # any JS errors? $B network # any failed requests? $B js "document.title" # correct title? $B is visible ".hero-section" # key elements present? $B screenshot /tmp/prod-check.png ``` ### Dogfood a feature end-to-end ```bash # Navigate to the feature $B goto https://app.example.com/new-feature # Take annotated screenshot — shows every interactive element with labels $B snapshot -i -a -o /tmp/feature-annotated.png # Find ALL clickable things (including divs with cursor:pointer) $B snapshot -C # Walk through the flow $B snapshot -i # baseline $B click @e3 # interact $B snapshot -D # what changed? (unified diff) # Check element states $B is visible ".success-toast" $B is enabled "#next-step-btn" $B is checked "#agree-checkbox" # Check console for errors after interactions $B console ``` ### Test responsive layouts ```bash # Quick: 3 screenshots at mobile/tablet/desktop $B goto https://yourapp.com $B responsive /tmp/layout # Manual: specific viewport $B viewport 375x812 # iPhone $B screenshot /tmp/mobile.png $B viewport 1440x900 # Desktop $B screenshot /tmp/desktop.png ``` ### Test file upload ```bash $B goto https://app.example.com/upload $B snapshot -i $B upload @e3 /path/to/test-file.pdf $B is visible ".upload-success" $B screenshot /tmp/upload-result.png ``` ### Test forms with validation ```bash $B goto https://app.example.com/form $B snapshot -i # Submit empty — check validation errors appear $B click @e10 # submit button $B snapshot -D # diff shows error messages appeared $B is visible ".error-message" # Fill and resubmit $B fill @e3 "valid input" $B click @e10 $B snapshot -D # diff shows errors gone, success state ``` ### Test dialogs (delete confirmations, prompts) ```bash # Set up dialog handling BEFORE triggering $B dialog-accept # will auto-accept next alert/confirm $B click "#delete-button" # triggers confirmation dialog $B dialog # see what dialog appeared $B snapshot -D # verify the item was deleted # For prompts that need input $B dialog-accept "my answer" # accept with text $B click "#rename-button" # triggers prompt ``` ### Test authenticated pages (import real browser cookies) ```bash # Import cookies from your real browser (opens interactive picker) $B cookie-import-browser # Or import a specific domain directly $B cookie-import-browser comet --domain .github.com # Now test authenticated pages $B goto https://github.com/settings/profile $B snapshot -i $B screenshot /tmp/github-profile.png ``` ### Compare two pages / environments ```bash $B diff https://staging.app.com https://prod.app.com ``` ### Multi-step chain (efficient for long flows) ```bash echo '[ ["goto","https://app.example.com"], ["snapshot","-i"], ["fill","@e3","test@test.com"], ["fill","@e4","password"], ["click","@e5"], ["snapshot","-D"], ["screenshot","/tmp/result.png"] ]' | $B chain ``` ## Quick Assertion Patterns ```bash # Element exists and is visible $B is visible ".modal" # Button is enabled/disabled $B is enabled "#submit-btn" $B is disabled "#submit-btn" # Checkbox state $B is checked "#agree" # Input is editable $B is editable "#name-field" # Element has focus $B is focused "#search-input" # Page contains text $B js "document.body.textContent.includes('Success')" # Element count $B js "document.querySelectorAll('.list-item').length" # Specific attribute value $B attrs "#logo" # returns all attributes as JSON # CSS property $B css ".button" "background-color" ``` ## Snapshot System The snapshot is your primary tool for understanding and interacting with pages. ``` -i Interactive elements only (buttons, links, inputs) with @e refs -c Compact (no empty structural nodes) -d Limit depth -s Scope to CSS selector -D Diff against previous snapshot (what changed?) -a Annotated screenshot with ref labels -o Output path for screenshot -C Cursor-interactive elements (@c refs — divs with pointer, onclick) ``` Combine flags: `$B snapshot -i -a -C -o /tmp/annotated.png` After snapshot, use @refs everywhere: ```bash $B click @e3 $B fill @e4 "value" $B hover @e1 $B html @e2 $B css @e5 "color" $B attrs @e6 $B click @c1 # cursor-interactive ref (from -C) ``` Refs are invalidated on navigation — run `snapshot` again after `goto`. ## Command Reference ### Navigation | Command | Description | |---------|-------------| | `back` | History back | | `forward` | History forward | | `goto ` | Navigate to URL | | `reload` | Reload page | | `url` | Print current URL | ### Reading | Command | Description | |---------|-------------| | `accessibility` | Full ARIA tree | | `forms` | Form fields as JSON | | `html [selector]` | innerHTML | | `links` | All links as "text → href" | | `text` | Cleaned page text | ### Interaction | Command | Description | |---------|-------------| | `click ` | Click element | | `cookie` | Set cookie | | `cookie-import ` | Import cookies from JSON file | | `cookie-import-browser [browser] [--domain d]` | Import cookies from real browser (opens picker UI, or direct with --domain) | | `dialog-accept [text]` | Auto-accept next alert/confirm/prompt | | `dialog-dismiss` | Auto-dismiss next dialog | | `fill ` | Fill input | | `header ` | Set custom request header | | `hover ` | Hover element | | `press ` | Press key (Enter, Tab, Escape, etc.) | | `scroll [sel]` | Scroll element into view | | `select ` | Select dropdown option | | `type ` | Type into focused element | | `upload ` | Upload file(s) | | `useragent ` | Set user agent | | `viewport ` | Set viewport size | | `wait ` | Wait for element/condition | ### Inspection | Command | Description | |---------|-------------| | `attrs ` | Element attributes as JSON | | `console [--clear|--errors]` | Console messages (--errors filters to error/warning) | | `cookies` | All cookies as JSON | | `css ` | Computed CSS value | | `dialog [--clear]` | Dialog messages | | `eval ` | Run JS file | | `is ` | State check (visible/hidden/enabled/disabled/checked/editable/focused) | | `js ` | Run JavaScript | | `network [--clear]` | Network requests | | `perf` | Page load timings | | `storage [set k v]` | localStorage + sessionStorage | ### Visual | Command | Description | |---------|-------------| | `diff ` | Text diff between pages | | `pdf [path]` | Save as PDF | | `responsive [prefix]` | Mobile/tablet/desktop screenshots | | `screenshot [path]` | Save screenshot | ### Snapshot | Command | Description | |---------|-------------| | `snapshot [flags]` | Accessibility tree with @refs | ### Meta | Command | Description | |---------|-------------| | `chain` | Multi-command from JSON stdin | ### Tabs | Command | Description | |---------|-------------| | `closetab [id]` | Close tab | | `newtab [url]` | Open new tab | | `tab ` | Switch to tab | | `tabs` | List open tabs | ### Server | Command | Description | |---------|-------------| | `restart` | Restart server | | `status` | Health check | | `stop` | Shutdown server | ## Tips 1. **Navigate once, query many times.** `goto` loads the page; then `text`, `js`, `screenshot` all hit the loaded page instantly. 2. **Use `snapshot -i` first.** See all interactive elements, then click/fill by ref. No CSS selector guessing. 3. **Use `snapshot -D` to verify.** Baseline → action → diff. See exactly what changed. 4. **Use `is` for assertions.** `is visible .modal` is faster and more reliable than parsing page text. 5. **Use `snapshot -a` for evidence.** Annotated screenshots are great for bug reports. 6. **Use `snapshot -C` for tricky UIs.** Finds clickable divs that the accessibility tree misses. 7. **Check `console` after actions.** Catch JS errors that don't surface visually. 8. **Use `chain` for long flows.** Single command, no per-step CLI overhead.