petrkindlmann/qa-skills

agentic-browser-testing

Goal-driven E2E testing where a browser agent (Playwright MCP / computer-use) reads a natural-language goal and explores the app via the accessibility tree to assert outcomes — no pre-written script.

View source

How to use

  1. Copy the installation command and review the source package before installing it in your own agent environment.
  2. Check the source document for required tools, credentials and supported hosts.
  3. Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/petrkindlmann/qa-skills --skill agentic-browser-testing

Before you start

  • Installation does not include a model subscription, API allowance or permission to access your files.
  • Repository stars and installation counts describe activity, not an independent quality or security test.
Original skill document

Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.

<objective> A scripted Playwright test breaks the moment a button moves or a class renames; writing one for a dashboard that changes weekly is a maintenance treadmill. This skill stands up a goal-driven browser agent instead: it reads a natural-language goal, explores the app via the accessibility tree (Playwright MCP browser_snapshot), and asserts the outcome against an explicit oracle. The failure mode it prevents is the one that makes teams distrust agents — an agent that reports "success" while stuck on the login page because nothing forced it to prove where it landed. You leave with a deterministic, CI-gated agent run and a graduation path to a durable scripted test once the flow stabilizes. </objective>

Quick Route

SituationGo to
Stand up a goal-driven run from scratchDiscovery + references/setup.md
Decide agentic vs scripted for a given flowFit: Intent-Driven vs Scripted
Agent passes one run, fails the nextDeterminism
"How does it click without screenshots?"Interaction Model
Runs are slow / burning tokensCost and Latency
Agent reports false successSuccess Assertion (the Oracle)
Flow is stable — make it permanentGraduation → references/graduation-and-ci.md
Block a merge on the goalCI Gating → references/graduation-and-ci.md
Canvas / no accessibility treeCanvas Fallback → references/graduation-and-ci.md

Discovery Questions

First, check .agents/qa-project-context.md in the project root and skip anything it already answers (stack, environments, seed/reset tooling, model access).

  1. Which flow, and how often does its UI change? Fast-changing/experimental UI favors

intent-driven; a stable critical path (login) favors scripted. This decides the whole approach.

  1. Is there a seeded fixture and a way to reset state? Determinism is impossible without

seeded data and a per-run reset. If neither exists, that is step zero.

  1. Can you deep-link past auth to a seeded entry point? Re-driving login every run is the

biggest avoidable cost; a seeded entry URL scopes the goal and cuts steps.

  1. What is the unambiguous success oracle? Specific account text, a /dashboard URL, an

order number — plus a forbidden state. "No error" is not an oracle.

  1. Does the target render to canvas / WebGL? No accessibility tree means snapshot-first

won't work; plan the vision fallback or instrument the canvas with ARIA.

  1. Which model and budget? Pin a model id and a step budget up front; tier cheap steps to

Haiku 4.5 / Sonnet 4.6 and reserve Opus 4.8 for genuinely ambiguous flows.


Core Principles

  1. Intent, not instructions — but only where churn earns it. The agent reads a goal and

finds its own path through the accessibility tree, so it survives a moved button or renamed class that would break a selector. That resilience costs 2-5x the time and money of a scripted run, so spend it on fast-changing UI and hard-to-locate flows, not on stable critical paths.

  1. An agent run is untrustworthy until it is deterministic. Same goal, same seeded app

must produce the same verdict. That requires temperature 0, a pinned model id, seeded data with a reset, a bounded step budget, and an explicit pass/fail assertion. Without these you have a coin flip, not a test.

  1. The oracle lives outside the agent. Never let the LLM self-grade "looks good." Success

is a checkable assertion against the final browser_snapshot — specific expected text, a URL, AND a forbidden-state negative check — evaluated by your harness, not the model.

  1. Accessibility tree first, pixels last. browser_snapshot returns roles, refs, and

accessible names (~200-400 tokens) and is deterministic and cheap. Screenshots, pixel coordinates, vision, and OCR are a scoped last resort for canvas only, never the default.

  1. Graduation is the goal, not perpetual agent runs. Once a flow is stable, promote the

run to a durable scripted tests/*.spec.ts with role-based locators. An agent that has been green for two weeks should become a fast, free regression test — keep the agent for exploration, not for guarding a settled path.


Fit: Intent-Driven vs Scripted

The decision is per-flow, not per-project. Run risk-based-testing first if you need the risk map; this table is the routing rule once you have it.

Flow characteristicUseWhy
Stable, high-frequency critical path (login, payment)Scripted + pinned (playwright-automation)Runs every PR; must be fast, free, and deterministic. No upside to re-exploring it.
Fast-changing / experimental UI (a dashboard that churns weekly, a redesign in flight)Agentic / intent-drivenSelectors would break constantly; a goal survives layout churn.
Hard-to-locate flow you can't reliably selectAgenticThe agent finds the control by role/name instead of you reverse-engineering a selector.
Exploratory smoke / "does the happy path still work at all"AgenticOne NL goal covers a lot of ground without a maintained script.
Anything in CI that must never falsely passScripted, OR agentic with a hard oracleNon-determinism is a false-pass risk you must actively cap.

The rule, stated plainly: keep stable critical paths scripted and pinned; point intent-driven agents at fast-changing UI and exploratory smoke. Do not move everything to the agent — it is slower, costlier, and non-deterministic, and not every test should be agentic.


The Interaction Model (accessibility-tree-first)

Playwright MCP is not computer-use with screenshots and pixel coordinates. It is accessibility-tree-first:

  1. browser_navigate to the seeded entry URL.
  2. browser_snapshot returns the accessibility tree — each interactive element as a

role, a stable ref, and its accessible name (from ARIA/labels). ~200-400 tokens.

  1. The agent picks an element by ref and calls browser_click or browser_type.
  2. browser_wait_for waits on text appearing/disappearing — never a fixed sleep.
  3. Re-browser_snapshot after the DOM changes; assert against that tree.

Why not screenshots: the snapshot is token-efficient (thousands of tokens cheaper than an image), deterministic (text refs, not fuzzy pixel matching), and needs no vision model or OCR. Feeding screenshots as the primary input makes the run slower, pricier, and flakier. browser_take_screenshot is for human evidence only, never as the assertion input.

See references/setup.md for the MCP registration, the full tool table, and the goal prompt.


Determinism: making a run trustworthy in CI

A run that passes once and fails the next with no app change is not yet a test. The fix is never "just retry" or bumping temperature for "smarter" exploration — that adds variance. Pin the variables instead:

LeverSetting
ModelPinned model id (e.g. claude-haiku-4-5-20251001), never latest
Samplingtemperature 0 — no creative wandering in CI
DataSeeded fixture + reset/seed the database before every run
ScopeBounded step budget (maxSteps), e.g. 18 — exceeding it FAILS, never auto-retries
OracleExplicit pass/fail verdict asserted against the snapshot
EvidenceAssert on the accessibility tree, never a screenshot diff

Avoid: temperature: 0.7 or 1 for exploration, retry-until-pass loops, waitForTimeout sleeps, and screenshot-based assertions. Each one hides flakiness rather than removing it. Full harness config in references/setup.md.


Success Assertion: the Oracle (where agents fail silently)

This is the sharpest failure mode: the agent reports success while stuck on the login page, because "page loaded / no error / looks good" was accepted as success and the LLM was allowed to self-grade. Force an explicit oracle the harness checks — never the agent.

For the goal "sign in as an existing user and confirm the dashboard shows the right account name":

text
SUCCESS (all must hold — assert against the final browser_snapshot):
  - URL matches /dashboard
  - Snapshot contains the specific expected account name text, e.g. "Acme Corp — Jane R."
NEGATIVE / forbidden state (fail fast if any is true):
  - Still on a URL matching /login  → FAIL
  - Snapshot contains role="alert" with "invalid credentials"  → FAIL
VERDICT: harness emits {"passed": true|false}; the LLM does not decide.

The positive checks (specific account name + /dashboard URL) prove where it landed; the negative check (must NOT be on the login page) is what kills the false pass. "No error," "didn't crash," "screenshot looks correct," and "trust the agent" are not success criteria.


Cost and Latency

Agent runs are 2-5x slower and pricier than scripted tests — a step is an LLM round-trip, the dominant cost. Cut spend without losing coverage by going smaller, not bigger:

  • Step budget — keep maxSteps low and enforced; fewer round-trips, less drift.
  • Model tiering — Haiku 4.5 / Sonnet 4.6 for cheap navigation steps; reserve Opus 4.8 for

genuinely ambiguous exploration. Don't run the biggest model on every step.

  • Prompt caching — cache the static system prompt, tool schemas, and goal; they repeat

every run.

  • Scope via a seeded entry point — one narrow goal per run, deep-linked past login instead

of re-driving it each time.

  • Snapshot over screenshots — the a11y snapshot is ~200-400 tokens; a full-page screenshot

is thousands. Default to snapshot.

Backwards moves to reject: "use a bigger model / Opus 4.8 for every step," "raise the step limit," "screenshot every step," and running with no budget at all. See references/setup.md.


Graduation and CI Gating

Promote a stabilized goal into a durable scripted test, and gate merges on the verdict. Both are detailed in references/graduation-and-ci.md; the essentials:

  • Graduate with Playwright Test Agents (planner / generator / healer, shipped in

Playwright v1.56.0). npx playwright init-agents --loop=claude. The planner writes a Markdown test plan to specs/<flow>.md; the generator turns it into tests/<flow>.spec.ts with role-based locators (getByRole, getByLabel, getByText) verified against the live DOM; the healer repairs broken locators. This is the promotion path — not "keep running it as an agent," not recorded clicks, not page.locator('xpath=...'), not data-testid-only.

  • Gate CI so a failed goal exits non-zero and emits a machine-readable verdict

({"passed": true|false} in result.json); the GitHub Actions job parses the boolean and exit 1s on false. State is seeded/ephemeral and reset per run, with a step budget and a timeout cap. Never continue-on-error: true, never "always exit 0," never a prose verdict a human reads.

  • Canvas with no accessibility tree: prefer instrumenting the canvas with ARIA; as a scoped

last resort enable --caps=vision to unlock browser_mouse_click_xy for that flow only. browser_snapshot will not work on a raw canvas, but don't make coordinates the default and don't abandon agentic testing.


Migrating a brittle script to a goal (honest tradeoffs)

Converting an 80-line script that re-types login and walks 6 hardcoded steps into a single NL goal with an explicit success assertion is a real win for a churning flow — but state the downsides honestly:

  • Non-determinism / false-pass risk — the run could pass falsely; that's why the hard

oracle and the negative check are non-negotiable.

  • Cost/latency — 2-5x slower; bound it with a step budget and a seeded entry point.
  • Not every test should be agentic — keep stable paths scripted, and plan to graduate

this one back to a scripted test once it stabilizes.

Reject the over-promise: it is not "strictly better with no downsides," do not "migrate everything," and never drop the assertions to make it pass.


Anti-Patterns

1. Reflexively writing a scripted Playwright test

"Browser test" pattern-matches to codegen, so the default is page.goto / page.locator / await expect(page...) / hunting data-testid. That misses the entire point. A goal-driven agent reads NL intent and explores via browser_snapshot — no pre-written selectors.

2. "Use the agent for everything"

Over-selling the new toy. The agent is 2-5x slower and non-deterministic. Stable critical paths (login) stay scripted and pinned; intent-driven wins on fast-changing UI. Never "always use the agent" or "agents replace all scripted tests."

3. Fixing flakiness with retries or higher temperature

"Just retry" and bumping temperature for "smarter" exploration both add variance. The real levers are temperature 0, a pinned model, seeded data, a bounded step budget, and an explicit verdict.

4. Assuming computer-use = screenshots + pixel coordinates

Playwright MCP is accessibility-tree-first. Defaulting to vision, screenshots, OCR, or mouse_click_xy is slower, costlier, and flakier. Pixels are a canvas-only last resort.

5. "No error = success" (the false pass)

Accepting "page loaded / didn't crash / looks good" and letting the LLM self-grade is exactly why the agent reports success while stuck on login. Require specific expected text, a URL, and a forbidden-state negative check, evaluated by the harness.

6. Bigger model / more steps to go faster

Backwards. Opus 4.8 on every step and raising maxSteps raise cost and latency without buying reliability. Smaller models, tighter budgets, caching, and tighter scope are the fix.

7. Running an agent forever instead of graduating

A goal green for two weeks on a now-stable flow should become a scripted tests/*.spec.ts via Playwright Test Agents. "Keep running it as an agent," recording clicks, and xpath locators are all wrong promotions.

8. Prose verdict in CI

Returning a paragraph for a human to read, or continue-on-error: true, lets a failed goal merge. The run must exit non-zero on failure with a machine-readable boolean.


Done When

  • Goal prompt exists as natural-language intent (no page.locator / page.goto /

data-testid in the goal) with a START seeded entry URL.

  • An explicit success oracle is defined: specific expected text AND a URL check AND a

forbidden-state negative check, asserted against browser_snapshot — not a screenshot.

  • Run config pins a model id, sets temperature: 0, a maxSteps budget, and a seed; no

waitForTimeout, no retry-until-pass.

  • Interaction is snapshot-first: browser_navigate / browser_snapshot /

browser_click / browser_type / browser_wait_for; screenshots used only for evidence.

  • The runner emits result.json with {"passed": true|false} and exit 1s on false; the CI

job gates the merge on the boolean (no continue-on-error, no always exit 0).

  • CI seeds/resets ephemeral state per run and enforces a step budget and a timeout cap.
  • A graduation trigger is recorded (e.g. "green for 2 weeks → run init-agents, generate

tests/<flow>.spec.ts with getByRole locators").

  • If any target is canvas/WebGL, the vision fallback (--caps=vision +

browser_mouse_click_xy) is scoped to that flow only, or the canvas is instrumented with ARIA.


Related Skills

  • playwright-automation — Writing and maintaining deterministic scripted Playwright tests

and Page Objects. Go there to author the durable test; this skill graduates an agent run into one.

  • ai-system-testing — Testing your product's OWN LLM/AI features (prompt regression, model

output quality). This skill tests any app using an agent; it does not test your AI feature.

  • exploratory-testing — Human SBTM exploration and bug hunting. The agentic smoke goal is

the automated cousin; use exploratory-testing for charter-driven manual sessions.

  • test-reliability — Self-healing locators and quarantine for scripted flaky tests at

runtime. Complements the determinism levers here once a test has graduated.

  • qa-project-context — The universal dependency; supplies stack, environments, seed/reset

tooling, and model access that every question above depends on.

Reference Files (in references/)

  • setup.md — Playwright MCP registration (.mcp.json), the snapshot tool table, the

natural-language goal prompt with success/negative assertions, the determinism harness config (pinned model, temperature 0, maxSteps, seed, prompt cache), and cost/latency levers.

  • graduation-and-ci.md — Playwright Test Agents promotion pipeline (planner → specs/*.md,

generator → tests/*.spec.ts with role-based locators, healer), the GitHub Actions gating workflow with a machine-readable boolean verdict, and the canvas --caps=vision fallback.

Related by task

from this repository

More skills

All skills
petrkindlmann
Community

test-reliability

Runtime per-test healing with evidence: multi-attribute selector healing, environment-aware diagnosis, flake classification, quarantine management, and confidence-scored auto-repair. Goes beyond simple locator fallbacks to cover action-level healing, data healing, and observable repair workflows. Use when: "flaky test," "test stability," "self-healing locator," "broken locator recovery," "unreliable test," "quarantine flaky test." Not for: bulk regenerating selectors after a planned UI refactor

installs
1
GitHub stars
208
Updated
Oct 22
petrkindlmann
Community

ai-bug-triage

Hybrid fingerprint + LLM pipeline for bug classification, deduplication, and ticket generation. Normalizes CI logs, creates stable fingerprints, clusters near-duplicates, then uses LLM for severity classification and ticket writing. Includes bug reporting templates and severity/priority matrix. Use when: "bug triage," "classify bugs," "failure analysis," "auto-classify," "CI failures," "bug report," "defect template." Not for: runtime self-healing of one flaky locator — use test-reliability. Not

installs
2
GitHub stars
198
Updated
Oct 21
petrkindlmann
Community

playwright-automation

Write production-grade Playwright tests in TypeScript: Page Object Model, fixtures, auto-waiting, user-facing locators, parallel execution, CI integration, sharding, and 2025-2026 feature awareness. Includes an explicit "do not" list for AI agents. Use when: "Playwright," "write E2E test," "page object," "new Playwright suite," "Playwright config." Not for: fixing one flaky test at runtime — use test-reliability. Not for: bulk regenerating selectors after a UI refactor — use selector-drift-recov

installs
2
GitHub stars
198
Updated
Jun 10
petrkindlmann
Community

api-testing

Test REST and GraphQL APIs with Playwright APIRequestContext, Supertest, or standalone HTTP clients. Covers schema validation with Zod 4/AJV, auth flow testing, CRUD lifecycle tests, error and header validation, pagination, and performance assertions. Use when: "API test," "endpoint test," "REST test," "GraphQL test," "schema validation," "Postman replacement." Not for: consumer-driven contract verification (Pact, broker) — use contract-testing; browser UI flows — use playwright-automation. Rela

installs
3
GitHub stars
198
Updated
Jun 10