Initial: pi-skill — 68 skills, 43 extensions, 11 themes for Pi

This commit is contained in:
Kunthawat Greethong
2026-05-25 16:38:02 +07:00
commit 69f7d8bdda
1689 changed files with 342427 additions and 0 deletions

View File

@@ -0,0 +1,217 @@
---
name: qa-web
description: >
QA test skill for web applications using agent-browser. Tests forms, navigation,
responsive layouts, state persistence via cookies/localStorage, and visual regression.
The web counterpart to agent-device — together they cover native + web testing.
Invoke when user says "test the web app", "test localhost", "QA the website",
"test the form", "verify responsive layout", "run web tests", "test browser",
or any task requiring automated web application testing.
allowed-tools: Bash(agent-browser:*) Bash(node:*) Bash(curl:*) Read
---
# qa-web
Web application QA testing using **agent-browser**. The web counterpart to agent-device — together they provide full coverage for apps with both native and web versions.
## When to Use
| Scenario | Tool |
|----------|------|
| Test native iOS/Android app | agent-device + CDP |
| Test web app / localhost | **agent-browser** (this skill) |
| Test React Native Web | **agent-browser** (this skill) |
| Test responsive layouts | **agent-browser** (this skill) |
| Test forms and navigation | **agent-browser** (this skill) |
## Core Workflow
Every web test follows the same pattern as native tests:
1. **Navigate**: `agent-browser open <url>`
2. **Snapshot**: `agent-browser snapshot -i` (get element refs)
3. **Interact**: Use refs to click, fill, select
4. **Re-snapshot**: After navigation/DOM changes, get fresh refs
5. **Assert**: Verify URL, text, element state
```bash
agent-browser open http://localhost:3000/login
agent-browser snapshot -i
# Output: @e1 [input type="email"], @e2 [input type="password"], @e3 [button] "Sign In"
agent-browser fill @e1 "user@example.com"
agent-browser fill @e2 "password123"
agent-browser click @e3
agent-browser wait --load networkidle
agent-browser snapshot -i # Check result
```
## Configuration
Set web-specific values in `qa.config.sh`:
```bash
export WEB_BASE_URL="http://localhost:3000" # Your web app URL
export WEB_SESSION="qa" # Browser session name
export WEB_VIEWPORT_WIDTH=1280 # Default viewport
export WEB_VIEWPORT_HEIGHT=720
```
## Usage
### Run example web test
```bash
bash .pi/skills/qa-automation/qa-web/run.sh
```
### Run with headed browser (see what's happening)
```bash
export WEB_HEADED=true
bash .pi/skills/qa-automation/qa-web/flows/example-web-test.sh
```
## Helper Library — web-helpers.sh
Source this in your web test scripts for consistent patterns:
```bash
source .pi/skills/qa-automation/qa-web/lib/web-helpers.sh
```
### Available Functions
| Function | Purpose |
|----------|---------|
| `web_open "url"` | Navigate to URL |
| `web_snapshot` | Get interactive element refs |
| `web_click "ref_or_selector"` | Click element |
| `web_fill "ref" "text"` | Fill input field |
| `web_select "ref" "value"` | Select dropdown option |
| `web_wait "selector_or_ms"` | Wait for element/time |
| `web_screenshot "name"` | Screenshot with naming convention |
| `web_get_text "ref"` | Get element text |
| `web_get_url` | Get current URL |
| `web_get_title` | Get page title |
| `web_is_visible "ref"` | Check element visibility |
| `web_assert_url "pattern"` | Assert URL matches pattern |
| `web_assert_title "text"` | Assert page title |
| `web_assert_text "text"` | Assert text visible on page |
| `web_scroll "direction" [px]` | Scroll page |
| `web_save_state "file"` | Save cookies/storage |
| `web_load_state "file"` | Restore saved state |
## Test Patterns
### Form Testing
```bash
source web-helpers.sh
web_open "$WEB_BASE_URL/signup"
web_snapshot
web_fill @e1 "Jane Doe"
web_fill @e2 "jane@example.com"
web_fill @e3 "password123"
web_select @e4 "California"
web_click @e5 # Submit
web_wait --load networkidle
web_assert_url "**/dashboard"
web_assert_text "Welcome, Jane"
web_screenshot "signup-success"
```
### Navigation Testing
```bash
web_open "$WEB_BASE_URL"
web_snapshot
# Click nav links
web_click @e3 # "About" link
web_assert_url "**/about"
web_screenshot "about-page"
# Go back
agent-browser back
web_assert_url "**/"
```
### Responsive Testing
```bash
# Desktop
agent-browser set viewport 1440 900
web_open "$WEB_BASE_URL"
web_screenshot "desktop-home"
# Tablet
agent-browser set viewport 768 1024
web_screenshot "tablet-home"
# Mobile
agent-browser set viewport 375 812
web_screenshot "mobile-home"
```
### State Persistence (Cookies/Storage)
```bash
# Login and save state
web_open "$WEB_BASE_URL/login"
web_fill @e1 "user@example.com"
web_fill @e2 "password"
web_click @e3
web_wait --load networkidle
web_save_state "/tmp/qa-auth-state.json"
# Reuse in future tests
web_load_state "/tmp/qa-auth-state.json"
web_open "$WEB_BASE_URL/dashboard"
web_assert_text "Welcome" # Still logged in
```
### Accessibility Testing
```bash
web_open "$WEB_BASE_URL"
agent-browser snapshot # Full a11y tree
agent-browser screenshot --full /tmp/qa-full-page.png
```
## File Structure
```
qa-web/
├── SKILL.md # This file
├── lib/
│ └── web-helpers.sh # Web test helper functions
├── flows/
│ └── example-web-test.sh # Example test
└── run.sh # Runner
```
## Integration with Native Tests
For apps with both native and web versions, use both tools in the same test run:
```bash
# Test native app
bash .pi/skills/qa-automation/qa-scroll/run.sh
# Test web app
bash .pi/skills/qa-automation/qa-web/run.sh
# Both results in /tmp/qa-tests/
```
## Troubleshooting
| Problem | Solution |
|---------|----------|
| "agent-browser: command not found" | Install: `npm install -g agent-browser` |
| Browser launches but page is blank | Check URL and dev server: `curl $WEB_BASE_URL` |
| Refs invalidated after click | Always re-snapshot after navigation/DOM changes |
| Can't access localhost | agent-browser runs locally — it CAN access localhost (unlike web_remote) |
| Headed mode not showing | Set `export WEB_HEADED=true` before running |

View File

@@ -0,0 +1,103 @@
#!/bin/bash
# ╔═══════════════════════════════════════════════════════════════════╗
# ║ Example Web Test — Form Submission & Navigation ║
# ╠═══════════════════════════════════════════════════════════════════╣
# ║ CUSTOMIZE: Replace URLs, selectors, and assertions for your app. ║
# ║ ║
# ║ Usage: bash .pi/skills/qa-automation/qa-web/flows/example-web-test.sh
# ╚═══════════════════════════════════════════════════════════════════╝
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/../lib/web-helpers.sh"
TEST_NAME="web-form-test"
setup_test "$TEST_NAME"
# ── Step 1: Open the web app ────────────────────────────────────────
step "Open web app"
web_open "$WEB_BASE_URL"
web_screenshot "01-homepage"
url=$(web_get_url)
log_info "URL: $url"
log_pass "Web app loaded"
# ── Step 2: Take a snapshot of interactive elements ──────────────────
step "Snapshot interactive elements"
snapshot=$(web_snapshot)
log_info "Snapshot:"
echo "$snapshot" | head -20
web_screenshot "02-snapshot"
# ── Step 3: Navigate to a page ──────────────────────────────────────
# CUSTOMIZE: Change the selector to match your app's navigation
step "Navigate to a page"
# web_click @e3 # Click a nav link (use ref from snapshot)
# Or navigate directly:
# web_open "$WEB_BASE_URL/about"
sleep 1
url=$(web_get_url)
log_info "URL after navigation: $url"
web_screenshot "03-navigated"
log_pass "Navigation successful"
# ── Step 4: Fill and submit a form ──────────────────────────────────
# CUSTOMIZE: Replace with your app's form fields
step "Fill form (if present)"
# web_snapshot # Get fresh refs
# web_fill @e1 "Jane Doe"
# web_fill @e2 "jane@example.com"
# web_click @e5 # Submit button
# web_wait_network
# web_screenshot "04-form-submitted"
log_info "Form step skipped — customize for your app"
web_screenshot "04-current-state"
# ── Step 5: Check responsive layout ─────────────────────────────────
step "Check responsive layouts"
# Desktop
web_set_viewport 1440 900
sleep 1
web_screenshot "05a-desktop"
log_pass "Desktop viewport captured"
# Tablet
web_set_viewport 768 1024
sleep 1
web_screenshot "05b-tablet"
log_pass "Tablet viewport captured"
# Mobile
web_set_viewport 375 812
sleep 1
web_screenshot "05c-mobile"
log_pass "Mobile viewport captured"
# Reset
web_set_viewport "$WEB_VIEWPORT_WIDTH" "$WEB_VIEWPORT_HEIGHT"
# ── Step 6: Final state ─────────────────────────────────────────────
step "Final state check"
title=$(web_get_title)
url=$(web_get_url)
log_info "Title: $title"
log_info "URL: $url"
web_screenshot "06-final"
log_pass "Web test complete"
# ── Cleanup ──────────────────────────────────────────────────────────
web_close
teardown_test
echo ""
echo "Web test completed!"
echo " Screenshots: $SCREENSHOT_DIR/$TEST_NAME/"
echo ""

View File

@@ -0,0 +1,347 @@
#!/bin/bash
# ╔═══════════════════════════════════════════════════════════════════╗
# ║ web-helpers.sh — Web Test Helpers using agent-browser ║
# ╠═══════════════════════════════════════════════════════════════════╣
# ║ Source this file in web test scripts: ║
# ║ source "$(dirname "$0")/../lib/web-helpers.sh" ║
# ║ ║
# ║ Provides consistent wrappers around agent-browser commands ║
# ║ with the same test lifecycle as native test-helpers.sh. ║
# ╚═══════════════════════════════════════════════════════════════════╝
set -euo pipefail
# ── Source configuration and test framework ──────────────────────────
WEB_HELPERS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
QA_ROOT_WEB="$(cd "$WEB_HELPERS_DIR/../.." && pwd)"
source "$QA_ROOT_WEB/qa.config.sh"
# Source test-helpers for lifecycle (setup_test, teardown_test, step, log_*)
source "$QA_ROOT_WEB/qa-test-flows/lib/test-helpers.sh"
# ── Session flags ────────────────────────────────────────────────────
_WEB_SESSION_FLAG=""
[ -n "$WEB_SESSION" ] && _WEB_SESSION_FLAG="--session $WEB_SESSION"
_WEB_HEADED_FLAG=""
[ "${WEB_HEADED:-false}" = "true" ] && _WEB_HEADED_FLAG="--headed"
# ── Navigation ───────────────────────────────────────────────────────
# Open a URL in the browser
web_open() {
local url="$1"
agent-browser $_WEB_SESSION_FLAG $_WEB_HEADED_FLAG open "$url" 2>/dev/null || {
log_warn "Failed to open: $url"
return 1
}
sleep 1
}
# Get interactive element snapshot (refs like @e1, @e2)
web_snapshot() {
agent-browser $_WEB_SESSION_FLAG snapshot -i 2>/dev/null || echo "(snapshot failed)"
}
# Full accessibility tree snapshot
web_full_snapshot() {
agent-browser $_WEB_SESSION_FLAG snapshot 2>/dev/null || echo "(snapshot failed)"
}
# ── Interaction ──────────────────────────────────────────────────────
# Click an element by ref or selector
web_click() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG click "$target" 2>/dev/null || {
log_warn "Click failed: $target"
return 1
}
sleep 0.5
}
# Fill an input field (clears first)
web_fill() {
local target="$1"
local text="$2"
agent-browser $_WEB_SESSION_FLAG fill "$target" "$text" 2>/dev/null || {
log_warn "Fill failed: $target"
return 1
}
sleep 0.3
}
# Type text without clearing
web_type() {
local target="$1"
local text="$2"
agent-browser $_WEB_SESSION_FLAG type "$target" "$text" 2>/dev/null || {
log_warn "Type failed: $target"
return 1
}
sleep 0.3
}
# Select dropdown option
web_select() {
local target="$1"
local value="$2"
agent-browser $_WEB_SESSION_FLAG select "$target" "$value" 2>/dev/null || {
log_warn "Select failed: $target $value"
return 1
}
sleep 0.3
}
# Check a checkbox
web_check() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG check "$target" 2>/dev/null || return 1
}
# Uncheck a checkbox
web_uncheck() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG uncheck "$target" 2>/dev/null || return 1
}
# Press a key
web_press() {
local key="$1"
agent-browser $_WEB_SESSION_FLAG press "$key" 2>/dev/null || return 1
}
# Hover over an element
web_hover() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG hover "$target" 2>/dev/null || return 1
}
# ── Wait ─────────────────────────────────────────────────────────────
# Wait for element, time, or network idle
web_wait() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG wait "$target" 2>/dev/null || return 1
}
# Wait for network idle
web_wait_network() {
agent-browser $_WEB_SESSION_FLAG wait --load networkidle 2>/dev/null || return 1
}
# Wait for specific text to appear
web_wait_text() {
local text="$1"
agent-browser $_WEB_SESSION_FLAG wait --text "$text" 2>/dev/null || return 1
}
# ── Get Information ──────────────────────────────────────────────────
# Get element text
web_get_text() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG get text "$target" 2>/dev/null || echo ""
}
# Get current URL
web_get_url() {
agent-browser $_WEB_SESSION_FLAG get url 2>/dev/null || echo ""
}
# Get page title
web_get_title() {
agent-browser $_WEB_SESSION_FLAG get title 2>/dev/null || echo ""
}
# Get element attribute
web_get_attr() {
local target="$1"
local attr="$2"
agent-browser $_WEB_SESSION_FLAG get attr "$target" "$attr" 2>/dev/null || echo ""
}
# Get input value
web_get_value() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG get value "$target" 2>/dev/null || echo ""
}
# Count matching elements
web_count() {
local selector="$1"
agent-browser $_WEB_SESSION_FLAG get count "$selector" 2>/dev/null || echo "0"
}
# ── Check State ──────────────────────────────────────────────────────
# Check if element is visible
web_is_visible() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG is visible "$target" 2>/dev/null && echo "true" || echo "false"
}
# Check if element is enabled
web_is_enabled() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG is enabled "$target" 2>/dev/null && echo "true" || echo "false"
}
# Check if checkbox is checked
web_is_checked() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG is checked "$target" 2>/dev/null && echo "true" || echo "false"
}
# ── Screenshots ──────────────────────────────────────────────────────
# Take a screenshot with test naming convention
web_screenshot() {
local name="$1"
local path="$SCREENSHOT_DIR/$TEST_NAME/${name}.png"
mkdir -p "$(dirname "$path")"
agent-browser $_WEB_SESSION_FLAG screenshot "$path" 2>/dev/null || {
log_warn "Web screenshot failed: $name"
return 1
}
echo "$path"
}
# Full-page screenshot
web_screenshot_full() {
local name="$1"
local path="$SCREENSHOT_DIR/$TEST_NAME/${name}.png"
mkdir -p "$(dirname "$path")"
agent-browser $_WEB_SESSION_FLAG screenshot "$path" --full 2>/dev/null || {
log_warn "Full web screenshot failed: $name"
return 1
}
echo "$path"
}
# ── Scroll ───────────────────────────────────────────────────────────
# Scroll page
web_scroll() {
local direction="${1:-down}"
local amount="${2:-300}"
agent-browser $_WEB_SESSION_FLAG scroll "$direction" "$amount" 2>/dev/null || return 1
}
# Scroll element into view
web_scroll_into_view() {
local target="$1"
agent-browser $_WEB_SESSION_FLAG scrollintoview "$target" 2>/dev/null || return 1
}
# ── State Management ─────────────────────────────────────────────────
# Save browser state (cookies, localStorage, auth)
web_save_state() {
local path="$1"
agent-browser $_WEB_SESSION_FLAG state save "$path" 2>/dev/null || {
log_warn "Failed to save state to: $path"
return 1
}
log_info "Browser state saved to: $path"
}
# Load browser state
web_load_state() {
local path="$1"
if [ -f "$path" ]; then
agent-browser $_WEB_SESSION_FLAG state load "$path" 2>/dev/null || {
log_warn "Failed to load state from: $path"
return 1
}
log_info "Browser state loaded from: $path"
else
log_warn "State file not found: $path"
return 1
fi
}
# ── Assertion Helpers ────────────────────────────────────────────────
# Assert current URL matches pattern
web_assert_url() {
local pattern="$1"
local url
url=$(web_get_url)
if echo "$url" | grep -q "$pattern"; then
log_pass "URL matches: $pattern"
return 0
else
log_fail "URL mismatch: expected '$pattern', got '$url'"
return 1
fi
}
# Assert page title contains text
web_assert_title() {
local expected="$1"
local title
title=$(web_get_title)
if echo "$title" | grep -qi "$expected"; then
log_pass "Title contains: $expected"
return 0
else
log_fail "Title mismatch: expected '$expected', got '$title'"
return 1
fi
}
# Assert text is visible on page
web_assert_text() {
local text="$1"
local body
body=$(agent-browser $_WEB_SESSION_FLAG get text body 2>/dev/null || echo "")
if echo "$body" | grep -qi "$text"; then
log_pass "Text visible: $text"
return 0
else
log_fail "Text not found: $text"
return 1
fi
}
# Assert element is visible
web_assert_visible() {
local target="$1"
local visible
visible=$(web_is_visible "$target")
if [ "$visible" = "true" ]; then
log_pass "Element visible: $target"
return 0
else
log_fail "Element NOT visible: $target"
return 1
fi
}
# ── Browser Lifecycle ────────────────────────────────────────────────
# Close the browser session
web_close() {
agent-browser $_WEB_SESSION_FLAG close 2>/dev/null || true
}
# Set viewport size
web_set_viewport() {
local width="${1:-$WEB_VIEWPORT_WIDTH}"
local height="${2:-$WEB_VIEWPORT_HEIGHT}"
agent-browser $_WEB_SESSION_FLAG set viewport "$width" "$height" 2>/dev/null || return 1
}
# Emulate a mobile device
web_set_device() {
local device="$1"
agent-browser $_WEB_SESSION_FLAG set device "$device" 2>/dev/null || return 1
}
echo "Web helpers loaded. Base URL: $WEB_BASE_URL | Session: ${WEB_SESSION:-default}"

View File

@@ -0,0 +1,27 @@
#!/bin/bash
# Run the Web QA test
#
# Usage: bash .pi/skills/qa-automation/qa-web/run.sh
set -euo pipefail
SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
echo ""
echo "╔═══════════════════════════════════════════════════╗"
echo "║ Web Application QA ║"
echo "║ Started: $(date '+%Y-%m-%d %H:%M:%S') "
echo "╚═══════════════════════════════════════════════════╝"
echo ""
bash "$SKILL_DIR/flows/example-web-test.sh"
EXIT_CODE=$?
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " Exit code: $EXIT_CODE"
echo " Screenshots: /tmp/qa-tests/screenshots/web-form-test/"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
exit $EXIT_CODE