Playwright Locators Tutorial with Examples: Use AI to Build Better Test Automation

Playwright Locators Tutorial with Examples Use AI to Build Better Test Automationv

Introduction

Playwright locators are the single biggest factor in whether a test suite stays reliable over time or slowly turns into a maintenance burden nobody wants to touch. Every Playwright automation testing project depends on finding the right element on the page before clicking, typing, or asserting against it, and that “finding” step is exactly what a Playwright locator does.

This guide goes far deeper than the brief locator overview most beginner tutorials cover. It walks through every major Playwright locator type with real JavaScript examples, the priority order Playwright itself recommends, chaining and filtering techniques, tricky cases like iframes and dynamic content, the mistakes that quietly make test suites fragile, and how AI tools now help write and repair Playwright locators faster than doing it by hand.

Before jump into full aticle explore these basic articles

 Playwright Automation Testing with AI: Complete JavaScript & TypeScript Framework From Scratch

Playwright CI/CD setup with GitHub Actions and AI Complete Automation Testing Pipeline Guide

What Are Playwright Locators?

A locator is how a Playwright script finds an element on a page before interacting with it. Rather than grabbing an element once and hoping it still exists a few lines later, Playwright locators are lazy by design, meaning they re-locate the element each time an action runs. This is part of why Playwright’s auto-waiting works so well: the Playwright locator checks the current state of the page at the moment of the action, not an outdated snapshot from earlier in the test.

Why Playwright Locators Strategy Matters

Two tests can do exactly the same thing and behave completely differently over time, purely based on locator choice. A test built on a role or text-based Playwright locator tends to survive a redesign untouched. A test built on a deep CSS selector tied to a specific div structure often breaks the moment a developer reorganizes a component, even if nothing about the actual user-facing behavior changed.

This is not a minor detail. Teams that ignore locator strategy early usually end up rewriting large parts of their suite later, once enough small UI changes accumulate. Getting Playwright locators right from the start is one of the cheapest investments in a test automation project.

Locator Priority: What to Use First

Playwright’s own documentation recommends a rough priority order, and following it consistently is one of the simplest ways to keep a suite maintainable.

  1. getByRole() – tied to accessibility semantics, the most resilient option
  2. getByText() – tied to visible content a real user would read
  3. getByLabel() – tied to form labels, ideal for inputs
  4. getByTestId() – tied to a dedicated test attribute, stable but requires developer cooperation
  5. CSS selectors – tied to markup structure, more brittle
  6. XPath – the most flexible but generally the last resort

The general rule: pick the locator strategy closest to how a real user would identify the element, and only drop down to CSS or XPath when nothing higher up the list works.

getByRole() Explained with Examples

getByRole() targets elements by their accessibility role, which is the same information screen readers rely on. This makes it the most resilient locator strategy available, since it depends on semantics rather than styling.

javascript

await page.getByRole('button', { name: 'Login' }).click();
await page.getByRole('link', { name: 'Sign up' }).click();
await page.getByRole('checkbox', { name: 'Remember me' }).check();

Each of these examples targets an element by what it is and what it says, not by its class name or position in the DOM, which is exactly why this style of locators holds up well over time.

getByText() and getByLabel() Explained with Examples

getByText() finds an element by its visible text content, which works well for buttons, headings, or any element without a clear accessibility role attached.

javascript

await page.getByText('Welcome back').isVisible();

getByLabel() finds a form field by its associated label, which is often the cleanest way to target inputs.

javascript

await page.getByLabel('Email address').fill('user@example.com');

Both of these locators read almost like plain English, which also makes test files easier for a new team member to understand without prior context.

CSS Selectors: When and How to Use Them

CSS selectors give precise control when accessibility roles or visible text are not reliable or available, such as targeting a specific icon inside a repeated component.

javascript

await page.locator('.nav-menu__item--active').click();

CSS-based Playwright locators are useful, but they tie a test directly to markup structure. A class name rename or a restructured component can silently break a test that was working correctly the day before, which is why CSS should generally sit below role and text-based Playwright locators in priority.

XPath: When and How to Use Them

XPath remains the most flexible Playwright locator option, capable of navigating up, down, and sideways through the DOM in ways CSS selectors cannot.

javascript

await page.locator('xpath=//div[@class="results"]/ul/li[3]').click();

This flexibility comes at a cost. XPath expressions like this one are tightly coupled to DOM structure and tend to be the hardest Playwright locators to read and maintain months later. XPath is worth keeping in the toolbox for genuinely complex, deeply nested cases, but it should rarely be the first choice.

Chaining and Filtering Locators

Real pages often contain repeated elements, several cards, several rows, several buttons with the same label, and a single Playwright locator alone is not always enough to pick the right one.

javascript

await page.locator('.product-card').filter({ hasText: 'Wireless Mouse' }).getByRole('button', { name: 'Add to cart' }).click();

This chains a base Playwright locator, filters it down to the one matching specific text, then finds the button inside that specific match. .first() and .nth() work similarly, narrowing a broader Playwright locator down to exactly one element when several matches exist.

javascript

await page.getByRole('listitem').nth(2).click();

Chaining and filtering are what make Playwright locators genuinely usable on real, data-heavy pages rather than simple demo sites.

Handling Dynamic Content, iFrames, and Shadow DOM

Not every element sits in a simple, static part of the page, and this is where a lot of beginner-level locator knowledge runs out.

Dynamic content. Elements that load asynchronously, such as search results or a spinner-gated section, do not need extra waiting logic in most cases. Playwright locators already wait for the element to appear before acting, as long as the locator itself is written correctly against the final rendered state.

iFrames. Elements inside an iframe are not reachable through the main page locator directly. They need to be accessed through a frame locator first.

javascript

await page.frameLocator('#payment-frame').getByLabel('Card number').fill('4242424242424242');

Shadow DOM. Playwright automatically pierces open shadow roots, so most shadow DOM elements can be targeted the same way as regular elements, without special syntax, which is a meaningful advantage over some older automation tools.

Common Playwright Locator Mistakes

Chaining CSS classes too deeply. A selector like .container .row .col-md-4 .card-body button breaks the moment any single layer of that structure changes, even if the button itself never moved.

Relying on nth-child() for anything that reorders. Position-based selectors are one of the most common sources of flaky, hard-to-debug failures once list content changes order.

Reaching for XPath by default. XPath is powerful, but defaulting to it skips the more resilient options higher in the priority list for no real benefit in most cases.

Ignoring accessibility roles that already exist. Many elements already have a usable role or label in the markup. Writing a CSS selector instead, simply out of habit, throws away a more stable option that was already available.

Not filtering repeated elements properly. Grabbing the first match on a page with several similar elements often works by accident during development and breaks the first time the page order changes in production.

Using AI to Write and Fix Locators

AI assistants have become genuinely useful for working with Playwright locators, in three specific ways worth understanding rather than treating as a vague catch-all benefit.

Generating a locator from a description or pasted HTML. Describing an element in plain language, or pasting the relevant HTML snippet, and asking an AI assistant for the most resilient locator gives a strong starting point, usually favoring role or text-based options automatically.

Fixing a broken locator after a UI change. Pasting the old, failing locator alongside the new HTML lets an AI assistant diagnose what changed and suggest a replacement, often one that is more resilient than a quick manual patch would have been.

Auditing an existing test file for brittle locators. AI tools can scan a spec file and flag deep CSS chains or fragile XPath expressions, proposing role or text-based alternatives, which is a fast way to improve an older test suite without rewriting it from scratch.

As with any AI-assisted change to a test suite, every suggested locator still needs a human review pass to confirm it targets the right element and does not just happen to pass on the current version of the page.

A Worked Example: Fixing a Broken Locator with AI

Consider a real scenario. A checkout page originally had this Playwright locator, tied to a specific CSS structure:

javascript

await page.locator('.checkout-panel > div:nth-child(3) > button').click();

After a redesign, the checkout panel’s internal layout changed, and this locator started failing in CI even though the “Place Order” button still existed on the page. Pasting the old locator alongside the new page HTML into an AI assistant, and asking it to suggest a more resilient replacement, produces something closer to this:

javascript

await page.getByRole('button', { name: 'Place Order' }).click();

The fix is not just a patch, it is a genuine improvement. The new Playwright locator no longer depends on the internal structure of the checkout panel at all. It depends only on the button’s accessible name, which is far less likely to change even through several future redesigns. This is the practical value of AI-assisted locator repair: it tends to nudge a fix toward the top of the priority list rather than simply patching the same brittle pattern that broke in the first place.

The same approach works in reverse for entire test files. Pointing an AI assistant at an existing spec file and asking it to flag any Playwright locators using deep CSS chains or nth-child() selectors often surfaces several quiet risk points a team has been living with for months, without anyone reviewing them until something actually breaks.

Playwright Locators Best Practices Checklist

    Everything covered in this guide comes down to a short list of habits. Teams that consistently apply these Playwright locators best practices tend to end up with suites that survive redesigns with minimal rework, while teams that skip them usually end up rewriting large chunks of their tests every time the UI changes.

    • Default to getByRole() before anything else. It is the most resilient of all the Playwright locators covered here because it depends on accessibility semantics, not markup.
    • Use getByText() and getByLabel() for content and form fields. These read close to plain English and stay stable as long as the visible copy or label text does not change.
    • Reserve CSS selectors for cases with no reasonable role or text option. They still have a place among Playwright locators, just lower in the priority order than role or text.
    • Treat XPath as a last resort, not a starting point. Powerful, but generally the hardest of all Playwright locators to read and maintain months later.
    • Filter and chain locators instead of relying on raw position. .filter() and .nth() handle repeated elements far more reliably than assuming a fixed order.
    • Use frameLocator() for anything inside an iframe. Elements inside a frame are never reachable through the page’s main locator directly.
    • Review AI-suggested locators before merging them, the same as any other code change. AI speeds up writing Playwright locators, but it does not replace confirming they target the right element.
    • Revisit old, brittle locators periodically rather than only fixing them after a failure. A short periodic audit catches fragile patterns before they cause a flaky CI run.

    Conclusion

    Playwright locators are not a small implementation detail buried inside a test file. They are the foundation that determines whether an entire test suite stays maintainable as an application grows, or slowly turns into something the team dreads touching. Favoring role and text-based locators, using CSS and XPath only when genuinely necessary, and handling dynamic content, iframes, and repeated elements correctly covers the vast majority of real-world cases.

    AI assistants now make writing and repairing these locators noticeably faster, particularly for diagnosing why a locator broke after a UI change, but they work best as a starting point reviewed by someone who understands the priority order covered in this guide, not as a replacement for that understanding.

    Explore more articles from AI blogs AI Learning Hub, AI tools pagesubscribe to AI Pathway Lab  AI for Testers

    3 Proven Ways AI Accelerates Software QA Workflows

    Automation with AI, Write Test Scripts 10x Faster in 2026

    AI Workflows for QA Automation, How to Integrate

    For official reference material, Playwright’s own locators documentation covers the full API in detail, and the MDN ARIA reference explains the semantics behind getByRole() more deeply for anyone who wants to understand what is happening underneath it.

    Frequently Asked Questions

    What is the best type of locator to use in Playwright?

    getByRole() is generally the most resilient choice, since it targets elements by their accessibility semantics rather than markup structure or styling, which tends to survive UI changes far better.v

    When should I use XPath instead of CSS selectors?

    XPath is worth reaching for when an element needs to be located relative to a parent, sibling, or ancestor in a way CSS cannot express, but it should not be the default choice for straightforward cases.

    Do Playwright locators automatically wait for elements to appear?

    Yes. Playwright locators are designed to wait for an element to become actionable before performing an action, which removes most of the manual wait logic older tools required.

    How do I locate an element inside an iframe

    Use frameLocator() to first target the iframe itself, then chain a normal locator inside it to reach the element, since elements inside an iframe are not reachable through the page’s main locator directly.

    Can AI reliably generate correct Playwright locators?

    AI-generated locators are usually a strong starting point, especially when given real HTML context, but they still need a human review pass to confirm they target the correct element reliably.

    Why do my tests pass locally but fail in CI due to locator issues?

    This is often caused by a locator that happens to match the first available element during a fast local run, but matches a different or missing element once timing, data, or rendering order shifts slightly in a CI environment.

    Leave a Comment

    Your email address will not be published. Required fields are marked *