qa-use

Installation
SKILL.md

qa-use

E2E testing and browser automation for AI-driven development workflows.

Critical Insight: Plugin Commands as Shortcuts

For AI Harnesses (codex, opencode, etc.):

Plugin commands (slash commands like /qa-use:verify) are convenience shortcuts that wrap CLI workflows. Harnesses with only the Bash tool can access ALL functionality via CLI commands documented below.

Pattern throughout this document:

  • CLI Workflow: Step-by-step CLI commands (works for ALL harnesses)
  • Plugin Shortcut: Optional slash command (convenience)

Setup & Configuration

Before using any qa-use commands, verify configuration is in place:

# Check current configuration (no-op if already configured)
qa-use setup

# Configure with API key (validates against server)
qa-use setup --api-key <key>

# View full configuration details
qa-use info

Environment Variables (alternative to config file):

Variable Description
QA_USE_API_KEY API key for authentication
QA_USE_REGION Region: us (default) or auto
QA_USE_API_URL Override API base URL

Config file: .qa-use.json in the project directory or ~/.qa-use.json in the home directory. Precedence: env vars > project .qa-use.json > ~/.qa-use.json.

If you encounter "API key not configured", 401, or auth errors: Run qa-use setup to check config state. NEVER fabricate or guess API keys.

Core Workflow

1. Browser Control & Session Lifecycle

CLI Workflow:

# Create browser session (returns immediately — runs detached in the background)
qa-use browser create --viewport desktop

# For localhost testing — auto-tunnels when base URL is localhost and API is remote.
# No flag needed for the common case:
qa-use browser create --no-headless http://localhost:3000

# Force a tunnel even in dev mode:
qa-use browser create --tunnel on --no-headless

# Opt out of auto-tunnel (e.g. backend is also local):
qa-use browser create --no-tunnel

# Navigate
qa-use browser goto https://example.com

# Snapshot to get element refs (ALWAYS do this before interacting)
qa-use browser snapshot

# Interact by ref
qa-use browser click e3
qa-use browser fill e5 "text"

# Close
qa-use browser close

Background session management:

qa-use browser create returns immediately — the actual browser + tunnel run in a detached child process so your terminal stays free. Manage sessions with:

qa-use browser status --list   # Show all active sessions across processes
qa-use browser status           # Details for the auto-resolved session
qa-use browser close <id>       # Close a specific session
qa-use doctor                   # Reap stale sessions/tunnels (dead PIDs)
qa-use doctor --dry-run         # Preview what would be cleaned

Tunnel commands:

Cross-process tunnel registry — multiple commands share a single tunnel per target:

qa-use tunnel start <url>         # Acquire a tunnel (released immediately unless --hold)
qa-use tunnel start <url> --hold  # Keep the tunnel up until Ctrl+C
qa-use tunnel ls                  # List active tunnels (target, public URL, refcount)
qa-use tunnel status <target>     # Detail for a single tunnel
qa-use tunnel close <target>      # Force-release a tunnel (kills detached holders)

Plugin Shortcut:

/qa-use:explore https://example.com

(Wraps create + goto + snapshot with autonomous exploration)

Critical: Always run snapshot before your first interaction on a page. Never guess element refs.

Snapshot Diff Feature (use it to avoid unnecessary snapshots): After each action (goto, click, fill, etc.), the browser automatically shows DOM changes:

  • Summary: "5 elements added, 1 element modified"
  • Added elements: + [e54] generic "Thanks for agreeing!" (green)
  • Modified elements: ~ [e18] checkbox "I agree..." with +attrs: checked, active (yellow)
  • Removed elements: - [e99] button "Submit" (red)

When you can skip a full snapshot: If the diff output from your last action already shows the element ref you need to interact with next, use it directly — no need for an intermediate snapshot. For example, if clicking a button shows + [e54] button "Submit" in the diff, you can click e54 immediately.

When you still need a full snapshot: Run snapshot when you need to find elements that weren't in the diff (e.g., pre-existing elements you haven't interacted with yet), or when the diff was truncated (shows "... and N more changes").

2. Understanding Blocks

What are blocks?

Blocks are atomic recorded interactions from a browser session. They are:

  • Automatically captured during any browser interaction (click, fill, goto, scroll, etc.)
  • Stored server-side with the session
  • Retrieved via qa-use browser get-blocks
  • The foundation for test generation

Why blocks matter:

  • Record-once, replay-many: Interactive recording becomes automated test
  • AI-friendly: Agents can analyze blocks to understand user intent
  • Version control: Blocks stored with session enable test iteration
  • Bridge CLI → Tests: Natural workflow from exploration to automation

How blocks work:

# 1. Create session and interact (auto-tunnels localhost)
qa-use browser create --no-headless
qa-use browser goto https://example.com
qa-use browser snapshot        # Returns: [ref=e1] button
qa-use browser click e1        # Records as block
qa-use browser fill e5 "text"  # Records as block

# 2. Retrieve blocks (JSON array)
qa-use browser get-blocks
# Returns:
# [
#   {"type": "goto", "url": "...", "timestamp": "..."},
#   {"type": "click", "ref": "e1", "timestamp": "..."},
#   {"type": "fill", "ref": "e5", "value": "text", "timestamp": "..."}
# ]

# 3. Generate test YAML from blocks
qa-use browser generate-test -n "my_test" -o qa-tests/my_test.yaml

# 4. Run generated test
qa-use test run my_test

Plugin Shortcut:

/qa-use:record start my_test
# ... perform interactions ...
/qa-use:record stop

(Wraps the interactive workflow with AI-powered test generation)

3. Test Management

CLI Workflow:

# Run test by name
qa-use test run login

# Run and save the (non-synced) local test to cloud
qa-use test run login --persist

# Validate syntax
qa-use test validate login

# Show test details
qa-use test info login

# List test runs
qa-use test runs --status failed

Plugin Shortcut:

/qa-use:test-run login

(Convenience shortcut for common test execution)

4. Test Variables (Imperative Edit)

Quick set/unset for the typed variables: block on a single test — useful when you don't want to round-trip the full YAML.

CLI Workflow:

# Local YAML file — Document API preserves comments + key order
qa-use test vars list  qa-tests/login.yaml
qa-use test vars list  qa-tests/login.yaml --json
qa-use test vars set   qa-tests/login.yaml --key user --value alice
qa-use test vars set   qa-tests/login.yaml --key url --value https://x \
                                          --type url --lifetime all
qa-use test vars set   qa-tests/login.yaml --key password --value hunter2 --sensitive
qa-use test vars set   qa-tests/login.yaml --key password --sensitive  # preserves stored value
qa-use test vars unset qa-tests/login.yaml --key user

# Remote --id fallback — exports YAML, mutates, re-imports (best-effort RMW)
qa-use test vars list  --id <uuid>
qa-use test vars set   --id <uuid> --key user --value alice
qa-use test vars unset --id <uuid> --key user

Rules:

  • Mutual exclusion: pass either <file> or --id, not both. Neither → exit 1.
  • --id requires a full UUID (use qa-use test list --query <name> to find one).
  • Form upgrade: passing only --key/--value writes simple form (key: value). Any of --type/--lifetime/--context/--sensitive upgrades to full form ({ value, type, lifetime, context, is_sensitive }).
  • Sensitive-preserve: on an existing sensitive var, --sensitive without --value keeps the stored value. On a new key, that combination errors out.
  • --json redaction: sensitive entries omit the value key entirely; the is_sensitive: true flag is the redaction signal.
  • Remote round-trip caveat: comment/key-order preservation only applies to the local-file path. The server normalizes formatting on import.

No Plugin Shortcut - Use CLI commands directly.

5. Test Sync Lifecycle

CLI Workflow:

# Pull tests from cloud
qa-use test sync pull

# Push all local tests to cloud
qa-use test sync push --all

# Push specific test
qa-use test sync push --id <uuid>

# Force push (overwrite conflicts)
qa-use test sync push --force

# Compare local vs cloud
qa-use test diff login.yaml

Persist vs Sync:

A local test is synced when its YAML has both an id: and a version_hash: (these are written back by test sync push/pull). --persist on test run and qa-use test sync are related but not the same:

Local file state persist What happens at run time
Non-synced false (default) Runs locally; nothing saved to cloud. Re-run with --persist or use test sync push to persist.
Non-synced true Test is uploaded as a new cloud entry after the run. Re-running like this creates duplicates — prefer test sync push once the file tracks the cloud id.
Synced false Runs against the cloud-tracked definition; no extra write.
Synced true Cloud definition is upserted (may overwrite newer cloud edits). Use test sync push/pull for explicit version control.

Rule of thumb: test sync push/pull is the deliberate path. Reserve --persist (or defaults.persist: true in .qa-use.json) for one-off uploads of brand-new local tests.

No Plugin Shortcut - Use CLI commands directly

Essential Commands

Browser Session Management

Command Description
qa-use browser create Create remote browser session
qa-use browser create <url> Create session and navigate to URL
qa-use browser create --tunnel [auto|on|off] Tunnel mode — default auto (localhost + remote API). --no-tunnel is sugar for off.
qa-use browser create --no-headless Show browser window (paired with a local/tunnel browser)
qa-use browser create --viewport <size> Set viewport: desktop, tablet, mobile
qa-use browser create --ws-url <url> Connect to existing WebSocket browser
qa-use browser create --after-test-id <uuid> Run a test first, then become interactive
qa-use browser create --var <key=value> Override app config variables (repeatable)
qa-use browser list List active sessions
qa-use browser status Show current session details (app_url, recording_url, etc.)
qa-use browser status --list Show all active sessions across processes
qa-use browser close Close active session
qa-use browser close <id> Close a specific session by id
qa-use doctor Reap stale sessions/tunnels (dead PIDs)
qa-use tunnel ls List active tunnels in the registry
qa-use tunnel start <url> --hold Hold a public tunnel for external consumers

Sessions auto-persist in ~/.qa-use.json. One active session = no -s flag needed. browser create returns immediately — the browser + tunnel run in a detached child. Use qa-use doctor if stale state accumulates.

Navigation

Command Description
qa-use browser goto <url> Navigate to URL
qa-use browser back Go back
qa-use browser forward Go forward
qa-use browser reload Reload page

Element Interaction

Command Description
qa-use browser click <ref> Click element by ref
qa-use browser click --text "Button" Click by semantic description
qa-use browser fill <ref> "value" Fill input field
qa-use browser type <ref> "text" Type with delays (for autocomplete)
qa-use browser press <key> Press key (e.g., Enter, Tab)
qa-use browser check <ref> Check checkbox
qa-use browser uncheck <ref> Uncheck checkbox
qa-use browser select <ref> "option" Select dropdown option
qa-use browser hover <ref> Hover over element
qa-use browser scroll down 500 Scroll by pixels
qa-use browser scroll-into-view <ref> Scroll element into view
qa-use browser drag <ref> --target <ref> Drag element to target
qa-use browser mfa-totp [ref] <secret> Generate TOTP code (optionally fill)
qa-use browser upload <ref> <file>... Upload file(s) to input (base64-encoded, works remote & tunnel)

Inspection & Snapshot Diff

Command Description
qa-use browser snapshot Get full ARIA tree with element refs (use only when diff output is insufficient)
qa-use browser url Get current URL
qa-use browser screenshot Save screenshot.png
qa-use browser screenshot file.png Save to custom path
qa-use browser screenshot --base64 Output base64 to stdout
qa-use browser evaluate <expression> Execute JavaScript in browser context

The snapshot-diff feature automatically displays DOM changes after each browser action:

  • Added elements: Shown with + prefix and green color — these refs are immediately usable
  • Modified elements: Shown with ~ prefix and yellow color, including attribute changes (+attrs: checked)
  • Removed elements: Shown with - prefix and red color — do NOT use these refs

Downloads: When an action triggers a file download (e.g., clicking a download link), the response includes download info: filename, size, and a presigned URL. Use qa-use browser downloads to list all downloads or --save <dir> to save them locally.

Use diff output to interact with newly appeared elements directly, without running a full snapshot first.

Test Operations

Command Description
qa-use test run <name> Run test by name
qa-use test run --all Run all tests
qa-use test run <name> --tunnel [mode] Override tunnel mode (auto, on, off). --no-tunnel is sugar for off. Bare --tunnel is sugar for on.
qa-use test run <name> --download Download assets to /tmp/qa-use/downloads/
qa-use test run <name> --var key=value Override variable
qa-use test validate <name> Validate test syntax
qa-use test list List available tests
qa-use test info <name> Show test details (steps, tags, description)
qa-use test info --id <uuid> Show cloud test details by ID
qa-use test runs [name] List test run history
qa-use test runs --id <uuid> Filter runs by test ID
qa-use test runs --status failed Filter runs by status
qa-use test init Initialize test directory
qa-use test sync pull Pull tests from cloud
qa-use test sync push --all Push all local tests to cloud
qa-use test sync push --id <uuid> Push specific test
qa-use test sync push --force Push tests, overwriting conflicts
qa-use test diff <file> Compare local vs cloud test
qa-use test schema [path] View test definition schema

API Operations (Dynamic OpenAPI)

qa-use api dynamically discovers operations from /api/v1/openapi.json and caches metadata locally for offline fallback.

Command Description
qa-use api Show help and available subcommands
qa-use api ls List available /api/v1/* routes from OpenAPI
qa-use api ls --refresh Force refresh OpenAPI cache
qa-use api ls --offline Use cached OpenAPI metadata only
qa-use api info /api/v1/<route> Show route details: parameters, request body, responses
qa-use api info /api/v1/<route> -X POST Show info for specific HTTP method
qa-use api info /api/v1/<route> --json Route info as JSON
qa-use api examples Show usage examples
qa-use api openapi Print OpenAPI spec URL
qa-use api openapi --raw Dump full OpenAPI spec as JSON
qa-use api /api/v1/tests Call endpoint (method inferred when possible)
qa-use api -X GET /api/v1/test-runs -f limit=5 GET with query fields
qa-use api -X POST /api/v1/tests-actions/run --input body.json POST with JSON body file
qa-use api -X GET /api/v1/test-runs/<id> Fetch detail endpoint by ID

No Plugin Shortcut - Use CLI commands directly.

Logs & Debugging

Command Description
qa-use browser logs console View console logs from session
qa-use browser logs console -s <id> View logs from specific/closed session
qa-use browser logs network View network request logs
qa-use browser logs network -s <id> View network logs from specific session
qa-use browser downloads List downloaded files from session
qa-use browser downloads --save <dir> Save downloaded files to local directory
qa-use browser downloads --json Output download info as JSON

Test Generation

Command Description
qa-use browser generate-test Generate test YAML from recorded session
qa-use browser generate-test -s <id> Generate from specific session
qa-use browser generate-test -n <name> Specify test name
qa-use browser generate-test -o <path> Specify output path
qa-use browser get-blocks Get recorded interaction blocks (JSON)

Waiting

Command Description
qa-use browser wait <ms> Fixed wait
qa-use browser wait-for-selector ".class" Wait for selector
qa-use browser wait-for-load Wait for page load

Variable Overrides

Use --var to override app config variables at runtime. Common variables:

Variable Description
base_url Base URL for the app (e.g., preview deployment URL)
login_url Login page URL
login_username Username/email for authentication
login_password Password for authentication

Example with ephemeral preview URL:

qa-use browser create --after-test-id <login-test-uuid> \
  --var base_url=https://preview-123.example.com \
  --var login_url=https://preview-123.example.com/auth/login

Common Patterns

Pattern 1: Feature Verification

CLI Workflow:

# 1. Search for existing test
qa-use test list | grep "login"

# 2. Run test
qa-use test run login

# 3. Debug failures
qa-use browser logs console

Plugin Shortcut:

/qa-use:verify "login works with valid credentials"

(Wraps the above CLI workflow with AI-powered test discovery and analysis)

Pattern 2: Record & Generate Test

CLI Workflow:

# 1. Create session (auto-tunnels localhost targets)
qa-use browser create --no-headless

# 2. Navigate and interact
qa-use browser goto https://example.com
qa-use browser snapshot
qa-use browser click e1
qa-use browser fill e5 "test"

# 3. Generate test from blocks
qa-use browser get-blocks
qa-use browser generate-test -n "my_test"

# 4. Run test
qa-use test run my_test

Plugin Shortcut:

/qa-use:record start my_test
# ... perform interactions ...
/qa-use:record stop

Pattern 3: Authenticated Exploration

CLI Workflow:

# Create session that runs login test first
qa-use browser create --after-test-id <login-test-uuid>

# Session now authenticated, explore
qa-use browser goto /dashboard
qa-use browser snapshot

Plugin Shortcut:

/qa-use:explore /dashboard

(Automatically handles auth detection and session creation)

Pattern 4: Edit Existing Test

CLI Workflow:

# 1. Open test file in editor
vim qa-tests/login.yaml

# 2. Validate syntax
qa-use test validate login

# 3. Run to verify
qa-use test run login

Plugin Shortcut:

/qa-use:record edit login

(AI-assisted editing with validation)

Pattern 5: Using Snapshot Diff to Avoid Unnecessary Snapshots

CLI Workflow:

# Create session and navigate
qa-use browser create --no-headless
qa-use browser goto https://evals.desplega.ai/checkboxes

# goto shows diff — initial page load shows all elements:
# Changes: 45 elements added
# + [e18] checkbox "I agree to the terms and conditions"
# + [e19] generic "I agree to the terms and conditions"

# ✅ Use ref from diff directly — no snapshot needed!
qa-use browser click e18

# Diff shows what changed:
# Changes: 5 elements added, 1 element modified
# + [e54] generic "Thanks for agreeing!"
# + [e55] link "Terms and Conditions"
# ~ [e18] checkbox "I agree to the terms and conditions"
#     +attrs: active, checked

# ✅ Can click e55 directly from diff output — no snapshot needed!
qa-use browser click e55

# ❌ Need to find an element NOT in the diff? Now run snapshot:
qa-use browser snapshot

Key principle: Use diff output as your primary source of element refs after actions. Only fall back to snapshot when you need to find elements that weren't in the diff.

Benefits:

  • Fewer API calls = faster automation
  • Diff refs are always fresh (just returned from the server)
  • Instantly see what changed (new elements, attribute changes, removals)

No Plugin Shortcut - Automatic feature in all browser commands

CI/CD Integration

Running Tests in CI

Environment Variables:

export QA_USE_API_KEY="your-api-key"
export QA_USE_REGION="us"  # Optional: "us" or "auto"

Basic Test Execution:

# Run all tests
qa-use test run --all

# Run specific tag
qa-use test run --tag smoke

# Exit codes: 0 = pass, 1 = fail

GitHub Actions Example

name: QA Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '20'
      - name: Install qa-use
        run: npm install -g @desplega.ai/qa-use
      - name: Run tests
        run: qa-use test run --all
        env:
          QA_USE_API_KEY: ${{ secrets.QA_USE_API_KEY }}

Test Artifacts

Screenshots:

  • Automatically saved on failure
  • Location: /tmp/qa-use/downloads/ (local) or cloud (remote)

Logs:

  • Console logs: qa-use browser logs console -s <session-id>
  • Network logs: qa-use browser logs network -s <session-id>

Advanced Topics

Localhost Testing (Auto-Tunnel)

qa-use auto-tunnels localhost targets when the API is remote. No flag required for the common case:

qa-use browser create --no-headless http://localhost:3000
qa-use test run my_test   # auto-tunnels if base_url is localhost

Tri-state --tunnel flag:

Value Behavior
auto (default) Tunnel iff base URL is localhost AND API URL is remote
on (or bare --tunnel) Force a tunnel even in dev mode
off (or --no-tunnel) Never tunnel
Testing localhost (http://localhost:3000)?
  ├─ API remote (default)  → auto-tunnels. No flag needed.
  ├─ API also local (dev)  → no tunnel by default. Use --tunnel on to force.
  └─ Public URL target     → no tunnel (remote cloud browser)

Plugin shortcuts handle tunnel detection automatically:

/qa-use:explore http://localhost:3000
/qa-use:record start local_test

See references/localhost-testing.md for troubleshooting.

Session Persistence

Sessions are stored in ~/.qa-use.json and have:

  • TTL: 30 minutes (default)
  • Auto-resolve: One active session = no -s flag needed
  • Cleanup: Automatic on timeout or explicit browser close

Block Limitations

What's captured:

  • goto, click, fill, type, check, uncheck, select, hover
  • scroll, scroll-into-view, drag, upload, press

What's NOT captured:

  • Assertions (must be added manually)
  • Waits (inferred from timing, may need adjustment)
  • Complex interactions (multi-drag, hover sequences)

Manual editing: Edit generated YAML to add assertions and refine selectors.

WebSocket Sessions

Sharing sessions across processes:

# Process 1: Create session (auto-tunnels if target is localhost + API remote)
qa-use browser create http://localhost:3000
# Output: ws://localhost:12345/browser/abc123

# Process 2: Connect to session
qa-use browser goto https://example.com --ws-url ws://localhost:12345/browser/abc123

Deep-Dive References

Access any reference at runtime via the CLI: qa-use docs <topic>

Topic CLI Command Description
browser-commands.md qa-use docs browser-commands Complete browser CLI reference with all flags
test-format.md qa-use docs test-format Full test YAML specification
localhost-testing.md qa-use docs localhost-testing Tunnel setup for local development
failure-debugging.md qa-use docs failure-debugging Failure classification and diagnostics
ci.md qa-use docs ci CI/CD integration patterns and examples

Use qa-use docs --list to discover all available topics and templates.

Templates

Template Description
basic-test.yaml Simple navigation and assertion
auth-flow.yaml Login flow with credentials
form-test.yaml Form submission with validation

Test Format Overview

name: Login Test
description: Validates login functionality with valid credentials
tags:
  - smoke
  - auth
app_config: <app-config-id>
variables:
  email: test@example.com
  password: secret123
depends_on: setup-test  # Optional
steps:
  - action: goto
    url: /login
  - action: fill
    target: email input
    value: $email
  - action: click
    target: login button
  - action: to_be_visible
    target: dashboard

See references/test-format.md for complete specification.

Common Mistakes

❌ Wrong ✅ Correct
browser navigate <url> browser goto <url>
browser destroy browser close
browser close <session-id> browser close
Guessing element refs Use refs from diff output or snapshot
Running snapshot after every action Use diff output; only snapshot when needed
Forcing --tunnel in dev (both local) Rely on auto-mode, or use --tunnel on explicitly
test sync --pull test sync pull (subcommand, not flag)
test sync --push test sync push (subcommand, not flag)

Troubleshooting

When stuck or encountering unexpected errors, use the built-in documentation:

# Check configuration state
qa-use setup

# Browse main documentation
qa-use docs

# List all available topics
qa-use docs --list

# Access specific topic
qa-use docs <topic>
Situation Command
Auth / API key errors qa-use setup then qa-use docs
Unknown browser command qa-use docs browser-commands
Test failures qa-use docs failure-debugging
Localhost / tunnel issues qa-use docs localhost-testing
Test YAML syntax qa-use docs test-format
CI/CD setup qa-use docs ci

Key rules:

  • ALWAYS consult qa-use docs before improvising workarounds
  • NEVER fabricate API keys, tokens, URLs, or credentials
  • If qa-use setup shows no config, report it — don't guess

npx Alternative

All commands use qa-use assuming global install. For one-off use:

npx @desplega.ai/qa-use browser <command>
Installs
115
GitHub Stars
22
First Seen
Jan 28, 2026