Playwright Locators

Locators are expressions that identify elements on a web page. This document provides standards on using effective locators in Playwright tests.

Standard Metadata

  • Area: Playwright
  • Owner: Technical Leadership group
  • Last reviewed: 2026-10-07
  • Next review due from: 2026-12-01
  • Enforcement: Code review
  • Status: Active

Playwright locators should reference their underlying elements · PW-05.1 · SHOULD · TEST

When implementing Page Object Model, locators reflect the user’s perspective - this is also referred to as having user-centric locators.

Playwright’s documentation details the different methods which can be used to locate an element.

For example, to “Login” a user would identify the login button by its appearance as a button, and its name.

// pages/login.page.ts

// Identifies the button the way a user would: by its role and visible name
loginButton = () => this.page.getByRole('button', { name: 'Login' });

Playwright locator names must use the element’s visible text or function, followed by its type · PW-05.2 · MUST · TEST

Base the first part of a locator’s name on the text, label or placeholder a user sees on the element. Where an element has no visible text, name it after its function. This makes locators easy to match to the page, and helps new engineers become familiar with the system and its automated tests.

End the name with the element type, using the suffixes below. This keeps locator names consistent across pages and tests.

Element Suffix Example
Button Button saveDetailsButton()
Text input or text area Input emailInput()
Checkbox Checkbox subscribeCheckbox()
Dropdown Dropdown countryDropdown()
Link Link forgotPasswordLink()
Static text or heading Text welcomeText()
Toast or alert Toast customerRemovedToast()
Image Image logoImage()
Table, row or cell Table, Row, Cell customersTable()
// Named after its visible text, "Sign Up"
signUpButton = () => this.page.getByRole('button', { name: 'Sign Up' });

// No visible label, so named after its function
passwordInput = () => this.page.getByPlaceholder('Enter your password');

Playwright locators must be action-independent · PW-05.3 · MUST · TEST

Locators must not be tied to any actions that manipulates or retrieves information from the element, to ensure;

  1. The element is versatile and re-usable
  2. Actions being performed on locators are readable
  3. Test failures and timeouts are observable

Any actions to be performed on an element, i.e typing or getting the value, should be defined separately in tests or functions.

// Login Page example of the page object model within the Audacia Template

// Locators
usernameInput = () => this.page.getByLabel('Username');
passwordInput = () => this.page.getByLabel('Password');
loginButton = () => this.page.getByRole('button', { name: 'Login' });

// Actions
public async confirmLogin() {
  // Start waiting for the login request before clicking, so the response isn't missed
  const loginResponse = this.page.waitForResponse(response =>
    response.url().includes('/connect/token') && response.status() === 200);

  await this.loginButton().click();
  await loginResponse;
}

Playwright locators should use the most user-centric method available · PW-05.4 · SHOULD · TEST

Use the first method in this list that can find the element. Methods higher in the list match how a user sees the page, so they read more clearly and are less likely to break when the DOM changes. The order follows The Testing Library’s priority.

Priority Method Use for
1 getByRole() Buttons, links, checkboxes, options, tables and other elements with a role
2 getByLabel() or getByPlaceholder() Form fields
3 getByText() or getByAltText() Non-interactive text and images
4 getByTestId() Elements with no usable role or text, such as dynamic text. Test IDs follow the CSS selectors for automated tests format
subscribeCheckbox = () => this.page.getByRole('checkbox', { name: 'Subscribe' });
emailInput = () => this.page.getByLabel('Email');
searchInput = () => this.page.getByPlaceholder('Search...');
welcomeText = () => this.page.getByText('Welcome to Audacia!');
logoImage = () => this.page.getByAltText('Company Logo');
directionsText = () => this.page.getByTestId('view-route__directions-panel__directions-text');

.locator() must only be used as a last resort · PW-05.5 · MUST · TEST

Only use .locator() with a CSS or XPath selector when none of the methods in PW-05.4 can find the element. The Playwright documentation recommends against it, because these selectors break when the DOM changes. Where possible, ask the developers to add a data-testid instead.

Use the most stable selector available:

// ✔️ A unique ID or stable attribute
usernameInput = () => this.page.locator('#username');
usernameInput = () => this.page.locator('input[name="username"]');

// ❌ Class names change with styling and may come from a third-party library such as MudBlazor
usernameInput = () => this.page.locator('.mud-input-slot');

// ❌ Positions and DOM paths break when the order or layout of the page changes
usernameInput = () => this.page.locator('input').first();
usernameInput = () => this.page.locator('//div[2]/form/input');

Use chained Playwright locators for readability · PW-05.6 · COULD · TEST

Chained locators can be used to select an element that is nested within another identifiable area of the page. This method is particularly useful when multiple elements share the same name or title but are distinguished by their location within the page’s structure.

Example:

// Locate the table row containing a specific username
userRow = (name: string) => this.page.getByRole('row').filter({ has: this.page.getByRole('cell', { name, exact: true }) });

// Chain locators to find the 'Select user' button within the context of a specific username
selectUserButton = (name: string) => this.userRow(name).getByTitle('Select user');

// Chain locators to find the 'Switch user' button within the context of a specific username
switchUserButton = (name: string) => this.userRow(name).getByLabel('Switch user');

Restrictions on chained locators

Chained locators do not work in scenarios where you need to interact with one element and then another in a non-nested context.

Chaining locators also shouldn’t be used for dropdowns, as there is a built in .selectOption() function available. See the Playwright documentation on selectOption.