en un clic
qa-use
// E2E testing and browser automation with qa-use CLI. Use when the user needs to run tests, verify features, automate browser interactions, or debug test failures.
// E2E testing and browser automation with qa-use CLI. Use when the user needs to run tests, verify features, automate browser interactions, or debug test failures.
| name | qa-use |
| description | E2E testing and browser automation with qa-use CLI. Use when the user needs to run tests, verify features, automate browser interactions, or debug test failures. |
| allowed-tools | Bash(qa-use *) |
E2E testing and browser automation for AI-driven development workflows.
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:
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.
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:
+ [e54] generic "Thanks for agreeing!" (green)~ [e18] checkbox "I agree..." with +attrs: checked, active (yellow)- [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").
What are blocks?
Blocks are atomic recorded interactions from a browser session. They are:
qa-use browser get-blocksWhy blocks matter:
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)
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)
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:
<file> or --id, not both. Neither → exit 1.--id requires a full UUID (use qa-use test list --query <name> to find one).--key/--value writes simple form (key: value).
Any of --type/--lifetime/--context/--sensitive upgrades to full form
({ value, type, lifetime, context, is_sensitive }).--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.No Plugin Shortcut - Use CLI commands directly.
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
| 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.
| 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 |
| 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) |
| 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:
+ prefix and green color — these refs are immediately usable~ prefix and yellow color, including attribute changes (+attrs: checked)- prefix and red color — do NOT use these refsDownloads: 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.
| 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 |
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.
Remote API checks are managed through first-class commands. They call the desplega.ai API directly; they do not run checks locally or create browser sessions.
| Command | Description |
|---|---|
qa-use check list --app-config <id> | List remote API checks |
qa-use check info <check-id> | Inspect one check, including dependencies and captures |
qa-use check create --name <name> --app-config <id> --config check.json | Create a check |
qa-use check update <check-id> --depends-on <id> --alias <name> | Update dependency-chain metadata |
qa-use check delete <check-id> --force | Delete a check |
qa-use check-schedule list --app-config <id> | List remote check schedules |
qa-use check-schedule create --name <name> --app-config <id> --cron "*/15 * * * *" --check <id> | Create an ordered schedule |
qa-use check-schedule run <schedule-id> --var env=staging | Run a schedule as a remote variable-passing chain |
Common flow:
qa-use check create \
--name "Auth token" \
--app-config <app-config-id> \
--config auth-check.json \
--alias auth \
--capture token=$.access_token
qa-use check update <claim-check-id> \
--depends-on <auth-check-id> \
--alias claim
qa-use check-schedule create \
--name "Claims chain" \
--app-config <app-config-id> \
--cron "*/15 * * * *" \
--check <auth-check-id> \
--check <claim-check-id>
qa-use check-schedule run <schedule-id> --var env=staging --var claim_id=123
There is no standalone qa-use check run <check-id> command yet because the
public API currently documents schedule runs, not individual check-run actions.
Use qa-use api info /api/v1/checks -X POST for the current check payload
contract, and see references/checks.md for examples.
No Plugin Shortcut - Use CLI commands directly.
| 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 |
| 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) |
| 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 |
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
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)
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
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)
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)
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:
No Plugin Shortcut - Automatic feature in all browser commands
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
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 }}
Screenshots:
/tmp/qa-use/downloads/ (local) or cloud (remote)Logs:
qa-use browser logs console -s <session-id>qa-use browser logs network -s <session-id>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.
Sessions are stored in ~/.qa-use.json and have:
-s flag neededbrowser closeWhat's captured:
What's NOT captured:
Manual editing: Edit generated YAML to add assertions and refine selectors.
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
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 |
| checks.md | qa-use docs checks | API checks and check schedule workflows |
| 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.
| Template | Description |
|---|---|
| basic-test.yaml | Simple navigation and assertion |
| auth-flow.yaml | Login flow with credentials |
| form-test.yaml | Form submission with validation |
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.
| ❌ 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) |
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 |
| API checks / schedules | qa-use docs checks |
| CI/CD setup | qa-use docs ci |
Key rules:
qa-use docs before improvising workaroundsqa-use setup shows no config, report it — don't guessAll commands use qa-use assuming global install. For one-off use:
npx @desplega.ai/qa-use browser <command>