Agent skill
visual-testing
Use for visual UI verification with Playwright MCP. Test user flows, verify UI states, and catch visual regressions.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/visual-testing
SKILL.md
Visual Testing with Playwright
"If you didn't see it with your own eyes, how do you know it works?"
When to Apply
- Always: UI features, user flows, state changes, form interactions
- Especially: Features with visual feedback (loading states, toasts, modals)
- Skip: Pure backend changes, API-only features, CLI tools
Available Tools
Playwright MCP provides browser control via these tools:
| Tool | Purpose |
|---|---|
mcp__playwright__browser_navigate |
Go to a URL |
mcp__playwright__browser_click |
Click an element |
mcp__playwright__browser_type |
Type into an input |
mcp__playwright__browser_select_option |
Select from dropdown |
mcp__playwright__browser_hover |
Hover over element |
mcp__playwright__browser_screenshot |
Capture screenshot |
mcp__playwright__browser_evaluate |
Run JavaScript |
mcp__playwright__browser_close |
Close browser |
The Workflow
1. Start Dev Server
Ensure the app is running before visual testing:
# Check if already running
curl -s http://localhost:3000 > /dev/null && echo "Server running" || pnpm dev &
2. Navigate to Feature
mcp__playwright__browser_navigate({ url: "http://localhost:3000/documents/test-doc" })
3. Interact with UI
Test the actual user flow, not just static rendering:
# Click the edit button
mcp__playwright__browser_click({ selector: "button[aria-label='Edit']" })
# Type in the editor
mcp__playwright__browser_type({ selector: ".ProseMirror", text: "Hello world" })
# Wait for auto-save indicator
mcp__playwright__browser_screenshot({ filename: "after-edit.png" })
4. Capture Key States
Screenshot the important UI states:
- Initial load - Does the page render correctly?
- After interaction - Did the state change visually?
- Success/error states - Is feedback visible?
- Edge cases - Empty states, loading states
5. Verify with Vision
Claude can analyze screenshots to verify:
- Element visibility and positioning
- Text content and formatting
- Color and styling
- Layout and responsiveness
- Error messages and feedback
Selectors
Use stable selectors in this priority order:
- Role/Label (best):
button[aria-label='Save'],input[name='email'] - Test ID:
[data-testid='submit-btn'] - Semantic HTML:
button,input[type='email'] - Class (avoid):
.btn-primary(brittle)
Common Flows
Document Editing
1. Navigate to /documents/{id}
2. Click in editor
3. Type content
4. Screenshot → verify "Saving..." appears
5. Wait 1 second
6. Screenshot → verify "Saved" appears
7. Navigate away and back
8. Screenshot → verify content persisted
Form Submission
1. Navigate to form page
2. Fill required fields with browser_type
3. Screenshot → verify form state
4. Click submit
5. Screenshot → verify success/error state
6. If error, verify message is helpful
Navigation Flow
1. Navigate to starting page
2. Screenshot initial state
3. Click navigation element
4. Screenshot → verify correct page loaded
5. Click back
6. Screenshot → verify return to original
Authentication for Protected Pages
Most Brief pages require authentication. Playwright tests use @clerk/testing to handle this.
Environment Variables
Set these in your .env or shell:
PLAYWRIGHT_TEST_USER_EMAIL=test@example.com
PLAYWRIGHT_TEST_USER_PASSWORD=your-test-password
How It Works
-
Auth Setup (
e2e/auth.setup.ts):- Uses
setupClerkTestingToken()to bypass bot detection - Signs in with test credentials
- Saves auth state to
playwright/.clerk/user.json
- Uses
-
Test Projects (
playwright.config.ts):chromium: Authenticated tests (loads saved auth state)chromium-no-auth: Unauthenticated tests (for sign-in flow testing)
-
State Persistence:
- Auth state is saved after first sign-in
- Subsequent runs reuse the saved session
- State files are gitignored
Running Authenticated Tests
# Run all tests (will authenticate first)
pnpm test:e2e
# Run only authenticated tests
pnpm test:e2e --project=chromium
# Run only unauthenticated tests
pnpm test:e2e --project=chromium-no-auth
For MCP Visual Testing
The Playwright MCP browser is a separate instance from the Playwright test runner, so it doesn't automatically load saved auth state. The MCP browser persists cookies within a Claude Code session, so you only need to sign in once per session.
⚠️ CRITICAL: Clerk uses MULTI-STEP sign-in!
- Page 1: Enter EMAIL only → click Continue
- Page 2 (
/sign-in/factor-one): Enter PASSWORD → click ContinueDo NOT try to fill password on the email page - it doesn't exist there!
Test credentials (from .env.local):
- Email:
PLAYWRIGHT_TEST_USER_EMAIL(test@briefhq.ai) - Password:
PLAYWRIGHT_TEST_USER_PASSWORD
Sign-in Flow via MCP
-
Navigate to sign-in:
textmcp__playwright__browser_navigate({ url: "http://localhost:3000/sign-in" }) -
Take a snapshot to get element refs:
textmcp__playwright__browser_snapshot() -
Fill email and continue:
textmcp__playwright__browser_type({ ref: "[identifier-input-ref]", text: "test@briefhq.ai", element: "Email input" }) mcp__playwright__browser_click({ ref: "[continue-button-ref]", element: "Continue button" }) -
Wait for password step, take snapshot, then fill password:
textmcp__playwright__browser_wait_for({ text: "Password" }) mcp__playwright__browser_snapshot() mcp__playwright__browser_type({ ref: "[password-input-ref]", text: "<password>", element: "Password input" }) mcp__playwright__browser_click({ ref: "[continue-button-ref]", element: "Continue button" }) -
Wait for redirect away from sign-in, then continue testing
Important Notes:
- Use
browser_snapshotto get element refs - refs change between page loads - Clerk uses multi-step sign-in: email first, then redirects to
/sign-in/factor-onefor password - The MCP browser persists cookies, so subsequent navigations stay authenticated
- Close browser with
browser_closewhen done to free resources
Quick Check: Already Authenticated?
Navigate to a protected page and check the URL:
mcp__playwright__browser_navigate({ url: "http://localhost:3000" })
If you see the home page (not /sign-in), you're already authenticated from a previous interaction.
Creating Test Users
Create a dedicated test user in your Clerk dev instance:
- Go to Clerk Dashboard > Users
- Create user with known email/password
- Store credentials in env vars (never commit!)
Integration with Ralph
When --visual-check is enabled, Ralph will:
- Add Playwright tools to allowed tools
- Include visual verification instructions in prompts
- Expect visual verification results in activity.md
Example Activity Log Entry
## Visual Verification
Tested SaveStatus component after implementation:
1. Navigated to http://localhost:3000/documents/test-doc
2. Made edit in editor
3. Screenshot: SaveStatus showing "Saving..." ✅
4. Waited for debounce
5. Screenshot: SaveStatus showing "Saved" with green text ✅
6. Navigated away and back
7. Screenshot: Content persisted correctly ✅
All visual checks passed.
Red Flags
- Testing only happy path (test errors too!)
- Not waiting for async operations before screenshot
- Using unstable selectors (indexes, generated classes)
- Skipping visual verification for "simple" UI changes
- Not testing on different viewport sizes
Best Practices
- Wait for stability before screenshots (animations, loading)
- Test real user flows not just individual components
- Verify error states not just success
- Document findings in activity.md with screenshot filenames
- Close browser when done to free resources
References
brief-designskill for design system tokens and patternstesting-strategyskill for coverage requirements- Playwright docs: https://playwright.dev/docs/api/class-page
Didn't find tool you were looking for?