look-before-you-leap/skills/webapp-testing/SKILL.md
End-to-end webapp testing with Playwright MCP integration. Use when: writing Playwright tests, E2E testing, browser testing, webapp testing, visual regression testing, accessibility testing with axe-core, testing user flows through a web UI, verifying frontend behavior in a real browser. Integrates with test-driven-development skill for test-first browser tests and engineering-discipline for verification. Do NOT use when: unit tests only (no browser UI involved), API tests without UI, mobile native testing (use react-native-mobile), testing CLI tools, or writing backend-only integration tests.
npx skillsauth add miospotdevteam/claude-control webapp-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Test web applications through a real browser using Playwright. This skill covers reconnaissance (exploring the app before writing tests), test strategy selection, Playwright MCP integration for interactive exploration, and structured test implementation.
Announce at start: "I'm using the webapp-testing skill to guide browser test development."
Prerequisite: The project must have a web application with a UI. If there is no UI to test, this skill does not apply.
Before writing any tests, determine the application type:
Is there a web UI to test?
├── No → This skill does not apply. Use unit/integration tests.
└── Yes
├── Static HTML (no JS, no dynamic content)?
│ └── Lightweight: use Playwright's built-in test runner
│ with simple navigation + content assertions.
│ No server lifecycle management needed if files are local.
│
└── Dynamic webapp (React, Vue, Svelte, Next.js, etc.)?
├── Already has Playwright configured?
│ └── Use existing config. Read playwright.config.ts,
│ understand baseURL, test directory, projects.
│
└── No Playwright setup?
└── Set up from scratch:
1. Install @playwright/test
2. Create playwright.config.ts
3. Configure webServer (or use with_server.py)
4. Create first test file
Use npx playwright test when:
playwright.config.tswebServer config to auto-start the dev serverUse a standalone script (with with_server.py) when:
With test-driven-development: When TDD is active, the RED phase writes a failing Playwright test (browser assertion fails), the GREEN phase implements the feature until the browser test passes, and REFACTOR cleans up both test and implementation code. Each TDD cycle produces one user- visible behavior verified through the browser.
With engineering-discipline: After tests are written, run the full verification suite (type checker, linter, all tests including Playwright).
With systematic-debugging: When a test fails unexpectedly, use the debugging skill's Phase 1 investigation before modifying test code. Trace whether the failure is in the app, the test, or a timing issue.
Do NOT write tests before understanding the application. Explore first.
Read these files before opening a browser:
package.json — scripts, dependencies, dev server commandplaywright.config.ts (if exists) — baseURL, test directory, projectsapp/ or pages/, React Router config,
Vue Router, SvelteKit routes/Identify the correct command from package.json scripts. Common patterns:
npm run dev / yarn dev / pnpm devnpm startUse with_server.py (see scripts/with_server.py) to manage server
lifecycle, or use Playwright's webServer config. See
references/server-recipes.md for framework-specific configurations.
Use the Playwright MCP tools to navigate and understand the app:
Step 1: Navigate to the app
→ browser_navigate to the base URL
Step 2: Take an accessibility snapshot
→ browser_snapshot to see the page structure, interactive elements,
and current state
Step 3: Interact with key flows
→ browser_click, browser_fill_form, browser_press_key to walk through
the primary user journeys
Step 4: Check multiple routes
→ browser_navigate to each route, browser_snapshot each one
Step 5: Check responsive behavior
→ browser_resize to mobile (375px) and tablet (768px) widths
→ browser_snapshot at each size
Document findings in discovery.md:
Based on reconnaissance, categorize:
| Priority | What to test | Why | |---|---|---| | Critical | Authentication flows, payment/checkout, data submission | User-blocking if broken | | High | Navigation between routes, search/filter, CRUD operations | Core functionality | | Medium | Responsive layout, error states, loading states | Quality and edge cases | | Low | Animations, tooltips, non-critical UI details | Nice-to-have |
| Approach | When | Example | |---|---|---| | Smoke tests | Verify the app loads and critical paths work | Navigate to /, verify heading visible | | Flow tests | Test complete user journeys end-to-end | Sign up → verify email → log in → create item | | Component tests | Test isolated interactive components | Date picker selects correct date, modal opens/closes | | Visual regression | Verify UI appearance hasn't changed | Screenshot comparison of key pages | | Accessibility tests | Verify WCAG compliance | axe-core scan of each route |
tests/
├── e2e/
│ ├── auth.spec.ts # Login, signup, logout flows
│ ├── navigation.spec.ts # Route navigation, breadcrumbs
│ └── [feature].spec.ts # One file per feature area
├── visual/
│ └── screenshots.spec.ts # Visual regression tests
├── a11y/
│ └── accessibility.spec.ts # axe-core scans
└── fixtures/
├── auth.ts # Authentication state setup
└── test-data.ts # Shared test data
Decide how the dev server will be managed:
Option A: Playwright webServer config (preferred for CI)
// playwright.config.ts
export default defineConfig({
webServer: {
command: 'npm run dev',
port: 3000,
reuseExistingServer: !process.env.CI,
},
});
Option B: with_server.py script (flexible, multi-server)
python3 scripts/with_server.py \
--cmd "npm run dev" --port 3000 \
--test-cmd "npx playwright test"
Option C: External server (already running)
// playwright.config.ts
export default defineConfig({
use: { baseURL: 'http://localhost:3000' },
// No webServer — assumes server is already running
});
Read references/playwright-patterns.md for detailed patterns on:
When the TDD skill is active, each cycle looks like:
test('user can create a new project', async ({ page }) => {
await page.goto('/dashboard');
await page.getByRole('button', { name: 'New Project' }).click();
await page.getByLabel('Project name').fill('My Project');
await page.getByRole('button', { name: 'Create' }).click();
await expect(page.getByText('My Project')).toBeVisible();
});
Install and configure:
npm install -D @axe-core/playwright
Write accessibility tests:
import AxeBuilder from '@axe-core/playwright';
test('home page has no accessibility violations', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
// Test specific sections
test('navigation is accessible', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page })
.include('nav')
.analyze();
expect(results.violations).toEqual([]);
});
// Exclude known issues while fixing them
test('dashboard accessibility (excluding known issues)', async ({ page }) => {
await page.goto('/dashboard');
const results = await new AxeBuilder({ page })
.disableRules(['color-contrast']) // TODO: fix contrast on sidebar
.analyze();
expect(results.violations).toEqual([]);
});
Run accessibility tests on every route discovered in Phase 1.
Playwright has built-in screenshot comparison:
test('landing page visual regression', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('landing.png', {
maxDiffPixelRatio: 0.01,
});
});
// Component-level screenshots
test('pricing cards visual regression', async ({ page }) => {
await page.goto('/pricing');
const cards = page.getByTestId('pricing-cards');
await expect(cards).toHaveScreenshot('pricing-cards.png');
});
First run: Creates baseline screenshots in tests/*.spec.ts-snapshots/.
Commit these to the repo.
Subsequent runs: Compares against baselines. If visuals changed
intentionally, update with npx playwright test --update-snapshots.
Gotchas:
await page.emulateMedia({ reducedMotion: 'reduce' });
# Run all Playwright tests
npx playwright test
# Run with UI mode for debugging
npx playwright test --ui
# Run specific test file
npx playwright test tests/e2e/auth.spec.ts
# Run with specific browser
npx playwright test --project=chromium
# Show HTML report
npx playwright show-report
Check that tests cover:
Run tests 3 times to check for flakiness:
npx playwright test --repeat-each=3
If any test fails intermittently, fix it before declaring done. Common causes of flakiness:
await on assertionspage.waitForResponse()page.waitForTimeout() as last resort| Anti-Pattern | Why It Fails | Correct Approach |
|---|---|---|
| Testing without exploring the app first | You'll miss flows, write incomplete tests | Complete Phase 1 reconnaissance first |
| Selectors based on CSS classes or DOM structure | Brittle — breaks on any refactor | Use role-based selectors (getByRole, getByLabel) |
| page.waitForTimeout(5000) everywhere | Slow and flaky — fails under load | Use auto-wait, waitForResponse, waitForSelector |
| One giant test for the entire flow | Hard to debug, masks which step failed | One test per logical user action |
| No server lifecycle management | Tests fail because server isn't running | Use webServer config or with_server.py |
| Ignoring accessibility testing | Ships inaccessible product | Run axe-core on every route |
| Skipping visual regression | UI regressions slip through | Screenshot baselines for key pages |
| Testing implementation details via DOM | Couples tests to code structure | Test user-visible behavior |
All paths relative to ${CLAUDE_PLUGIN_ROOT}/skills/webapp-testing/.
| Reference | When to use |
|---|---|
| references/playwright-patterns.md | Writing test code — selectors, assertions, patterns |
| references/server-recipes.md | Configuring dev server for common frameworks |
| scripts/with_server.py | Managing dev server lifecycle for test runs |
Related skills:
look-before-you-leap:test-driven-development — for test-first browser testslook-before-you-leap:engineering-discipline — for verification after testslook-before-you-leap:systematic-debugging — for investigating test failuresdevelopment
Use after discovery to write implementation plans with TDD-granularity steps. Produces plan.json (immutable definition, frozen after approval), progress.json (mutable execution state), and masterPlan.md (user-facing proposal for Orbit review). Every step is one component/feature; TDD rhythm (test, verify fail, implement, verify pass, commit) lives in its progress items. Consumes discovery.md from exploration phase. Make sure to use this skill whenever the user says discovery is done, exploration is finished, discovery.md is ready, or asks to write/create/draft the implementation plan — even if they don't mention plan.json or masterPlan.md by name. Also use when the user references completed exploration findings, blast radius analysis, or consumer mappings and wants them converted into actionable steps. Do NOT use when: the user says 'just do it' or 'no plan', resuming or executing an existing plan, during exploration or brainstorming (discovery not yet complete), debugging, or code review.
development
Test-Driven Development workflow enforcing red-green-refactor cycles. Use when writing new features, adding behavior, or implementing functions where tests should drive design. Requires explicit test-first prompting because Claude naturally writes implementation first. Integrates with writing-plans (TDD rhythm in Progress items) and engineering-discipline (verification). Do NOT use when: fixing a bug in existing tested code (use systematic-debugging), writing tests for existing untested code (characterization tests are a different workflow), refactoring without behavior change (use refactoring), or the project has no test infrastructure.
development
Use when encountering any bug, test failure, or unexpected behavior. Enforces root cause investigation before fixes. Four phases: investigate, analyze patterns, form hypotheses, implement. Prevents guess-and-check thrashing. Use ESPECIALLY when under pressure or when 'just one quick fix' seems obvious. Do NOT use for: learning unfamiliar APIs (use exploration), performance optimization without a specific regression, or code review without a reported bug.
development
Generate distinctive, production-quality SVG artwork inline in code — decorative backgrounds, abstract illustrations, generative patterns, filter effects, section dividers, brand marks, data visualizations, and animated elements. Pure hand-coded SVG with no external image assets or libraries. Use this skill whenever the user asks for: SVG illustrations, decorative SVG backgrounds, SVG patterns, SVG textures, grain/noise effects, generative art, abstract shapes, blob shapes, topographic patterns, mesh gradients, hero illustrations, SVG icons, section dividers, SVG filters, duotone effects, glow effects, SVG data visualization, sparklines, inline charts, or any request where visual art should be created as SVG code rather than imported as an image. Also trigger when frontend-design produces a design that calls for decorative artwork, custom illustrations, or textured backgrounds. Do NOT use for: GSAP-driven SVG animation (use immersive-frontend), raster image editing, CSS-only effects that don't need SVG, or simple geometric shapes that don't require artistic direction.