Skip to content
Skill Authoring
Skill

/qa-testing

Perform QA testing on running web applications using cmux_browser. Covers functional testing, accessibility auditing, edge case testing, and structured reporting with evidence. **Triggers — use this skill when:** - User says "test this", "QA this", "QA this PR", "check the app"

BOOST
From plugin
pi
12238 skills5 agents
Install
$ npx -y skills add espennilsen/pi --skill qa-testing --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/qa-testing

Context preview

The summary Claude sees to decide when to auto-load this skill.

Perform QA testing on running web applications using cmux_browser. Covers functional testing, accessibility auditing, edge case testing, and structured reporting with evidence. **Triggers — use this skill when:** - User says "test this", "QA this", "QA this PR", "check the app"

SKILL.md

qa-testing.SKILL.md
name: qa-testing
description: >
  Perform QA testing on running web applications using cmux_browser.
  Covers functional testing, accessibility auditing, edge case testing,
  and structured reporting with evidence.

  **Triggers — use this skill when:**
  - User says "test this", "QA this", "QA this PR", "check the app"
  - User says "run QA", "verify the build", "test the UI"
  - User asks to "check if it works", "validate the feature"
  - User says "acceptance testing", "smoke test", "regression test"
  - User asks to "find bugs", "test for bugs", "break it"
  - User wants to "check accessibility", "run axe", "a11y audit"

  **Covers:** Any web application accessible via HTTP. Uses cmux_browser
  (Playwright under the hood) for all browser interactions.

QA Testing — Web Application Testing with cmux_browser

Test running web applications by interacting as a real user via cmux_browser, then report findings with structured evidence.

Prerequisites

  • The application must be running and accessible via HTTP
  • cmux_browser tool must be available
  • If the app isn't running, start it first (see Setup below)

Workflow

Step 1: Setup

**If the app is already running**, skip to Step 2.

**If the app needs to be started:**

# Start in a background cmux pane
cmux_split({ direction: "down", command: "cd /path/to/project && npm run dev\n" })

# Wait for it to be ready (check the pane output)
cmux_read({ surface: "surface:N" })

# Or poll the URL
cmux_browser({ action: "open", url: "http://localhost:3000" })
cmux_browser({ action: "wait", waitCondition: "load-state", loadState: "networkidle" })

**If Docker is needed:**

cd /path/to/project && docker compose up -d
# Wait for healthy
timeout 60 bash -c 'until curl -sf http://localhost:3000 > /dev/null; do sleep 2; done'

Step 2: Smoke Test

Verify the app loads at all before deeper testing.

# Open the app
cmux_browser({ action: "open", url: "http://localhost:3000" })

# Wait for it to load
cmux_browser({ action: "wait", waitCondition: "load-state", loadState: "networkidle" })

# Screenshot the initial state
cmux_browser({ action: "screenshot" })

# Check for JavaScript errors
cmux_browser({ action: "errors" })

# Check console output
cmux_browser({ action: "console" })

# Get a DOM snapshot (accessibility tree)
cmux_browser({ action: "snapshot" })

If the smoke test fails (page doesn't load, crash errors), stop and report immediately.

Step 3: Functional Testing

For each acceptance criterion, follow this pattern:

# 1. Navigate to the relevant state
cmux_browser({ action: "navigate", url: "/some-page" })
cmux_browser({ action: "wait", waitCondition: "load-state", loadState: "networkidle" })

# 2. Interact as a real user
cmux_browser({ action: "click", selector: "button.submit" })
cmux_browser({ action: "fill", selector: "input[name='email']", value: "test@example.com" })
cmux_browser({ action: "press", key: "Enter" })

# 3. Verify outcomes
cmux_browser({ action: "wait", waitCondition: "text", text: "Success" })
cmux_browser({ action: "snapshot", interactive: true })  # check element states
cmux_browser({ action: "get", selector: ".result", subaction: "textContent" })
cmux_browser({ action: "is", selector: ".modal", subaction: "visible" })

# 4. Screenshot as evidence
cmux_browser({ action: "screenshot" })

# 5. Check for errors after the interaction
cmux_browser({ action: "errors" })

**Tips for reliable element selection:**

  • Use `snapshot` to see the accessibility tree and find the right selectors
  • Use `find` with `role` for semantic targeting: `cmux_browser({ action: "find", subaction: "role", name: "Submit" })`
  • Use `identify` to see interactive elements on the page
  • Prefer `data-testid`, `aria-label`, or semantic selectors over fragile CSS paths

Step 4: Edge Case Testing

**Be skeptical.** Agents often ship code that works for the happy path but breaks on edge cases. Actively try to break things:

| Test | How | What to look for | |------|-----|-----------------| | **Empty state** | Clear all data, visit pages with no content | Crashes, blank screens, missing "no data" messages | | **Empty inputs** | Submit forms with empty required fields | Missing validation, silent failures, crashes | | **Long text** | Paste 500+ character strings into inputs | Overflow, layout breaking, truncation without indication | | **Special characters** | Input `<script>alert(1)</script>`, emoji 🎉, Unicode ñ | XSS, encoding errors, display issues | | **Rapid clicks** | Double-click submit buttons, rapidly toggle switches | Duplicate submissions, race conditions, broken state | | **Back button** | Navigate forward through a flow, then press back | Lost state, stale data, errors | | **Refresh** | F5 / reload mid-flow | Lost state, errors, unexpected redirects | | **Network errors** | Disconnect WiFi / block API calls (if possible) | Missing error handling, infinite spinners, blank screens |

# Example: test empty form submission
cmux_browser({ action: "click", selector: "button[type='submit']" })
cmux_browser({ action: "screenshot" })
cmux_browser({ action: "errors" })

# Example: test long text
cmux_browser({ action: "fill", selector: "input[name='title']", value: "A".repeat(500) })
cmux_browser({ action: "screenshot" })

# Example: test special characters
cmux_browser({ action: "fill", selector: "input[name='name']", value: "<script>alert('xss')</script>" })
cmux_browser({ action: "click", selector: "button[type='submit']" })
cmux_browser({ action: "screenshot" })
cmux_browser({ action: "errors" })

Step 5: Accessibility Audit

Inject axe-core and run a full accessibility audit:

# Inject axe-core library
cmux_browser({ action: "eval", value: `
  await new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js';
    script.onload = resolve;
    script.onerror = reject;
Read more
Ships withpi

This repository is my Pi coding agent home directory. I keep it under version control and symlink it to ~/.pi/agent so Pi loads configuration, extensions, skills, and runtime state from here.

Get the whole plugin

Other skills on pi.