pi-heartbeat
Configure periodic health checks via HEARTBEAT.md and the /heartbeat command.
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"
$ npx -y skills add espennilsen/pi --skill qa-testing --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/qa-testingContext 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"
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.
Test running web applications by interacting as a real user via cmux_browser, then report findings with structured evidence.
**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'
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.
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:**
**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" })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;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.
Configure periodic health checks via HEARTBEAT.md and the /heartbeat command.
Manage persistent memory across sessions. Use when asked to remember, recall, forget, or review what was stored. Covers long-term…
Track and manage projects with git status via dashboard and tool.
Delegate tasks to specialized subagents for parallel or sequential execution.
Audit, generate, update, and lint AGENTS.md files across all projects. Use when asked to check project context files, scaffold…