Playwright AI Agents, end to end.
An AI testing agent is a language model with a goal, a browser it can drive through Playwright, a memory, and a loop: perceive → reason → act → verify. In this session you build agents that explore a real app, generate tests, self-heal flaky locators, and triage failures - and you practise every idea against the live TTACart demo store. (MCP is a separate session; here we focus on the agent itself.)
The 30-minute pitch
Four things you walk away able to do today.
Understand the agent loop
See how an agent perceives the page, reasons about the next step, acts through Playwright, and verifies the result - over and over until the goal is met.
Generate tests with AI
Feed a user story or let the agent explore TTACart, then have it emit a reviewable @playwright/test spec you commit.
Self-heal flaky locators
When a selector breaks, the agent inspects the new DOM and proposes a resilient role or test-id locator - you approve the diff.
Auto-triage failures
Point the agent at a failed run or trace; it classifies flaky vs real, suggests severity, and drafts a root-cause hypothesis.
App under test
We practise on TTACart
Agents need a stable target to explore and re-test. TTACart is a small e-commerce app with a login, an inventory grid, item details, a cart, and a multi-step checkout - enough surface to exercise an agent end to end, and predictable enough that you can tell a real regression from a hallucination.
TTACart store
Open it, then let an agent log in, shop, and check out while you watch each step of the loop.
Login → cart → checkout
The canonical journey an agent will learn. Use the credentials shown on the TTACart login screen - never hard-code secrets into agent prompts or specs.
Stable, deterministic
Roles and test ids are consistent, so the agent can reason about the page reliably and you can reproduce its runs.
Concept
What is an AI testing agent?
An agent is not a bigger script. A script runs fixed steps you wrote. An agent is given a goal, a set of tools (a browser driven by Playwright), a memory of what it has seen, and the freedom to choose its next action in a loop until the goal is met or a limit is hit. The LLM is the reasoning engine; Playwright is its hands and eyes.
Deterministic, brittle
You spell out every locator and step. Fast and repeatable, but it cannot adapt - a renamed button stops the run cold, and a new flow needs new code from you.
Goal-driven, adaptive
You state the goal ("buy one item and verify the total"). The agent inspects the live page, decides the next click, recovers from small changes, and reports what it did - within the guardrails you set.
| Building block | For a QA agent on TTACart |
|---|---|
| Goal / spec | "Log in, add one item to the cart, complete checkout, and assert the order total." |
| Tools | A Playwright-driven browser: navigate, click, fill, read the DOM and accessibility tree, screenshot, assert. |
| Memory / context | What it has already clicked, the current URL, prior failures, and the page snapshot it is looking at now. |
| Reasoning (LLM) | Chooses the next action from the goal + current perception, and decides when the goal is satisfied. |
| Human-in-the-loop | You review generated specs, approve healed locators, and gate anything that writes or merges. |
Architecture
Anatomy of a QA agent
Every capability on this page is the same four-beat loop wrapped around the building blocks above. Read it clockwise: the agent looks, thinks, acts, and checks - then loops.
Read the page
Capture the DOM and accessibility snapshot (or a trace). This is the agent's eyes - a compact, structured view of what is on screen right now.
Decide the next step
The LLM weighs the goal against what it sees and picks one action: which control to use and what value to enter.
Drive Playwright
Translate the decision into a Playwright call - getByRole, click, fill, goto - and execute it against TTACart.
Check the result
Assert the expected change happened (URL, text, count). Pass advances the loop; fail feeds back into reasoning or a retry.
Carry context
Remember prior steps, the goal, and failures so the agent does not loop forever or repeat a dead end.
Stay bounded
A step budget, allowed actions, and human gates keep the agent safe, cheap, and reviewable.
goal = "log in, add one item, check out, assert the total" on https://app.thetestingacademy.com/playwright/ttacart/
while not done and steps < budget:
snapshot = perceive(page) # DOM + a11y tree (the agent's eyes)
action = reason(goal, snapshot) # LLM picks ONE next step
result = act(page, action) # Playwright: click / fill / goto
done = verify(goal, result) # assertion decides pass / continue
remember(action, result) # update memory, avoid dead ends
report(done, steps, evidence) # screenshots, trace, generated specCapability 1
AI test generation
Give the agent a user story, or let it explore TTACart on its own, and it emits a @playwright/test spec. Under the hood it leans on the same engine as codegen - it prefers role, text, and test-id locators - but it also adds the assertions your story implies. The rule is review-before-commit: the spec is a draft you read, run, and tidy.
You are a Playwright test author. App under test: https://app.thetestingacademy.com/playwright/ttacart/ User story: As a shopper, I log in with the credentials shown on the login screen, add one item to the cart, complete checkout, and see an order-confirmation message. Write a @playwright/test spec in TypeScript. Use getByRole and getByTestId locators, add web-first assertions (expect(...)), and do NOT hard-code any password - read it from an env var.
import { test, expect } from '@playwright/test';
test('shopper can check out one item', async ({ page }) => {
await page.goto('https://app.thetestingacademy.com/playwright/ttacart/');
// credentials come from the login screen; never commit secrets
await page.getByLabel('Username').fill(process.env.TTA_USER!);
await page.getByLabel('Password').fill(process.env.TTA_PASS!);
await page.getByRole('button', { name: /login/i }).click();
await expect(page).toHaveURL(/inventory/);
await page.getByRole('button', { name: /add to cart/i }).first().click();
await page.getByRole('link', { name: /cart/i }).click();
await page.getByRole('button', { name: /checkout/i }).click();
// ...fill the multi-step checkout form...
await page.getByRole('button', { name: /finish/i }).click();
await expect(page.getByText(/thank you|order/i)).toBeVisible();
});Capability 2
Self-healing locators
A test breaks because a developer renamed a class. Instead of a red pipeline and a manual fix, the agent perceives the new DOM, finds the element that still matches the intent ("the add-to-cart button"), and proposes a more resilient locator - usually a role or test id, which survives restyling far better than a CSS path.
Brittle CSS
Tied to structure and styling that changes often.
page.locator( '.inventory_item:nth-child(1) ' + '> button.btn_primary' )
Healed, resilient
Tied to intent - the role and accessible name.
page.getByRole('button', {
name: /add to cart/i
}).first()This locator no longer matches on https://app.thetestingacademy.com/playwright/ttacart/:
page.locator('.inventory_item:nth-child(1) > button.btn_primary')
Here is the current accessibility snapshot of the page:
<a11y snapshot pasted here>
Propose the most resilient Playwright locator that selects the
first "add to cart" control. Prefer getByRole or getByTestId.
Return ONLY the new locator and a one-line reason.Capability 3
Auto bug triage & RCA
When a run goes red, the agent reads the failure - the error, the failing step, and the Playwright trace (DOM snapshot, network, console) - and does the first pass a human would: is this flaky or a real regression? It suggests a severity, drafts a root-cause hypothesis, and writes a bug report you can paste into your tracker. No real Jira credentials live in the agent.
Flaky vs real
Timeout that passes on retry and shows a slow network call - likely flaky. Assertion that fails every run - likely a real regression.
Rank the impact
Checkout total wrong - high. A misaligned label - low. The agent proposes; you confirm.
Hypothesis + report
A likely cause from the trace plus a ready-to-edit bug write-up with steps and evidence.
A Playwright test failed on https://app.thetestingacademy.com/playwright/ttacart/. Inputs:
- error: expect(getByText(/total/)).toHaveText('$32.97') ... got '$29.99'
- trace: test-results/checkout/trace.zip (summary attached)
- history: failed on all 3 of the last 3 runs
Triage it. Decide flaky vs real with a one-line reason, suggest a
severity (S1-S4), give a root-cause hypothesis, and draft a bug
report: title, steps, expected, actual. Do NOT call any tracker API.Doing it well
Agent patterns & guardrails
An agent without limits is slow, expensive, and unpredictable. These guardrails turn a clever demo into something you can run in a team.
Bounded steps
Cap the loop (for example 15 steps). If the goal is not met, stop and report - never spin forever.
Human-in-the-loop gates
The agent may read and propose freely, but writing a file, healing a locator, or filing a bug needs your approval.
Deterministic verification
Let the LLM decide actions, but verify with plain Playwright assertions - not "the model thinks it passed".
Cost & limits
Small snapshots, few tokens per step, a step budget, and caching keep runs fast and cheap.
Reference
Agent capability cheat sheet
| Capability | Example prompt (abridged) | Playwright pieces it uses |
|---|---|---|
| Explore an app | "Map the main flows of TTACart and list the pages." | Accessibility snapshot, getByRole, navigation. |
| Generate a test | "Turn this story into a @playwright/test spec." | codegen-style locators, web-first expect. |
| Self-heal a locator | "This selector broke - propose a resilient one." | DOM/a11y snapshot, getByRole / getByTestId. |
| Triage a failure | "Flaky or real? Severity + RCA + bug draft." | Trace viewer data: snapshots, network, console. |
| Verify a fix | "Re-run the failing test and confirm it is green." | --last-failed, assertions, HTML report. |
| Summarise a run | "Summarise today's report for the standup." | JSON / HTML report, trace links. |
Hands-on
Six agent drills on TTACart
Agent logs in
Give an agent the goal "log in" against TTACart with the on-screen credentials. Watch it perceive, act, and verify the inventory page.
Checkout, then emit a spec
Have the agent complete a full checkout, then ask it to write the journey as a reviewable @playwright/test spec.
Break & self-heal
Change a working locator to a brittle CSS path, let it fail, and ask the agent to propose a resilient role or test-id locator.
Triage a failing trace
Capture a trace from a deliberately failing assertion and ask the agent for flaky-vs-real, a severity, and a root-cause hypothesis.
Generate edge cases
Ask the agent for edge-case cart tests: empty cart, remove the last item, quantity changes, and the order total after each.
Review & commit one spec
Run a generated spec headed, tighten its assertions, strip any secret, and commit exactly one - the human-in-the-loop gate.
Sources
Official references
| Reference | URL |
|---|---|
| Playwright codegen (test generators) | https://playwright.dev/docs/codegen |
| Trace viewer | https://playwright.dev/docs/trace-viewer |
| Playwright docs (home) | https://playwright.dev/docs |
| TTACart demo app | https://app.thetestingacademy.com/playwright/ttacart/ |