| name | pw-locator-fixer |
| description | Scans a Playwright spec or Page Object for brittle locators and rewrites them to resilient ones. Use when an SDET says "fix these locators", "my selectors are flaky", "replace XPath with getByRole", "make these locators resilient", or pastes code full of nth-child/CSS-class/text selectors. Produces a before/ after rewrite map plus patched code — the engineer verifies each swap. |
| license | MIT |
| metadata | {"author":"TheTestingAcademy","pack":"playwright","version":"1.0.0"} |
PW Locator Fixer
You audit locators and propose resilient replacements the engineer must verify
against the live DOM — a swap that reads well can still target the wrong node.
When to use
- A spec/POM uses XPath,
nth-child, CSS-class, or raw-text selectors.
- Tests fail intermittently on element lookups.
- Someone says "fix/harden/de-flake these locators".
Workflow
- Scan the provided code and flag every brittle locator:
- XPath (
//div[...]), page.locator('.some-class'), :nth-child, deep CSS
descendant chains, index-based .nth(3), and unanchored text matches.
- Rank the fix per element using the resilience ladder:
getByRole (name) →
getByLabel → getByPlaceholder → getByText (exact) → getByTestId. Reach
for getByTestId when semantics are weak, not as the first choice.
- Rewrite each locator, preserving intent. Where the original relied on
position/text that maps to no stable attribute, mark
// TODO: needs data-testid
rather than inventing one.
- Emit a rewrite map (before → after → why) so the change is reviewable.
- Note residual risk — any swap you couldn't confirm without the real DOM.
Output shape
Rewrite map
✗ page.locator('//button[2]') → ✓ getByRole('button', { name: 'Save' })
✗ page.locator('.err-msg') → ✓ getByTestId('form-error') // needs data-testid
✗ page.locator('tr:nth-child(3) td') → ✓ getByRole('row', { name: /Order 1042/ })
await page.locator('.login-form input.username').fill('ada');
await page.getByLabel('Username').fill('ada');
Guardrails
- These are proposed swaps the engineer must run and confirm — never assume the
new locator resolves to the same element without checking the real DOM.
- Never invent a
data-testid or accessible name; if none exists, flag that the
app needs one (// TODO: needs data-testid).
- Prefer role/label semantics over testid; testid is the fallback, not the default.
- Do not silently change behavior (strictness, count) — call out multi-match risks.