Agent skill
browser-test
Run comprehensive Playwright browser tests across desktop, tablet, and mobile viewports. Auto-discovers pages and tests navigation, forms, auth, CRUD, responsive behavior, interactive elements, error states, user flows, and performance metrics.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/browser-test
SKILL.md
Browser Test Skill
Run comprehensive Playwright browser tests across desktop, tablet, and mobile viewports.
When to Use
Invoke with /browser-test when you need to:
- Test your web application across multiple screen sizes
- Verify responsive behavior and mobile compatibility
- Test user flows and common interactions
- Capture screenshots at different viewports
- Check performance metrics (LCP, CLS, INP)
Usage
/browser-test <port> [target]
Arguments:
port(required) - Port the app is running on (e.g., 3000, 8080)target(optional) - Specific page (/dashboard), flow type (auth,forms,crud), orall(default)
Examples:
# Test entire app on port 3000
/browser-test 3000
# Test only the dashboard page
/browser-test 3000 /dashboard
# Test only authentication flows
/browser-test 3000 auth
# Test on different port
/browser-test 8080 all
Instructions
Phase 1: Setup and Validation
PORT="$1"
TARGET="${2:-all}"
# Validate port is provided
if [ -z "$PORT" ]; then
echo "❌ Error: Port number is required"
echo ""
echo "Usage: /browser-test <port> [page-or-feature|all]"
echo ""
echo "Examples:"
echo " /browser-test 3000"
echo " /browser-test 3000 all"
echo " /browser-test 3000 /dashboard"
echo " /browser-test 3000 auth"
exit 1
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🎭 Browser Testing with Playwright"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Target: http://localhost:$PORT"
echo "Scope: $TARGET"
echo "Viewports: Desktop (1920x1080), Tablet (768x1024), Mobile (375x812)"
echo ""
# Verify the app is running on the specified port
echo "📡 Checking if app is running on port $PORT..."
# Use curl to check if the port responds (works on Windows/Linux/Mac)
if command -v curl > /dev/null 2>&1; then
if curl -s -o /dev/null -w "%{http_code}" "http://localhost:$PORT" | grep -q "^[23]"; then
echo "✓ App is reachable at http://localhost:$PORT"
else
echo "⚠️ Warning: Could not reach http://localhost:$PORT"
echo " Make sure your app is running before continuing"
echo ""
fi
else
echo "⚠️ curl not found, skipping reachability check"
echo " Make sure your app is running at http://localhost:$PORT"
echo ""
fi
# Check if Playwright is installed
echo ""
echo "🔍 Checking Playwright installation..."
if npx playwright --version > /dev/null 2>&1; then
PLAYWRIGHT_VERSION=$(npx playwright --version)
echo "✓ Playwright found: $PLAYWRIGHT_VERSION"
else
echo "📦 Playwright not found. Installing..."
# Create package.json if it doesn't exist
if [ ! -f "package.json" ]; then
npm init -y > /dev/null 2>&1
fi
# Install Playwright
npm install --save-dev @playwright/test
# Install Chromium only (faster than all browsers)
npx playwright install chromium
echo "✓ Playwright installed successfully"
fi
# Create browser-tests directory structure
echo ""
echo "📁 Setting up test directory structure..."
mkdir -p browser-tests/tests
mkdir -p browser-tests/screenshots/desktop
mkdir -p browser-tests/screenshots/tablet
mkdir -p browser-tests/screenshots/mobile
mkdir -p browser-tests/reports
echo "✓ Directory structure created"
echo ""
Phase 2: Route and Feature Discovery
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Phase 2: Discovering Routes and Features"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Detect framework
FRAMEWORK="unknown"
echo "🔍 Detecting framework..."
if [ -d "app" ] && ([ -f "next.config.js" ] || [ -f "next.config.ts" ] || [ -f "next.config.mjs" ]); then
FRAMEWORK="nextjs-app-router"
echo "✓ Detected: Next.js (App Router)"
elif [ -d "pages" ] && ([ -f "next.config.js" ] || [ -f "next.config.ts" ]); then
FRAMEWORK="nextjs-pages-router"
echo "✓ Detected: Next.js (Pages Router)"
elif [ -f "nuxt.config.ts" ] || [ -f "nuxt.config.js" ]; then
FRAMEWORK="nuxt"
echo "✓ Detected: Nuxt"
elif [ -f "vite.config.ts" ] || [ -f "vite.config.js" ]; then
FRAMEWORK="vite-spa"
echo "✓ Detected: Vite SPA"
elif [ -f "angular.json" ]; then
FRAMEWORK="angular"
echo "✓ Detected: Angular"
elif [ -d "src" ] && grep -q "react-router" package.json 2>/dev/null; then
FRAMEWORK="react-router"
echo "✓ Detected: React Router"
elif [ -d "src" ] && grep -q "vue-router" package.json 2>/dev/null; then
FRAMEWORK="vue-router"
echo "✓ Detected: Vue Router"
else
echo "⚠️ Framework not auto-detected, will use runtime crawling"
fi
echo ""
echo "🗺️ Discovering routes and features..."
echo ""
# Claude: Based on detected framework, discover routes using static analysis:
#
# Next.js App Router:
# - Scan app/**/page.tsx and app/**/page.jsx
# - Map directory structure to routes
# - Identify route groups (app/(auth)/login -> /login)
# - Identify dynamic routes (app/posts/[id] -> /posts/:id)
#
# Next.js Pages Router:
# - Scan pages/**/*.tsx and pages/**/*.jsx
# - Exclude _app, _document, _error
# - Map file names to routes
#
# Nuxt:
# - Scan pages/**/*.vue
# - Follow Nuxt routing conventions
#
# React Router / Vue Router:
# - Find router configuration files (usually src/router, src/routes)
# - Parse route definitions
#
# Vite SPA / Unknown:
# - Fall back to runtime crawling (Phase 2B below)
#
# For each route, detect features by analyzing source code:
#
# FORMS - Look for:
# - <form>, <input>, <textarea>, <select> elements
# - Form libraries: react-hook-form, Formik, useForm
# - Validation schemas: Zod, Yup
# - API handlers with POST/PUT methods
#
# AUTHENTICATION - Look for:
# - Auth providers: NextAuth, Clerk, Auth0, Supabase
# - /login, /signin, /signup, /register routes
# - useSession, getServerSession, useAuth hooks
# - Middleware with authentication checks
# - Protected route patterns
#
# CRUD OPERATIONS - Look for:
# - Table/list components with edit/delete buttons
# - Routes with /new, /create, /edit, /:id patterns
# - API routes with GET/POST/PUT/DELETE methods
# - Database queries in server components/API routes
#
# INTERACTIVE ELEMENTS - Look for:
# - Dialog/Modal components
# - Dropdown/Select components
# - Accordion/Collapse components
# - Tooltip/Popover components
# - Tab/TabPanel components
#
# ERROR PAGES - Look for:
# - 404.tsx, not-found.tsx, [not-found].tsx
# - 500.tsx, error.tsx
# - ErrorBoundary components
#
# Present discovery results in structured format:
#
# Example output format:
# ┌────────────────────────────────────────┐
# │ Routes Discovered: 12 │
# ├────────────────────────────────────────┤
# │ / (homepage) │
# │ /about │
# │ /dashboard (requires auth) │
# │ /dashboard/settings │
# │ /products (CRUD list) │
# │ /products/[id] (CRUD detail) │
# │ /products/new (CRUD create) │
# │ /login (auth) │
# │ /signup (auth) │
# │ /contact (form) │
# │ /404 (error page) │
# │ /api/health (API - skip browser test) │
# └────────────────────────────────────────┘
#
# ┌────────────────────────────────────────┐
# │ Features Detected │
# ├────────────────────────────────────────┤
# │ ✓ Forms: 3 pages │
# │ - /contact (contact form) │
# │ - /login (credentials) │
# │ - /signup (registration) │
# │ │
# │ ✓ Authentication: NextAuth │
# │ - /login, /signup pages │
# │ - Protected: /dashboard/* │
# │ │
# │ ✓ CRUD: Products │
# │ - List: /products │
# │ - Detail: /products/[id] │
# │ - Create: /products/new │
# │ │
# │ ✓ Interactive Elements │
# │ - Modal: Delete confirmation │
# │ - Dropdown: Navigation menu │
# │ │
# │ ✓ Error Pages │
# │ - Custom 404: /404 │
# └────────────────────────────────────────┘
#
# If TARGET is not "all", filter to matching scope:
# - If TARGET is a path like "/dashboard", only test that route
# - If TARGET is "auth", only test authentication flows
# - If TARGET is "forms", only test form pages
# - If TARGET is "crud", only test CRUD operations
echo ""
Phase 3: Test Generation
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Phase 3: Generating Test Scripts"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Generate playwright.config.ts with 3 viewport projects
echo "📝 Generating playwright.config.ts..."
cat > browser-tests/playwright.config.ts << 'PLAYWRIGHT_CONFIG_EOF'
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
outputDir: './test-results',
fullyParallel: false, // Sequential for predictable screenshots
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 1,
workers: 1, // Run one test at a time
timeout: 30000,
use: {
baseURL: `http://localhost:${PORT}`,
screenshot: 'only-on-failure',
trace: 'retain-on-failure',
},
projects: [
{
name: 'desktop',
use: {
viewport: { width: 1920, height: 1080 },
...devices['Desktop Chrome'],
},
},
{
name: 'tablet',
use: {
viewport: { width: 768, height: 1024 },
...devices['iPad Mini'],
},
},
{
name: 'mobile',
use: {
viewport: { width: 375, height: 812 },
...devices['iPhone 13'],
},
},
],
reporter: [
['json', { outputFile: './reports/test-results.json' }],
['html', { outputFolder: './reports/html', open: 'never' }],
['list'],
],
});
PLAYWRIGHT_CONFIG_EOF
# Replace PORT placeholder
sed -i "s/\${PORT}/$PORT/g" browser-tests/playwright.config.ts
echo "✓ Config generated"
echo ""
# Claude: Generate test spec files based on discovered features
#
# For each test category, generate a spec file:
#
# 1. navigation.spec.ts - For every discovered route:
# - Test page loads without console errors
# - Test title/heading is present
# - Test all internal links are clickable
# - Test back/forward browser navigation
# - Capture screenshot after page load
#
# 2. forms.spec.ts - For each detected form:
# - Test form renders with expected fields
# - Test empty submit shows validation errors
# - Test valid submit succeeds (or shows success state)
# - Test tab order for accessibility
# - Capture screenshots of: form, validation errors, success
#
# 3. auth.spec.ts - Only if auth detected:
# - Test login page renders
# - Test invalid credentials show error
# - Test valid login redirects (if test credentials available)
# - Test logout works
# - Test protected routes redirect to login
# - Note: Ask user for test credentials or check .env.test
#
# 4. crud.spec.ts - Only if CRUD detected:
# - Test list view loads and displays items
# - Test create form submits
# - Test edit form pre-fills data
# - Test delete shows confirmation and removes item
# - Test empty state renders
#
# 5. responsive.spec.ts - Cross-viewport comparison:
# - Test mobile menu vs desktop nav visibility
# - Test no horizontal scroll
# - Test touch targets >= 44x44px on mobile
# - Test text readability (no overflow)
#
# 6. interactive.spec.ts - For detected interactive elements:
# - Test modals open/close (click, Escape, overlay)
# - Test dropdowns expand and allow selection
# - Test accordions expand/collapse
# - Test tooltips appear on hover
#
# 7. error-states.spec.ts - Error handling:
# - Test 404 page for non-existent routes
# - Test form validation errors display
# - Test error page has navigation back to home
#
# 8. performance.spec.ts - Web vitals for all pages:
# - Measure LCP (target: <2.5s)
# - Measure CLS (target: <0.1)
# - Measure INP (target: <200ms)
# - Report per viewport
#
# 9. user-flows.spec.ts - End-to-end journeys:
# Based on detected features, generate flows like:
# - Signup-to-first-action: Register → onboard → complete task
# - Browse-to-purchase: Browse → select → cart → checkout
# - Search-and-filter: Search → filter → view result
# - Settings-update: Navigate → change → save → verify
# - Content-creation: Navigate → create → submit → verify in list
#
# Each test file should:
# - Import from '@playwright/test'
# - Use test.describe() to group related tests
# - Use test() for individual test cases
# - Access viewport via testInfo.project.name
# - Reference actual selectors/routes from Phase 2 discovery
# - Capture screenshots at key steps
# - Use meaningful test names and assertions
#
# Example test structure:
# ```typescript
# import { test, expect } from '@playwright/test';
#
# test.describe('Homepage', () => {
# test('loads successfully', async ({ page }, testInfo) => {
# await page.goto('/');
#
# // Common assertions
# await expect(page).toHaveTitle(/.+/);
# await expect(page.locator('body')).toBeVisible();
#
# // Viewport-specific assertions
# const viewport = testInfo.project.name;
# if (viewport === 'mobile') {
# await expect(page.locator('[data-testid="mobile-menu"]')).toBeVisible();
# } else {
# await expect(page.locator('[data-testid="desktop-nav"]')).toBeVisible();
# }
#
# // Screenshot
# await page.screenshot({
# path: `screenshots/${viewport}/homepage.png`,
# fullPage: true
# });
# });
# });
# ```
#
# For each spec file generated, output:
echo "✓ Generated: tests/navigation.spec.ts"
echo "✓ Generated: tests/forms.spec.ts"
# ... etc for each test file created
#
# Skip spec files for features not detected
echo ""
Phase 4: Test Execution
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Phase 4: Running Tests"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
cd browser-tests
echo "🧪 Running Playwright tests across 3 viewports..."
echo " This may take a few minutes..."
echo ""
# Run tests
npx playwright test
# Capture exit code
TEST_EXIT_CODE=$?
echo ""
if [ $TEST_EXIT_CODE -eq 0 ]; then
echo "✅ All tests passed!"
else
echo "⚠️ Some tests failed. See report for details."
echo ""
# Claude: Analyze failures
# - Read test-results.json
# - For each failure, determine if it's:
# 1. Test authoring issue (wrong selector, timing) → Fix the test
# 2. Application bug (wrong behavior) → Report it
# 3. Untestable scenario (needs real auth) → Add test.fixme() annotation
#
# If fixes are made, re-run:
# npx playwright test --last-failed
fi
cd ..
echo ""
Phase 5: Report Generation
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Phase 5: Generating Report"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "📊 Generating test report..."
# Claude: Read browser-tests/reports/test-results.json
# Generate browser-tests/reports/test-report.md with:
#
# Format:
# ```markdown
# # Browser Test Report
#
# **Generated**: 2026-02-05T12:00:00Z
# **Application**: http://localhost:3000
# **Framework**: Next.js (App Router)
#
# ---
#
# ## Summary
#
# | Viewport | Tests | Passed | Failed | Skipped |
# |----------|-------|--------|--------|---------|
# | Desktop (1920x1080) | 42 | 40 | 1 | 1 |
# | Tablet (768x1024) | 42 | 41 | 0 | 1 |
# | Mobile (375x812) | 42 | 39 | 2 | 1 |
# | **Total** | **126** | **120** | **3** | **3** |
#
# **Pass Rate**: 95.2%
#
# ---
#
# ## Routes Tested
#
# | Route | Desktop | Tablet | Mobile | Notes |
# |-------|---------|--------|--------|-------|
# | / | PASS | PASS | PASS | Homepage loads in <1s |
# | /dashboard | PASS | PASS | FAIL | Mobile nav overlaps content |
# | /products | PASS | PASS | PASS | |
# | /login | PASS | PASS | PASS | |
# | /contact | FAIL | PASS | FAIL | Form submit 500 error |
# | /404 | PASS | PASS | PASS | Custom error page works |
#
# ---
#
# ## Test Results by Category
#
# ### Navigation (8 tests per viewport)
# - ✅ All pages load without console errors
# - ✅ Internal links resolve correctly
# - ✅ Back/forward navigation works
# - ❌ Dashboard nav overlaps main content at 375px (mobile)
#
# ### Forms (6 tests per viewport)
# - ✅ Contact form renders all fields
# - ✅ Validation errors appear for empty required fields
# - ❌ Contact form submit returns 500 (server error)
# - ✅ Login form accepts credentials
#
# ### Authentication (4 tests per viewport)
# - ✅ Login page renders
# - ✅ Invalid credentials show error message
# - ⏭️ Valid login (skipped - no test credentials)
# - ✅ Protected routes redirect to /login
#
# ### User Flows (3 flows)
# - ✅ Browse-to-detail: Click product → view detail → back to list
# - ❌ Signup-to-dashboard: Form submit fails at registration step
# - ✅ Settings-update: Change setting → save → persists on reload
#
# ### Responsive Behavior (6 tests per viewport)
# - ✅ Mobile menu visible on mobile/tablet
# - ✅ Desktop nav hidden on mobile
# - ❌ Dashboard sidebar does not collapse on mobile
# - ✅ No horizontal scroll on any viewport
#
# ### Interactive Elements (5 tests per viewport)
# - ✅ Delete confirmation modal opens/closes
# - ✅ Dropdown navigation works
# - ✅ Modal closes on Escape key
#
# ### Error States (4 tests per viewport)
# - ✅ /nonexistent shows 404 page
# - ✅ 404 page has link back to home
# - ✅ Form validation errors are accessible
#
# ### Performance Metrics
#
# | Page | Metric | Desktop | Tablet | Mobile | Target | Status |
# |------|--------|---------|--------|--------|--------|--------|
# | / | LCP | 1.2s | 1.4s | 1.8s | <2.5s | ✅ |
# | / | CLS | 0.02 | 0.03 | 0.05 | <0.1 | ✅ |
# | /dashboard | LCP | 1.8s | 2.1s | 2.8s | <2.5s | ⚠️ |
# | /products | LCP | 0.9s | 1.1s | 1.3s | <2.5s | ✅ |
#
# ---
#
# ## Failures Detail
#
# ### 1. Contact Form Server Error
# **Viewports**: Desktop, Mobile
# **File**: tests/forms.spec.ts:45
# **Description**: Submitting the contact form with valid data returns HTTP 500
# **Expected**: Success message or redirect
# **Actual**: Server error response
# **Screenshot**: screenshots/desktop/contact-form-error.png
# **Recommendation**: Check the /api/contact endpoint server-side handler
#
# ### 2. Dashboard Mobile Layout
# **Viewports**: Mobile
# **File**: tests/responsive.spec.ts:23
# **Description**: Dashboard sidebar does not collapse at mobile width
# **Expected**: Sidebar hidden behind hamburger menu
# **Actual**: Sidebar overlaps main content
# **Screenshot**: screenshots/mobile/dashboard-layout-issue.png
# **Recommendation**: Add responsive breakpoint for sidebar at 768px
#
# ---
#
# ## Screenshots
#
# All screenshots saved to `browser-tests/screenshots/`:
# - `desktop/` - 12 screenshots (1920x1080)
# - `tablet/` - 12 screenshots (768x1024)
# - `mobile/` - 12 screenshots (375x812)
#
# ---
#
# ## Re-running Tests
#
# ```bash
# # Run all tests
# cd browser-tests && npx playwright test
#
# # Run specific test file
# npx playwright test tests/forms.spec.ts
#
# # Run for specific viewport only
# npx playwright test --project=mobile
#
# # Run with UI mode for debugging
# npx playwright test --ui
#
# # View HTML report
# npx playwright show-report reports/html
# ```
#
# ---
#
# ## Files Generated
#
# - `browser-tests/playwright.config.ts` - Playwright configuration
# - `browser-tests/tests/*.spec.ts` - Test spec files
# - `browser-tests/screenshots/` - Screenshots by viewport
# - `browser-tests/reports/test-report.md` - This report
# - `browser-tests/reports/test-results.json` - Machine-readable results
# - `browser-tests/reports/html/` - Interactive HTML report
# ```
echo "✓ Report generated: browser-tests/reports/test-report.md"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ Browser Testing Complete"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "📄 View report:"
echo " browser-tests/reports/test-report.md"
echo ""
echo "🖼️ Screenshots:"
echo " browser-tests/screenshots/{desktop,tablet,mobile}/"
echo ""
echo "🔄 Re-run tests:"
echo " cd browser-tests && npx playwright test"
echo ""
echo "🎭 Debug with UI:"
echo " cd browser-tests && npx playwright test --ui"
echo ""
Quick Reference
| Phase | Action | Key Output |
|---|---|---|
| 1 | Setup | Playwright installed, directories created |
| 2 | Discovery | Routes and features identified |
| 3 | Generation | Test spec files created |
| 4 | Execution | Tests run across 3 viewports |
| 5 | Report | Markdown report with results and recommendations |
Notes
- Tests run sequentially (not parallel) for predictable screenshots
- Only Chromium is installed (not Firefox/WebKit) for speed
- Tests are saved to the project (not the skill) so users can re-run them
- Screenshots captured at key steps in each test flow
- Performance metrics measured using Web Vitals API
- User flows test end-to-end journeys based on detected features
- Report includes specific recommendations for fixing failures
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?