Skip to main content
Back to Blog
Troubleshooting
2026-07-07

Playwright Healer Agent Guide for Repairing Failed Browser Tests

Use the Playwright Healer agent to replay a named failure, inspect current UI behavior, review a minimal patch, and reject repairs that hide regressions.

Playwright Healer agent tracing one failed browser scenario through diagnosis, a minimal reviewed patch, and focused rerun evidence

The Playwright Healer agent takes a failing test name, replays its failing steps, inspects the current UI for an equivalent element or flow, suggests a patch, and reruns the test until it passes or guardrails stop the loop. Use it on one reviewed failure at a time, preserve the original evidence, and inspect every change. A passing rerun can support a repair; it cannot prove the product is correct. A skipped output means Healer believes functionality is broken, not that the test has been fixed, and it must remain a visible failure decision for the team.

See the Playwright test-agents pillar for role boundaries. Generate definitions with the init-agents tutorial, retain intent through the Planner guide, and produce reviewable code with the Generator guide. Use the canonical flaky-test repair guide and Playwright Trace Viewer guide for broader diagnosis. Browse QA skills and the Playwright CLI skill for reusable workflows.

This guide is grounded in Playwright's current official Healer documentation, checked July 14, 2026. The page documents four actions: replay failing steps, inspect the current UI, suggest a patch such as a locator, wait, or data adjustment, and rerun until passing or stopped by guardrails. Its documented output is either a passing test or a skipped test when functionality appears broken. The diagnosis gates below are team safeguards, not a claim that Healer autonomously proves root cause or approves its own patch.

Start from a named, legitimate failure

Healer's documented input is a failing test name. That boundary is important. A precise title ties the repair to one approved scenario and prevents an open-ended rewrite of a suite. "Guest corrects an unsupported postal code" is actionable; "fix checkout" is not the documented input and gives no stable intent to protect.

Before invoking Healer, establish that the test belongs in the suite:

  1. Find the Markdown scenario or requirement the test protects.
  2. Confirm the test passed previously or was reviewed after generation.
  3. Preserve the original error, project, retry, and available artifacts.
  4. Verify the target application revision and test environment.
  5. Reproduce only when rerunning will not destroy rare failure evidence.
  6. Name the exact test and prohibit unrelated edits.

Do not send a newly generated, unreviewed batch straight into a healing loop. If Generator misunderstood the plan, making the code green can entrench the wrong behavior. Review intent and structure first.

Classify the failure before accepting a repair

The same failed assertion can result from different causes. Healer may inspect the current UI, but the reviewer still decides which class the evidence supports.

Failure classEvidence patternValid next moveDangerous "repair"
Locator driftIntended control still exists with changed stable semanticsUpdate the locator and preserve the same actionClick a different control that merely advances the page
Expected product changeApproved requirement and UI changed togetherUpdate plan and test in one reviewed changeAlter only the assertion without recording new intent
Product regressionRequired control, result, or transition is absentFile/fix product defect; keep signal visibleSkip, weaken, or redirect the test to another flow
Synchronization defectEvidence shows assertion runs before a meaningful readiness stateWait on that state through a web-facing conditionAdd arbitrary time or inflate all timeouts
Test-data defectAccount, cart, role, or record is invalid or sharedRepair fixture provisioning and isolationHard-code one mutable shared record
Environment failureService, flag, dependency, or network is unavailableRestore environment and rerun unchanged testRewrite expectations around an outage
Plan defectOriginal expected result was ambiguous or wrongReturn to Planner/product reviewLet Healer invent the business rule
Flake without causeFailure disappears and no divergence is foundKeep investigating or quarantine by policyCall the rerun a confirmed fix

"It passed after the patch" is validation evidence, not root-cause proof. A locator update can pass while targeting the wrong button. A longer wait can pass while hiding a backend slowdown. A data change can pass while removing the boundary the scenario was supposed to test.

Preserve the original failure specimen

Before replay, copy or retain what the failing attempt already produced: error text, stack location, browser project, retry number, screenshot, trace, video, console or network evidence, and application revision where available. Normal Playwright debugging artifacts are separate from Healer's narrow input contract, but they help a human compare the suggested explanation with the original failure.

Do not assume Healer automatically consumed a trace merely because the repository recorded one. The current test-agent page says it replays steps and inspects the current UI; it does not specify trace ingestion as a required Healer input. Use trace analysis as an explicit reviewer or debugging workflow and label evidence from a later replay separately.

A rerun can change timing, data, or server state. If the first attempt failed during a one-time race and replay passes immediately, report that the cause is unconfirmed. Do not edit code simply to produce a diff.

Record a compact failure envelope before invocation:

Test: guest corrects an unsupported postal code
File: tests/checkout/unsupported-postal-code.spec.ts
Project: chromium
Observed: after correcting 00000 to 10001, address step remained visible
Expected: delivery options heading becomes visible
First failing action: second Continue to delivery click
Artifacts: original trace and screenshot retained by CI
Protected intent: rejected code must recover without losing valid address fields
Allowed edits: this test or its checkout fixture only
Forbidden: skip, fixed sleep, broad timeout increase, unrelated suite changes

This envelope is a team artifact, not a Playwright file format. It keeps the investigation anchored to observable behavior and makes an unrelated patch easy to reject.

Inspect the failing test for false intent

Consider this reviewed test:

// spec: specs/guest-checkout.md
// seed: tests/seed.spec.ts
import { test, expect } from '../../fixtures';

test('guest corrects an unsupported postal code', async ({ page, guestCheckout }) => {
  await guestCheckout.openSeededCart();

  const postalCode = page.getByRole('textbox', { name: 'Postal code' });
  await postalCode.fill('00000');
  await page.getByRole('button', { name: 'Continue to delivery' }).click();
  await expect(page.getByText('We do not deliver to this postal code')).toBeVisible();

  await postalCode.fill('10001');
  await page.getByRole('button', { name: 'Continue to delivery' }).click();
  await expect(page.getByRole('heading', { name: 'Delivery options' })).toBeVisible();
});

Before Healer changes it, compare the plan and current product. The first assertion proves rejection. The final heading proves recovery reached a distinct step. If the product now labels that step "Shipping method" and the requirement approved the rename, a semantic locator update may preserve intent. If the delivery step never appears because the API returns an error, changing the test to assert the address heading would invert the requirement.

Check whether both button locators identify the same intended control at each state. Repeated accessible names are not inherently wrong, but a layout may contain multiple "Continue" buttons. A suggested scope change should point to the same address form, not whichever button happens to navigate.

Give Healer a bounded request

Invoke the generated Healer role through the selected coding-agent host. The prompt below is natural language, not a Playwright CLI command:

Use the Playwright Healer agent on the failing test named
"guest corrects an unsupported postal code" in
tests/checkout/unsupported-postal-code.spec.ts.

Preserve the scenario in specs/guest-checkout.md: a rejected code must show the
field error, and a valid correction must reach delivery options without losing
the other address values. Replay the failing steps in QA Sandbox, inspect the
current UI, and identify the earliest divergence. Suggest the smallest supported
patch and rerun only this test. Do not skip it, add fixed sleeps, weaken the final
outcome, change production code, or edit unrelated tests. If the required product
behavior appears broken, stop and report that evidence instead of masking it.

The official docs allow a skipped output when Healer believes functionality is broken. This prompt asks it to stop and report instead because the team's review policy does not permit an unapproved skip. That is a governance choice, not a different Healer feature.

The prompt restates protected intent so "equivalent flow" cannot be interpreted as any route to a green assertion. It also confines file scope. If the evidence points to a shared fixture, Healer can suggest that fact; a reviewer can then expand the allowed change deliberately.

Require an evidence chain with the patch

A useful repair explanation has six parts:

  1. The earliest step where expected and actual behavior diverged.
  2. The relevant UI state before that step.
  3. The observed result after the action.
  4. The classified cause and supporting evidence.
  5. The smallest patch that preserves the scenario.
  6. The focused rerun result and remaining uncertainty.

Reject "updated selector and test passes" as incomplete. Ask what the old selector matched, what the new one means, and why the product change is approved. For wait changes, ask which readiness event was absent and how the new condition proves it. For data changes, ask whether the scenario's boundary still exists.

An acceptable locator-only repair after an approved accessible-name change might be:

// Requirement-approved copy changed from "Delivery options" to "Shipping method".
await expect(page.getByRole('heading', { name: 'Shipping method' })).toBeVisible();

This one line is not acceptable merely because it resolves. Evidence must show that "Shipping method" is the renamed delivery step and the plan or requirement was updated. If both headings coexist and one is an unrelated sidebar, the patch is wrong.

A synchronization repair should wait on product meaning, not elapsed time. For example, if the delivery transition legitimately exposes a loading status and then the heading:

await page.getByRole('button', { name: 'Continue to delivery' }).click();
await expect(page.getByRole('status', { name: 'Saving address' })).toBeHidden();
await expect(page.getByRole('heading', { name: 'Delivery options' })).toBeVisible();

Use this pattern only if that status is real and part of the observed application. Do not invent an accessible name to make a generic example fit. Often the final web-first heading assertion already waits sufficiently; adding another wait without evidence only increases code.

Treat "equivalent element or flow" narrowly

The Healer docs say it inspects the current UI to locate equivalent elements or flows. Equivalent should mean the same user intent and outcome, not a shortcut that makes the test proceed.

For a checkout continuation, these are not automatically equivalent:

  • A primary "Continue to delivery" button and a breadcrumb link that jumps ahead.
  • A guest checkout control and an authenticated express-checkout control.
  • A visible address form and a hidden mobile duplicate.
  • A successful server transition and a client-side URL edit.
  • A confirmation page for the seeded item and one left from a previous order.

Review identity, context, preconditions, side effects, and outcome. A replacement locator must operate on the intended record and actor. A replacement flow must still exercise the risk named in the plan. If the UI redesign intentionally removed a step, update the plan before accepting a different flow.

This is where unsupported autonomy claims become dangerous. Healer can inspect and suggest; the team owns equivalence. No model observation replaces an approved product decision.

Evaluate locator patches

Approve a locator patch only when all of these are true:

  • The original control still exists or has an approved replacement.
  • The new locator expresses stable user-facing identity or an approved test contract.
  • It is unique in the intended region and state.
  • It does not bypass a required intermediate action.
  • The assertions after the action still prove the same outcome.
  • The change works from clean setup, not only the replay session.

Reject patches that switch to locator('button').nth(2) without a stable rationale, use a broad text substring, force an action through an overlay, or target a hidden duplicate. These may turn red into green without repairing the test's meaning.

If the accessible name changed because accessibility regressed, restoring the product semantics may be the right fix. A test locator failure can be valuable product evidence. Do not automatically adapt the test to a less accessible implementation.

Evaluate wait and timeout patches

The docs list a wait adjustment as one example of a suggested patch. A wait change is justified when evidence shows the test observes too early relative to a legitimate application state. It is not justified simply because a larger timeout eventually passes.

Ask three questions:

  1. Which observable readiness condition was missing from the test?
  2. Is the condition tied to user-visible or domain state rather than wall-clock delay?
  3. Does the change preserve a useful performance or timeout signal?

An arbitrary waitForTimeout usually answers none of them. Increasing a global timeout can also slow every failure and hide a regression. Prefer the existing web-first assertion when it already waits for the required condition. If the app has no observable readiness state, consider whether the product needs one or whether a fixture/API contract can establish it.

Run the repaired test repeatedly only as supporting stability evidence, not proof of absence of flakiness. A small sample cannot guarantee reliability under all CI conditions.

Evaluate data and fixture patches

A data repair can be legitimate when the fixture created an expired account, duplicate identifier, wrong role, unavailable item, or shared state. Preserve the scenario's intended boundary while fixing provisioning.

For example, replacing hard-coded order 123 with a fixture-created unique order can improve isolation. Replacing an out-of-stock scenario with an in-stock item merely to pass changes intent. The patch explanation must name the old invalid assumption and show why the new data still exercises the approved behavior.

Inspect cleanup and parallelism. Healer may get one focused test to pass with a shared account that will still collide in a full worker pool. Run neighboring tests and relevant projects after focused validation. Data fixes belong in the narrowest shared fixture that actually owns the state; avoid copying setup into one test when every scenario needs the corrected contract.

Handle product regressions and skipped output

The official page explicitly permits a skipped test when Healer believes functionality is broken. A skip is not a passing repair. It suppresses execution and changes the suite's signal. Treat it as an escalation artifact requiring an owner, defect reference, rationale, expiry or revisit condition, and explicit approval under team policy.

If current UI inspection shows a required button is gone, an API error prevents transition, or persisted data is wrong, preserve the failed assertion and report the product evidence. Fixing the application may make the unchanged test pass. That is a successful testing outcome even though Healer did not edit the test.

Do not allow a loop to alternate among locators until any path turns green. The documented guardrail stop exists because repair is bounded. Your host and repository should add practical limits on files, retries, time, environment, and forbidden actions. The official page does not publish one universal guardrail configuration, so do not invent a Playwright option for it.

When a skip is unavoidable under an established quarantine policy, make it visible in code review and reporting. Never count skipped as healed in reliability metrics.

Validate the smallest patch

After reviewing the diff, run the named test through the normal runner from a clean state:

npx playwright test tests/checkout/unsupported-postal-code.spec.ts --grep "guest corrects an unsupported postal code"
npx playwright test tests/checkout/unsupported-postal-code.spec.ts

The first command isolates the named behavior; the second catches interactions with other scenarios in the file. Then run relevant projects and neighboring coverage through repository scripts. A passing Chromium rerun does not establish WebKit, Firefox, mobile, locale, or parallel behavior unless those configurations are actually exercised.

Compare the new run with original evidence. Confirm the repaired action reaches the same state, assertions remain discriminating, no skip appeared, and no unrelated file changed. If the root cause was data or a fixture, add a regression check at the appropriate layer when useful.

Do not merge a patch solely because Healer stopped. Guardrails can stop on unresolved failure, and the documented output can be skipped. Read the final state and test report.

Failure paths inside the healing loop

Loop symptomInterpretationResponse
Replay passes without editsFailure may be intermittent or environment-specificPreserve uncertainty and compare original attempt
Suggested locator points elsewhere"Equivalent" was judged too broadlyReject and restate protected intent and region
Timeout keeps increasingRoot cause remains unprovenRestore useful limit and find an observable condition
Test data changes remove the boundaryPatch changes the scenarioReject and repair fixture without changing risk
Healer edits several unrelated filesInput or permissions are too broadStop, revert only its proposed scope through review, and retry narrowly
Product behavior is visibly absentLikely regression or intentional changeObtain product decision; do not force a green test
Test becomes skippedFunctionality was judged broken or signal was suppressedEscalate; a skip is not a passing repair
Focused test passes but suite failsShared fixture, project, or parallel interaction remainsRun relevant scope and repair ownership boundary

The right outcome can be "no test patch." A clear diagnosis that identifies a product regression is more valuable than a misleading green suite.

Version and capability limits

Healer was introduced with Planner and Generator in Playwright 1.56. This article reflects the stable 1.61-era documentation available on July 14, 2026. Regenerate definitions whenever Playwright is updated so the role receives current tools and instructions.

The documentation does not claim perfect repair, root-cause certainty, unlimited looping, automatic merge, production authorization, or immunity from false-green patches. It names patch examples, reruns, guardrails, and two possible outputs. Host implementation and permissions can differ across VS Code, Claude Code, Codex, and OpenCode.

The current agent page documents the Node.js Playwright Test workflow. Do not assume the same initializer and Healer behavior exist for every language binding. Do not infer that a release-note debugging feature is automatically used by Healer unless the current definition or documentation says so.

Frequently Asked Questions

What input does the Playwright Healer agent need?

The official docs list a failing test name. Give a precise title that maps to a reviewed scenario, plus boundaries and preserved intent in the host request.

What does Healer do after a test fails?

It replays the failing steps, inspects current UI for equivalent elements or flows, suggests a patch, and reruns until the test passes or guardrails stop the loop.

Can Healer skip a broken test?

The documented output can be a skipped test if Healer believes functionality is broken. Treat that as unresolved and subject to explicit team review, not as a successful repair.

Does a passing rerun prove the patch is correct?

No. It proves one run passed in that context. Review the preserved intent, root-cause evidence, locator identity, assertion strength, clean setup, projects, and neighboring tests.

Should Healer add a fixed sleep for timing failures?

Only evidence can justify a timing change, and a fixed sleep rarely represents readiness. Prefer an observable application condition or existing web-first assertion. Reject timeout inflation without a causal explanation.

Can Healer fix product code?

The official test-agent page describes patches such as locator, wait, or data fixes in the failing-test workflow; it does not grant unrestricted product-code authority. Set file boundaries and route confirmed product defects through normal ownership.

What if the test passes during replay?

Keep the original failure and report that the cause is unconfirmed. Compare project, data, timing, environment, and artifacts. A clean replay does not erase a flaky or environment-specific failure.

When is a locator update safe?

When evidence shows the intended control has an approved new identity, the locator is stable and unique in context, and all downstream assertions still prove the same scenario.

Is Healer the same as unattended self-healing automation?

No. Playwright documents a bounded agent workflow with a named failure, suggested patch, reruns, guardrails, and a possible skipped output. Human review and merge policy remain outside that claim.

Repair signal, not just syntax

Return to the Planner guide if expected behavior is wrong, the Generator guide if implementation structure is weak, and the init-agents guide when definitions are stale. The agent pillar explains the complete handoff and approval model.

The authoritative role contract is the official Playwright Healer section, supported by the test-agent artifact conventions and 1.56 release record. For wider failure analysis, continue with the flaky-test guide and Trace Viewer guide. Browse QA skills and the Playwright CLI skill without treating those resources as additional Healer autonomy.