Overview
This skill systematically tests every page in an application using Playwright MCP. It verifies page loading, element rendering, interaction functionality, and error detection.
Standard Test Plan Location
Plan file: tests/e2e-test-plan.md
This skill reads the page inventory from the test plan at tests/e2e-test-plan.md. If the plan file doesn't exist, the calling command should invoke the e2e-test-plan skill first to generate it.
Purpose
Ensure that:
- All pages load without errors
- All expected elements are present
- All interactions work correctly
- No console or network errors occur
- Pages are accessible and functional
Workflow
Step -1: Test Plan Verification (REQUIRED FIRST)
CRITICAL: Before testing pages, verify the test plan exists.
-
Check for Test Plan
- Look for
tests/e2e-test-plan.md - If the file exists, read the "Pages to Test" section
- If the file does NOT exist, STOP and report that the plan must be generated first
- Look for
-
Read Page List from Plan
- Extract public pages
- Extract authenticated pages
- Extract admin pages
- Use this list for testing
Step 0: Build Assets & Verify URL (CRITICAL - DO THIS FIRST)
Before testing any pages, build assets and verify the application is accessible.
0a. Build Application Assets
Missing assets are a common cause of E2E test failures. Before testing:
-
Check for package.json
Look for package.json in project root If found, assets likely need building -
Run Build Commands
npm install # If node_modules missing npm run build # Compile production assets # or for dev server: npm run dev # Start Vite/webpack dev server -
Detect Build Issues After loading a page, check for:
- Unstyled content (missing CSS)
- Blank pages (missing JS)
- Console errors: "Failed to load resource"
- Network 404s for .js, .css, .png files
- Errors about /build/, /dist/, /assets/
If assets are missing:
- Stop testing
- Run
npm install && npm run build - Restart and retest
0b. URL/Port Verification
-
Navigate to Base URL
browser_navigate({ url: base_url }) browser_snapshot() -
Verify Correct Application Check the snapshot for:
- ✅ Application name, logo, or known branding
- ✅ Expected navigation structure
- ✅ Known page elements from codebase analysis
- ❌ Default server pages ("Welcome to nginx!", "It works!", "Apache2 Ubuntu Default Page")
- ❌ Connection errors ("This site can't be reached", "Connection refused")
- ❌ Different/unexpected application content
-
Port Discovery (if verification fails) If the page doesn't match expected application:
Common ports to try: - http://localhost:8000 (Laravel/Django) - http://localhost:8080 (Common alternative) - http://localhost:3000 (Node.js/React/Next.js) - http://localhost:5173 (Vite dev server) - http://localhost:5174 (Vite alternative port) - http://localhost:5000 (Flask/Python) - http://localhost:4200 (Angular) - http://localhost:8888 (Jupyter/custom)For each port:
browser_navigate({ url: "http://localhost:{port}" }) browser_snapshot() // Check if this matches the expected application // If yes, use this as the new base URL -
Check Project Configuration If port discovery fails, look for hints in:
.envfile (APP_PORT, PORT, VITE_PORT, SERVER_PORT)package.jsonscripts (look for --port flags)vite.config.js/ts(server.port setting)docker-compose.yml(port mappings).env.examplefor default port values
-
Proceed or Stop
- If correct URL found: Update base_url and continue testing
- If URL differs from provided: Log warning in test report
- If no working URL found: STOP TESTING and report error
- "Application not accessible at {provided_url}"
- "Ports attempted: 8000, 8080, 3000, 5173, 5000, 4200"
- "Suggestion: Verify the development server is running"
Step 1: Page Inventory
-
List All Pages
- Extract from route definitions
- Include dynamic route patterns
- Note authentication requirements
-
Categorize Pages
- Public pages
- Authenticated pages
- Admin pages
- Special pages (error pages, maintenance, etc.)
-
Define Expected Elements
- Navigation elements
- Main content areas
- Forms and inputs
- Action buttons
- Footer elements
Step 2: Page Load Testing
For EACH page:
-
Navigate to Page
browser_navigate({ url: "/page-path" }) -
Wait for Load
browser_wait_for({ text: "Expected content" }) OR browser_wait_for({ time: 2 }) -
Capture Snapshot
browser_snapshot() -
Check Console Messages
browser_console_messages({ level: "error" }) -
Check Network Requests
browser_network_requests()
Step 3: Element Verification
For each page, verify:
-
Navigation
- Header present
- Menu items visible
- Logo displayed
- Navigation links work
-
Main Content
- Title/heading present
- Expected content visible
- Images loaded
- Data displayed (if applicable)
-
Forms (if present)
- All inputs visible
- Labels present
- Submit button enabled
- Validation messages work
-
Footer
- Footer visible
- Links work
- Copyright present
Step 4: Interaction Testing
-
Link Testing
For each link on page: browser_click on link browser_snapshot to verify destination browser_navigate_back -
Button Testing
For each button: browser_click on button Verify expected action occurs Check for errors -
Form Testing
browser_fill_form with test data browser_click submit Verify success or validation errors -
Dropdown Testing
browser_select_option on dropdowns Verify selection applied
Step 5: Error Detection
-
Console Errors
browser_console_messages({ level: "error" }) Common errors to detect: - Uncaught exceptions - Failed to load resource - CORS errors - API errors - Component errors -
Network Errors
browser_network_requests() Check for: - 4xx errors (client errors) - 5xx errors (server errors) - Failed requests - Timeout errors -
Visual Errors
browser_snapshot() Look for: - Broken layout - Missing images - Overlapping elements - Unreadable text
Step 6: Responsive Testing
Test each page at multiple viewports:
-
Desktop (1920x1080)
browser_resize({ width: 1920, height: 1080 }) browser_navigate to page browser_snapshot Verify desktop layout -
Tablet (768x1024)
browser_resize({ width: 768, height: 1024 }) browser_navigate to page browser_snapshot Verify tablet layout -
Mobile (375x812)
browser_resize({ width: 375, height: 812 }) browser_navigate to page browser_snapshot Verify mobile layout Verify mobile menu works
Test Patterns
Asset Build Verification (RUN BEFORE TESTING)
// Step 1: Check if assets need building
1. Check for package.json in project root
2. If node_modules missing: run npm install
3. Run npm run build (or npm run prod)
// Step 2: Verify assets after page load
4. browser_navigate to any page
5. browser_snapshot() - check for styled content
6. browser_console_messages({ level: "error" })
- Look for "Failed to load resource"
- Look for "404 (Not Found)"
- Look for module/import errors
7. browser_network_requests()
- Check for 404s on .js, .css, .png files
- Check for failed requests to /build/, /dist/, /assets/
// If assets missing:
8. STOP testing
9. Report: "Assets not built. Run: npm install && npm run build"
10. After build, restart testing
URL Verification Test (RUN FIRST)
// Step 1: Try provided URL
1. browser_navigate({ url: base_url })
2. snapshot = browser_snapshot()
// Step 2: Check if correct application
3. If snapshot shows:
- "Welcome to nginx!" → WRONG URL
- "It works!" → WRONG URL
- "Apache2 Ubuntu Default Page" → WRONG URL
- "This site can't be reached" → CONNECTION ERROR
- Expected app content → CORRECT URL ✓
// Step 3: Port discovery if needed
4. If WRONG URL:
ports = [8000, 8080, 3000, 5173, 5174, 5000, 4200]
for port in ports:
browser_navigate({ url: `http://localhost:${port}` })
snapshot = browser_snapshot()
if snapshot shows expected app content:
base_url = `http://localhost:${port}`
break
// Step 4: Report result
5. If correct URL found:
Log: "Application verified at {base_url}"
Continue with testing
6. If no correct URL:
STOP TESTING
Report: "Cannot find application. Ports tried: ..."
Basic Page Test
1. browser_navigate({ url: "/page" })
2. browser_wait_for({ time: 2 }) // Wait for load
3. snapshot = browser_snapshot()
4. errors = browser_console_messages({ level: "error" })
5. requests = browser_network_requests()
// Verify
Assert: snapshot contains expected elements
Assert: errors is empty
Assert: no failed requests in network
Form Page Test
1. browser_navigate({ url: "/form-page" })
2. browser_snapshot() // Verify form present
// Test empty submission
3. browser_click({ element: "Submit button", ref: "[submit-ref]" })
4. browser_snapshot() // Should show validation errors
// Test valid submission
5. browser_fill_form({
fields: [
{ name: "Name", type: "textbox", ref: "[name-ref]", value: "Test User" },
{ name: "Email", type: "textbox", ref: "[email-ref]", value: "test@example.com" }
]
})
6. browser_click({ element: "Submit button", ref: "[submit-ref]" })
7. browser_wait_for({ text: "Success" })
8. browser_snapshot() // Verify success
Navigation Test
1. browser_navigate({ url: "/" })
2. browser_snapshot() // Get all navigation refs
For each nav link:
3. browser_click({ element: "Nav link", ref: "[link-ref]" })
4. browser_snapshot() // Verify correct page loaded
5. browser_navigate_back()
Dynamic Content Test
1. browser_navigate({ url: "/data-page" })
2. browser_wait_for({ text: "Loading..." }) // Wait for loading state
3. browser_wait_for({ textGone: "Loading..." }) // Wait for content
4. browser_snapshot() // Verify data displayed
5. browser_console_messages({ level: "error" }) // Check for errors
Common Page Types
Home Page
Expected Elements:
- Hero section with headline
- Feature highlights
- Call-to-action buttons
- Navigation header
- Footer
Tests:
- [ ] Hero content visible
- [ ] CTA buttons clickable
- [ ] Navigation works
- [ ] Footer links work
Login Page
Expected Elements:
- Email/username field
- Password field
- Submit button
- Forgot password link
- Register link
Tests:
- [ ] Form displays correctly
- [ ] Empty submission shows errors
- [ ] Invalid credentials show error
- [ ] Valid credentials redirect
- [ ] Forgot password link works
Dashboard Page
Expected Elements:
- Welcome message
- Statistics/widgets
- Navigation sidebar
- User menu
- Action buttons
Tests:
- [ ] Loads for authenticated users
- [ ] Redirects unauthenticated users
- [ ] Widgets display data
- [ ] Actions are functional
List Page
Expected Elements:
- Data table or list
- Pagination
- Search/filter
- Action buttons (edit, delete)
Tests:
- [ ] Data displays correctly
- [ ] Pagination works
- [ ] Search filters data
- [ ] Actions are functional
- [ ] Empty state handled
Form Page
Expected Elements:
- Form fields
- Labels
- Validation messages
- Submit button
- Cancel button
Tests:
- [ ] All fields editable
- [ ] Validation works
- [ ] Submit saves data
- [ ] Cancel returns to list
- [ ] Required fields enforced
Output Format
Page Test Results
# Page Test Results
## Pre-Test Verification
### Asset Build Status
- Build command run: npm run build ✓
- Assets compiled: Yes
- CSS loaded: Yes
- JavaScript loaded: Yes
- No 404 errors on assets: Yes
(or if assets were missing:)
- Build command run: No ⚠️
- Assets compiled: No
- Issue: Missing /build/assets/app.js (404)
- Resolution: Ran `npm install && npm run build`
- Retested: All assets now loading ✓
### URL Verification
- Provided URL: http://localhost:8000
- Verified URL: http://localhost:8000 ✓
- Status: Application confirmed
(or if port was different:)
- Provided URL: http://localhost:8000
- Verified URL: http://localhost:3000 ⚠️
- Status: Application found on different port
- Note: Server appears to be running on port 3000
## Summary
- Total Pages: 25
- Passed: 23
- Failed: 2
- Skipped: 0
## Detailed Results
### Public Pages
#### Home (/)
- Status: PASSED
- Load Time: 1.2s
- Console Errors: 0
- Network Errors: 0
- Elements Verified:
- [x] Header navigation
- [x] Hero section
- [x] Feature cards
- [x] Footer
#### About (/about)
- Status: PASSED
- Load Time: 0.8s
- Console Errors: 0
- Network Errors: 0
- Elements Verified:
- [x] Page title
- [x] Content sections
- [x] Team members
### Authenticated Pages
#### Dashboard (/dashboard)
- Status: FAILED
- Load Time: 2.5s
- Console Errors: 1
- Error: "Cannot read property 'name' of undefined"
- Network Errors: 0
- Elements Verified:
- [x] Welcome message
- [ ] Statistics widget - MISSING
- [x] Recent activity
#### Profile (/profile)
- Status: PASSED
- Load Time: 1.1s
- Console Errors: 0
- Network Errors: 0
- Elements Verified:
- [x] User information
- [x] Edit button
- [x] Avatar
### Responsive Tests
#### Home Page
- Desktop (1920x1080): PASSED
- Tablet (768x1024): PASSED
- Mobile (375x812): FAILED
- Issue: Navigation menu overlaps content
## Errors Found
1. **Dashboard Widget Error**
- Page: /dashboard
- Error: Cannot read property 'name' of undefined
- Likely Cause: User data not loaded before rendering
2. **Mobile Navigation Issue**
- Page: /home
- Issue: Navigation overlaps on mobile
- Likely Cause: CSS media query issue
## Recommendations
1. Fix Dashboard data loading sequence
2. Adjust mobile navigation CSS
3. Add loading states for async data
Best Practices
- Wait for Page Load - Don't check elements too quickly
- Use Snapshots - Capture state at each step
- Check Console/Network - Look for hidden errors
- Test All Viewports - Responsive issues are common
- Document Everything - Note all elements tested
- Test Interactions - Don't just check static content
- Handle Dynamic Content - Wait for data to load