---
name: test-web-app-with-playwright
description: Tests a local web app in a real headless browser with Playwright - start the dev server, wait for the page to load, look before you click, then script the flow and capture screenshots and console errors. Use when the user wants to check a page works, click through a flow, take a screenshot, or see browser console logs.
license: Apache-2.0
compatibility: Needs Node 18+ or Python 3.8+ and Playwright browsers (npx playwright install chromium)
metadata:
  category: debugging
  tags: "playwright,testing,browser"
  author: johnny-bravo
  version: "1.0"
  updated: "2026-10-31"
  status: published
  source_url: "https://github.com/anthropics/skills/tree/ca45fc496a3436251f191354091d557da31c15b5/skills/webapp-testing"
  source_license: Apache-2.0
  copyright: "Copyright 2026 Anthropic, PBC."
  original_author: "Anthropic (anthropics/skills, webapp-testing)"
  modified: "Adapted by TheSkillVault: rewritten for beginners, added a JavaScript test-runner path next to Python, dropped the bundled helper scripts, added safety and done-when sections."
  imported_on: "2026-10-31"
---

# Test a web app with Playwright

Drive your app in a real browser, the way a user would. First look at what is on the page, then act on what you found.

## When to use
- You want proof that a page or flow (sign-up, checkout, form) works.
- You need a screenshot, or the browser console errors, from a local app.
- A click or form "does nothing" and you want to see why.

## Steps
1. **Install.** JavaScript: `npm i -D @playwright/test` then `npx playwright install chromium`. Python: `pip install playwright` then `playwright install chromium`.
2. **Start the app.** Run your dev server (for example `npm run dev`). In `playwright.config.ts`, the `webServer` option can start and stop it for you.
3. **Open and wait.** Go to the URL and wait for the page to settle (`waitForLoadState('networkidle')`) before reading anything. Dynamic apps render after the first load.
4. **Look first.** Take a full-page screenshot and list the buttons, links and inputs. Pick selectors from what is really there.
5. **Prefer user-facing selectors.** Use `getByRole('button', { name: 'Sign up' })`, `getByLabel` or `getByText`. Fall back to CSS or IDs only when needed.
6. **Script the flow.** Fill, click and check results with `expect(...)`. Do one user goal per test.
7. **Capture the console.** Listen to `page.on('console')` and `page.on('pageerror')`, and fail the test on unexpected errors.
8. **Run headless.** Use `npx playwright test` (or `python your_test.py`), and close the browser at the end. Open the HTML report or trace when something fails.

## Example (JavaScript)
```ts
import { test, expect } from "@playwright/test";
test("sign-up works", async ({ page }) => {
  await page.goto("http://localhost:3000/signup");
  await page.getByLabel("Email").fill("test@example.com");
  await page.getByRole("button", { name: "Sign up" }).click();
  await expect(page.getByText("Check your inbox")).toBeVisible();
});
```

## Gotchas
- Reading the page before it settles gives empty or wrong results on dynamic apps. Wait first.
- Test against localhost or a staging copy, never against live customer accounts.
- Use throwaway test users. Keep passwords and API keys in environment variables, not in test files or screenshots.

## Works with any stack
Any web framework works, because Playwright only sees the browser. If you use Python, the same API exists with snake_case names (`wait_for_load_state`).

## Done when
- The test runs headless and passes from a clean start.
- It fails if you break the feature on purpose.
- No unexpected console errors appear during the run.

## Example prompt
"Click through my sign-up form in a browser and tell me if it works, with a screenshot."

---
Adapted from "webapp-testing" in anthropics/skills (Apache-2.0, Copyright 2026 Anthropic, PBC). Changed by TheSkillVault as noted above. See LICENSE.txt.
