Ben Weese · benweese.com All projects

playwright-ai-qa-agents

Validate plugin

A Claude Code plugin, playwright-qa-agents, that turns "test this feature" into reviewed, runnable Playwright tests in TypeScript. Agents plan the scenarios, stop for a human to review the plan, then write the API clients, page objects and specs, run them, and repair broken UI locators within a fixed budget.

Docs site (this README, the worked example and the changelog)

By Ben Weese · more projects at code.benweese.com

How it fits

It is one of three repos that work together:

Repo Role
playwright-test-commons Shared framework code the generated tests use
playwright-ai-qa-agents (this repo) The Claude Code plugin
playwright-e2e-demo A real suite for automationexercise.com, written with this plugin

The workflow

flowchart LR
    B["description of the<br/>feature or change"] --> M["page-mapper<br/>(UI only)"]
    M --> P[planner]
    B --> P
    P --> R{{"human review<br/>of plans/&lt;feature&gt;.md"}}
    R --> G[generator]
    G --> X[run]
    X -->|"locator / timing failure (UI)"| H["healer<br/>max 3 attempts"]
    X -->|"site disagrees with plan"| BUG[bug report]
Loading

The plan opens with numbered acceptance criteria (AC-1, AC-2, ...), and each scenario lists the criteria it covers. Each scenario also gets an id, a number unique across the repo (#0012), that goes into its test title. Ids don't encode the kind of test; tags such as @smoke, @api and @ui do. A failing test points straight back to its written steps, its expected result and the requirement behind it.

docs/worked-example.md follows one real feature, the cart in playwright-e2e-demo, through every stage, from page map to the healer's final diff.

Requirements

Install

From a terminal, in the test repo:

claude plugin marketplace add benweese/playwright-ai-qa-agents
claude plugin install playwright-qa-agents@playwright-ai-qa-agents

The terminal works everywhere. The /plugin command isn't available in every client (the VS Code extension doesn't have it); where it is, these do the same:

/plugin marketplace add benweese/playwright-ai-qa-agents
/plugin install playwright-qa-agents@playwright-ai-qa-agents

Plugins load when a session starts. After installing, start a new Claude Code session before using the agents. In VS Code, run Developer: Reload Window from the command palette, or open a new Claude Code tab.

To suggest the plugin to everyone who opens the test repo, also name it in the repo's .claude/settings.json:

{
  "extraKnownMarketplaces": {
    "playwright-ai-qa-agents": {
      "source": {
        "source": "github",
        "repo": "benweese/playwright-ai-qa-agents"
      }
    }
  },
  "enabledPlugins": {
    "playwright-qa-agents@playwright-ai-qa-agents": true
  }
}

This records the marketplace and the plugin, but it doesn't install it on its own: in the VS Code extension the plugin didn't load from this file alone, only after the terminal install above. Keep the terminal steps in the test repo's README.

To pick up a new version, run claude plugin update playwright-qa-agents@playwright-ai-qa-agents (or /plugin update), then start a new session.

Check it loaded

Claude Code no longer has an /agents command. Instead, ask Claude in the new session:

List the subagents and skills from the playwright-qa-agents plugin.

It should name six agents (page-mapper, api-test-planner, ui-test-planner, api-test-generator, ui-test-generator, ui-test-healer) and the skills in the Skills table, each prefixed playwright-qa-agents:. If it finds none, the plugin isn't installed or the session started before the install: run claude plugin list in a terminal, then start a new session.

What the test repo needs

Usage

Start the whole flow with a description of the feature or change, a page URL, or a path to a requirements file:

/playwright-qa-agents:author-tests the product search page and POST /api/searchProduct

It maps the page, drafts plans/<feature>.md and stops for your review. Once you approve the plan, it generates the tests, runs them, and heals UI locator failures.

Agents

Agent Job
page-mapper Walks one live page with playwright-cli, in its own browser session, and documents its controls, input behaviour, URL params, validation, success, empty and error states, and multi-page flows in docs/pages/<page>.md. It records what the page does today, and flags what looks like a bug
api-test-planner / ui-test-planner Turn the description into numbered acceptance criteria, then hand-runnable scenarios that cover them. They check existing tests and clients first, so nothing is duplicated or invented. The API planner lists the schemas needed and leaves undocumented negative cases as open questions; the UI planner writes expected results from the requirement, not the page, lists the differences as expected findings, and checks every element can be located
api-test-generator Writes the spec and any planned client methods (typed and documented), generates and tightens JSON schemas with UPDATE_SCHEMAS=true, lints and runs
ui-test-generator Checks the plan was approved, then writes locators → page object → spec, using the locators the live page actually exposes, in its own browser session. Deletes anything it creates while exploring
ui-test-healer Fixes drift, ambiguity and timing failures, one test at a time, in its own browser session, with at most 3 attempts per test. Marks plan-vs-page mismatches test.fixme() instead of changing the assertion

Skills

Skill Use
/playwright-qa-agents:author-tests <feature> The full flow above
/playwright-qa-agents:run-spec <path | project | id> Run a spec, a project (smoke, api, ui) or one test by id (12 or #0012), and summarize
/playwright-qa-agents:check [fix] Run the repo's lint, optionally auto-fixing
/playwright-qa-agents:bug-report <description> Write a bug report to bugs/, using the test and plan if a test id is given
/playwright-qa-agents:update-docs [path] Bring the docs up to date: a detailed README that matches the code, CLAUDE.md split into a root file and folder guides, JSDoc on everything, and only comments that explain why. Proves no behaviour changed
/playwright-qa-agents:playwright-cli Playwright's own skill for driving a browser with playwright-cli, used by the page-mapper, UI generator and healer (see below)

Guardrails

These rules exist because AI test authoring fails in predictable ways:

What review caught

These cases come from building playwright-e2e-demo (54 tests plus setup and teardown). Each one is a place where the human checkpoint or a guardrail changed what shipped. docs/worked-example.md follows one feature through every stage.

What the agents produced Caught by What changed
#0042 expected the "Order Placed!" text the page-mapper saw, not the documented "Your order has been placed successfully!". The test would have passed and hidden the mismatch Plan review It asserts the documented text and fails on purpose. The UI planner now writes expected results from the requirement and lists differences as "Expected findings"
#0007 (search) accepted empty results, and #0017 (update account) never read the update back. Both could pass with nothing working Plan review #0007 requires products for each documented term, and #0017 reads the account back
#0029 assumed search matches product names only; the docs say "related". The plan's own example was wrong too Plan review A match counts in name, category or brand, checked against the API
11 UI scenarios were tagged @smoke as well as @ui. Projects select by tag, so a run of every project would run them twice, and #0042 would place two orders Plan review CI runs --project=api --project=ui, so each test runs once. The UI planner now checks @smoke against the config's project tags
The page map recommended an id plus class name, and .first(). The grid's "Add to cart" couldn't be located under the rules at all Locator guardrail, then plan review The repo allows stable data-* attributes and exactly two ids. Four locators still outside the rules keep a // Fixme: saying what the site needs
The API generator wrapped the accounts tests in test.describe.serial, so one failure would skip the rest Code review against the "never serial" rule Plain test.describe with per-worker data, verified across two runs. Both generators now say "parallel, not serial"
At default parallelism the shared site answered "503 heavy load": 19 failures, against 10 at two workers Run review workers: 2 in the config. Generators and the healer never raise workers, and suspect overload before blaming a locator
#0037 failed intermittently: the remove click landed before the site's script bound its handler Healing budget and "never change the assertion" Fixed in 1 of 3 attempts by waiting for page load and the remove response, assertion untouched. The wait now lives in commons as clickAndWaitForResponse
The API planner found negative cases the docs don't cover (such as a duplicate email on create) "Don't invent expected results" (planner rule) Listed as open questions instead of guessed status codes. The reviewer kept them out of scope
The UI generator left a throwaway account on the live site when a script errored and lost its email Nothing in time; found at run review The page-mapper, UI generator and healer now write down a record's identifying values before creating it. The suite's test emails now use the owner's domain, so leftovers are recognisable. The account was cleaned up afterwards with deleteAccount

Limitations

What the agents get wrong

From the playwright-e2e-demo build. The guardrails above reduce these, but don't remove them:

Convention or enforced

Every guardrail in the agent prompts is a convention: the model is asked to follow it, and nothing stops it if it doesn't. What enforcement exists lives in the test repo's tooling, not in this plugin. playwright-e2e-demo enforces these:

Guardrail How it holds in playwright-e2e-demo
Plan, review, then generate Convention. author-tests stops for review and the generators ask, but nothing blocks calling a generator directly
Assert the plan, not what you see Convention
3-attempt healing budget Convention: the healer counts its own attempts
Locator rules Partly enforced. Lint fails on XPath and on .first()/.nth()/.last(). Class names and ids are convention
No fixed waits, no networkidle Enforced: lint errors
Parallel, not serial Enforced (lint error in playwright-e2e-demo)
No skipped or conditional tests Enforced (lint error in playwright-e2e-demo)
Unique numeric test ids Enforced: check-test-ids runs in npm run lint
Types and JSDoc on reusable code Enforced: tsc and eslint-plugin-jsdoc in npm run lint
Don't raise the worker count Enforced by default with workers: 2 in playwright.config.ts, but an agent can still pass --workers
Named browser sessions, cleanup Convention
Shared helpers go to commons Convention
The test repo's CLAUDE.md wins Convention

A test repo without these lint rules gets only the conventions. This repo's own CI validates the plugin manifests and checks that their versions match. It doesn't test agent behaviour.

Cost

Token use from the playwright-e2e-demo build, read from its session logs: 9 pages mapped, 14 API and 38 UI tests planned and generated, 1 test healed. All agents ran on Sonnet. Most input is cache reads, which cost far less than fresh input.

Stage Work Fresh input Cache reads Output
page-mapper 7 runs, 9 pages (about 56k per run) 393k 3.33M 83k
api-test-planner 14 endpoints, 3 plans 94k 0.17M 13k
ui-test-planner 38 scenarios, 7 plans 160k 1.04M 35k
api-test-generator 14 tests, clients, 7 schemas 87k 0.45M 12k
ui-test-generator 38 tests, including review fixes 365k 7.24M 86k
ui-test-healer 1 test 22k 0.18M 4k
All agents 1.12M 12.4M 232k

The session that ran the agents and the reviews used more than all of them together: 654k fresh input, 31.0M cache reads and 166k output, on Opus. That session also rewrote the e2e README, set up CI and moved helpers into commons, so not all of it is pipeline cost. Expect orchestration to cost about as much as the agents.

Installed, the plugin adds about 900 tokens to every session (skill and agent descriptions). Each agent's prompt adds 1–2k tokens when it runs, and the bundled playwright-cli skill about 6k (from claude plugin details).

When not to use it

Bundled: Playwright's playwright-cli skill

skills/playwright-cli/ is Playwright's own skill for @playwright/cli: the full command reference, plus guides on element attributes, request mocking, storage state, tracing and more. It is copied unchanged from the npm package and keeps its Apache-2.0 LICENSE. Don't edit it here. To update it to the latest @playwright/cli:

tmp=$(mktemp -d)
npm pack @playwright/cli@latest --pack-destination "$tmp"
tar -xzf "$tmp"/playwright-cli-*.tgz -C "$tmp"
rm -rf skills/playwright-cli
cp -r "$tmp/package/skills/playwright-cli" skills/
cp "$tmp/package/LICENSE" skills/playwright-cli/

Layout

.claude-plugin/plugin.json        the plugin's name, version and description
.claude-plugin/marketplace.json   makes this repo a plugin marketplace (source: ./)
agents/                           page-mapper, planners, generators, healer
skills/author-tests/              the full authoring flow
skills/run-spec/  skills/check/  skills/bug-report/  skills/update-docs/
skills/playwright-cli/            Playwright's skill, vendored (see above)
docs/worked-example.md            one feature followed through every stage
CHANGELOG.md                      what changed in each version
.github/workflows/validate.yml    validates the plugin, and that both manifests have the same version

Development

claude plugin validate .

After editing, start a new Claude Code session (or run /reload-plugins where your client has it) to load the changes.

Releasing: bump version in both .claude-plugin/plugin.json and .claude-plugin/marketplace.json (CI fails if they differ), add an entry to CHANGELOG.md, push to main, then tag the commit v<version> and push the tag. Users get it with claude plugin update playwright-qa-agents@playwright-ai-qa-agents (or /plugin update where their client has it), then a new session.

Dependabot keeps the GitHub Actions in the workflow current.

Background

Adding Playwright Agents: Lessons from the Deep Trenches, on benweese.com: what came out of putting Playwright's planner, generator and healer agents to work, including token costs and weak generated checks.

License

MIT. The bundled skills/playwright-cli/ is Apache-2.0, from Microsoft's @playwright/cli.