The Testing Academy · Masterclass

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.)

Host
Pramod Dutta
Track
Playwright + AI
Audience
QA / SDET
App under test
TTACart

The 30-minute pitch

Four things you walk away able to do today.

Loop

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

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.

Heal

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.

Triage

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.

Live

TTACart store

Open it, then let an agent log in, shop, and check out while you watch each step of the loop.

https://app.thetestingacademy.com/playwright/ttacart/

Flow

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.

Why

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.

Plain script

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.

AI agent

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 blockFor a QA agent on TTACart
Goal / spec"Log in, add one item to the cart, complete checkout, and assert the order total."
ToolsA Playwright-driven browser: navigate, click, fill, read the DOM and accessibility tree, screenshot, assert.
Memory / contextWhat 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-loopYou review generated specs, approve healed locators, and gate anything that writes or merges.
Where the human stays in control: the agent proposes, you dispose. Treat its output - specs, locator fixes, bug reports - as a pull request to review, never an auto-merge.

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.

1 · Perceive

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.

2 · Reason

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.

3 · Act

Drive Playwright

Translate the decision into a Playwright call - getByRole, click, fill, goto - and execute it against TTACart.

4 · Verify

Check the result

Assert the expected change happened (URL, text, count). Pass advances the loop; fail feeds back into reasoning or a retry.

Memory

Carry context

Remember prior steps, the goal, and failures so the agent does not loop forever or repeat a dead end.

Guardrails

Stay bounded

A step budget, allowed actions, and human gates keep the agent safe, cheap, and reviewable.

the loop · pseudo-flow
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 spec

Capability 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.

prompt · story to spec
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.
generated · tests/checkout.spec.ts (review before commit)
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();
});
Review-before-commit: run the generated spec headed once, confirm each assertion is meaningful (not just toBeVisible on everything), then commit. The agent drafts; you own the spec.

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.

Before

Brittle CSS

Tied to structure and styling that changes often.

page.locator(
  '.inventory_item:nth-child(1) ' +
  '> button.btn_primary'
)
After

Healed, resilient

Tied to intent - the role and accessible name.

page.getByRole('button', {
  name: /add to cart/i
}).first()
prompt · heal a broken locator
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.
Caution: review every heal - do not auto-merge blindly. A "healed" locator can silently bind to the wrong element. Approve the diff, re-run the test, and confirm it asserts what you meant.

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.

Classify

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.

Severity

Rank the impact

Checkout total wrong - high. A misaligned label - low. The agent proposes; you confirm.

RCA

Hypothesis + report

A likely cause from the trace plus a ready-to-edit bug write-up with steps and evidence.

prompt · triage a failed run
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.
Evidence first: a triage is only as good as the trace. Capture --trace on-first-retry in CI so the agent always has DOM, network, and console to reason from.

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.

Pattern

Bounded steps

Cap the loop (for example 15 steps). If the goal is not met, stop and report - never spin forever.

Pattern

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.

Pattern

Deterministic verification

Let the LLM decide actions, but verify with plain Playwright assertions - not "the model thinks it passed".

Pattern

Cost & limits

Small snapshots, few tokens per step, a step budget, and caching keep runs fast and cheap.

When NOT to use an agent: for a stable, critical path that rarely changes, a plain deterministic Playwright spec is cheaper, faster, and easier to trust. Reach for an agent when the value is exploration, adaptation, healing, or triage - not for re-running a known flow.

Reference

Agent capability cheat sheet

CapabilityExample 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.
Note: the agent's "hands" are ordinary Playwright APIs - codegen, locators, assertions, traces, reports. The intelligence is in choosing which to use; the execution is the Playwright you already know.

Hands-on

Six agent drills on TTACart

A

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.

B

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.

C

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.

D

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.

E

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.

F

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

ReferenceURL
Playwright codegen (test generators)https://playwright.dev/docs/codegen
Trace viewerhttps://playwright.dev/docs/trace-viewer
Playwright docs (home)https://playwright.dev/docs
TTACart demo apphttps://app.thetestingacademy.com/playwright/ttacart/
Class dismissed. You can now describe an AI testing agent as a perceive-reason-act-verify loop, generate tests from a story, self-heal a broken locator, and triage a failure - all on a real app, with you in control. Next session: giving the agent tools over MCP.