Skip to main content

Webapp Testing

Toolkit for interacting with and testing local web applications using the Playwright MCP server. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

Web Application Testing (Playwright MCP)

Browser automation is available via the Playwright MCP server (playwright in .mcp.json). Use Playwright MCP tools to navigate, inspect, and interact with local web apps.

Scope: This skill covers Playwright MCP — the interactive browser server that agents use during verify and preview-testing phases. It is NOT about the Playwright test runner (pnpm test:e2e) used for CI E2E test suites. For E2E test patterns, see standards/core/testing.md.

Prerequisites

The dev server must be running before using browser tools. Start it first:

cd tools/prototype-scaffold && pnpm dev

Then verify the app is up at http://localhost:3000 before proceeding.

Decision Tree

Task → Is a dev server needed?
    ├─ Yes → Start server, wait for it to be ready
    │         Then: Does the page require authentication?
    │           ├─ Yes → Authenticate first (see "Authenticated Testing" below)
    │           │         Then: navigate → snapshot → interact
    │           └─ No → navigate → snapshot → interact
    └─ No (static HTML) → navigate to file:// URL directly
                           Then: snapshot → interact

Core Pattern: Snapshot-Then-Act

Always take a snapshot before interacting to discover element refs:

  1. playwright_navigate — Go to the URL
  2. playwright_screenshot — Optional: capture visual state
  3. playwright_snapshot — Get accessibility tree (preferred; use before clicks/fills)
  4. playwright_click / playwright_fill / playwright_select_option — Interact using refs from snapshot
  5. playwright_screenshot — Capture result

Key Tools

Tool When to Use
playwright_navigate Load a URL (starts a new browser session if needed)
playwright_snapshot Get page structure + element refs (use before all interactions)
playwright_screenshot Capture visual state (full page or element)
playwright_click Click a button, link, or element
playwright_fill Clear and type into an input
playwright_select_option Choose a dropdown value
playwright_press_key Send keyboard events (Enter, Tab, Escape, etc.)
playwright_evaluate Run JavaScript in the browser context
playwright_console_messages Retrieve browser console logs
playwright_wait_for Wait for navigation, network idle, or a selector condition

Common Patterns

Verify a page loads and renders key elements

1. playwright_navigate { url: "http://localhost:3000/admin" }
2. playwright_snapshot → check for expected headings/buttons
3. playwright_screenshot → visual confirmation

Fill and submit a form

For login forms, see the Authenticated Testing section. For other forms:

1. playwright_navigate { url: "http://localhost:3000/items/new" }
2. playwright_snapshot → get refs for form fields and submit button
3. playwright_fill { ref: "[name ref]", value: "Test Item" }
4. playwright_click { ref: "[submit ref]" }
5. playwright_wait_for { state: "networkidle" }
6. playwright_snapshot → verify success state

Capture console errors during interaction

1. playwright_navigate { url: "http://localhost:3000" }
2. [perform interactions]
3. playwright_console_messages → check for errors or warnings

Authenticated Testing (Clerk)

For pages behind Clerk auth (/dashboard, /settings, etc.), authenticate first using test credentials.

Prerequisites

Two environment variables must be set in your shell (typically ~/.zshenv):

  • CLERK_TEST_EMAIL — Test user email (e.g., claude@rajababa.io)
  • CLERK_TEST_PASSWORD — Test user password

Never add these to project .env* files — they can be accidentally committed.

If either variable is missing, skip authenticated testing and note it as a gap in your verification report.

Auth Flow

Development instances only — Only use this flow against a Clerk development instance. Never target staging or production.

Clerk's <SignIn /> component uses a multi-step form. Follow this sequence:

Step 0 — Resolve credentials. Retrieve both values before the Playwright flow:

echo $CLERK_TEST_EMAIL
echo $CLERK_TEST_PASSWORD

If either value is empty, skip auth testing and note the gap. The password will appear in the local conversation transcript — this is acceptable because these are dev-instance test credentials with no production access and minimal permissions. Use the returned values in steps 3 and 7.

1.  playwright_navigate { url: "http://localhost:3000/sign-in" }
2.  playwright_snapshot → find email/identifier input ref
3.  playwright_fill { ref: "[email input ref]", value: "[resolved CLERK_TEST_EMAIL]" }
4.  playwright_click { ref: "[Continue button ref]" }
5.  playwright_wait_for { state: "networkidle" }
6.  playwright_snapshot → find password input ref (new form state)
7.  playwright_fill { ref: "[password input ref]", value: "[resolved CLERK_TEST_PASSWORD]" }
8.  playwright_click { ref: "[Sign in button ref]" }
9.  playwright_wait_for { state: "networkidle" }
10. playwright_snapshot → verify redirect to protected page (e.g., /dashboard)
11. playwright_screenshot → capture authenticated state

Key details:

  • The sign-in URL is /sign-in (per NEXT_PUBLIC_CLERK_SIGN_IN_URL convention)
  • Clerk uses a two-step form: email first, then password on the next screen. You must snapshot between steps to get fresh refs
  • After authentication, the session cookie persists across subsequent playwright_navigate calls within the same MCP session
  • If the snapshot after step 10 still shows the sign-in page, authentication failed — screenshot and report the error

Verifying Auth Worked

After the auth flow, confirm you're on an authenticated page:

1. playwright_snapshot → look for user-specific elements (avatar, user name, dashboard content)
2. playwright_navigate { url: "http://localhost:3000/settings" } → navigate to another protected route
3. playwright_snapshot → confirm it loads (not redirected to /sign-in)

Troubleshooting

Symptom Likely Cause Fix
Email input not found in snapshot Clerk component hasn't loaded Add playwright_wait_for before snapshot
"Continue" does nothing Wrong ref — might be a different button Re-snapshot and look for the correct interactive element
Password step never appears Email not recognized by Clerk Verify test user exists in Clerk Dev instance
Redirected back to /sign-in after auth Session cookie not persisting Check if the app has additional middleware blocking
Rate limited by Clerk Too many rapid auth attempts Wait 60 seconds and retry

Session cleanup: Authenticated state persists for the duration of the MCP session. If you need a clean unauthenticated state for a subsequent test scenario, sign out programmatically:

1. playwright_evaluate { expression: "await window.Clerk?.signOut()" }
2. playwright_snapshot → confirm redirect to /sign-in

Alternatively, starting a new MCP session is the most reliable way to guarantee a clean state.

Best Practices

  • Always snapshot before clicking — Element refs change between page states; get fresh refs each time
  • Wait for network idle — After navigation or form submission, wait before inspecting
  • Use playwright_evaluate for complex checks — Run arbitrary JS to extract data not in the accessibility tree
  • Screenshot on failure — Capture a screenshot immediately when something unexpected happens for debugging

Fallback: Shell-Based Playwright

If the Playwright MCP server is unavailable, fall back to shell-based automation using pnpm exec playwright commands or direct Playwright scripts. See standards/core/testing.md for E2E testing patterns.

Search Framework Explorer

Search agents, skills, and standards