new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Playwright · all subjects

locators and strictness

109 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

Strict mode: single-element operations throw on multiple matches

Single-element operations like click() throw an error if more than one element matches the locator.

Strict mode: multiple-element operations work fine with multiple matches

Multiple-element operations like count() work perfectly fine when the locator resolves to multiple elements.

Locators are strict by default

Locators are strict, meaning that all operations on locators that imply some target DOM element will throw an exception if more than one element matches.

Locators are the central piece of Playwright's auto-waiting and retry-ability

Locators represent a way to find element(s) on the page at any moment. They are the foundation of Playwright's automatic waiting and retry mechanisms.

Recommended built-in locators in priority order

Use these built-in locators in order of recommendation: getByRole() to locate by explicit and implicit accessibility attributes; getByText() to locate by text content; getByLabel() to locate a form control by associated label's text; getByPlaceholder() to locate an input by placeholder; getByAltText() to locate an element, usually image, by its text alternative; getByTitle() to locate an element by its title attribute; getByTestId() to locate an element based on its data-testid attribute (other attributes can be configured).

Locators are re-evaluated on every action

Every time a locator is used for an action, an up-to-date DOM element is located in the page. This means that if the DOM changes between calls due to re-render, the new element corresponding to the locator will be used.

Locator methods are available on Page, Locator, and FrameLocator classes

All methods that create a locator, such as getByLabel(), are also available on the Locator and FrameLocator classes, so you can chain them and iteratively narrow down your locator.

getByRole locator reflects user and assistive technology perception

The getByRole() locator reflects how users and assistive technology perceive the page, for example whether some element is a button or a checkbox. When locating by role, you should usually pass the accessible name as well, so that the locator pinpoints the exact element. Role locators follow W3C specifications for ARIA role, ARIA attributes and accessible name. Many HTML elements like <button> have an implicitly defined role that is recognized by the role locator.

Role locators do not replace accessibility audits and conformance tests

Role locators give early feedback about the ARIA guidelines but do not replace accessibility audits and conformance tests.

Prioritize role locators for element location

Role locators should be prioritized to locate elements, as they provide the closest way to how users and assistive technology perceive the page.

Use getByLabel for form field location

Most form controls usually have dedicated labels. Use getByLabel() when locating form fields.

Use getByPlaceholder for inputs without labels

Use getByPlaceholder() when locating form elements that do not have labels but do have placeholder texts.

Text locators normalize whitespace

Matching by text always normalizes whitespace, even with exact match. This means it turns multiple spaces into one, turns line breaks into spaces and ignores leading and trailing whitespace.

Use text locators for non-interactive elements

Text locators should be used to find non-interactive elements like div, span, p, etc. For interactive elements like button, a, input, etc. use role locators.

Use getByAltText for image location

Use getByAltText() when your element supports alt text such as img and area elements.

Use getByTitle for elements with title attribute

Use getByTitle() when your element has the title attribute.

Test IDs are the most resilient way of testing

Testing by test ids is the most resilient way of testing as even if your text or role of the attribute changes, the test will still pass. However testing by test ids is not user facing. If the role or text value is important to you then consider using user facing locators such as role and text locators.

Configure custom test id attribute in config or via API

By default, getByTestId() will locate elements based on the data-testid attribute, but you can configure it in your test config using the testIdAttribute option or by calling Selectors.setTestIdAttribute().

CSS and XPath locators are not recommended

CSS and XPath selectors can be tied to the DOM structure or implementation and can break when the DOM structure changes. Long CSS or XPath chains are an example of bad practice that leads to unstable tests. Instead, try to come up with a locator that is close to how the user perceives the page such as role locators or define an explicit testing contract using test ids.

CSS and XPath selector auto-detection

Playwright supports CSS and XPath selectors, and auto-detects them if you omit the css= or xpath= prefix. So 'button' is auto-detected as CSS and '//button' is auto-detected as XPath.

Locators work with Shadow DOM by default

All locators in Playwright work with elements in Shadow DOM by default. The exceptions are: locating by XPath does not pierce shadow roots, and closed-mode shadow roots are not supported.

Filter locators by text using Locator.filter()

Locators can be filtered by text with the Locator.filter() method. It will search for a particular string somewhere inside the element, possibly in a descendant element, case-insensitively. You can also pass a regular expression.

Filter locators by not having text

You can filter locators by not having text using the hasNotText option in the filter() method.

Filter locators by child or descendant element

Locators support an option to only select elements that have or have not a descendant matching another locator. You can filter by any other locator such as getByRole(), getByTestId(), getByText() etc. using the has or hasNot options.

Filter locators must be relative to the original locator

The filtering locator must be relative to the original locator and is queried starting with the original locator match, not the document root.

Chain two locators together with locator() method

You can chain two locators together by using the locator() method on an existing locator. For example, to find a 'Save' button inside a particular dialog, you can use dialog.locator(saveButton).click().

Locator.and() narrows down by matching an additional locator

The Locator.and() method narrows down an existing locator by matching an additional locator. For example, you can combine getByRole() and getByTitle() to match by both role and title.

Locator.or() creates a locator that matches alternative locators

The Locator.or() method creates a locator that matches any one or both of two or more alternative locators. If both alternatives appear on screen, the 'or' locator will match both of them, possibly throwing a strict mode violation error.

Filter visible elements only

You can filter locators to only match visible elements using the visible: true option in the filter() method. However, it's usually better to find a more reliable way to uniquely identify the element instead of checking visibility.

Assert locator count to count list items

You can assert locators with toHaveCount() to count the items in a list.

Assert all text in a list with toHaveText()

You can assert locators with toHaveText() to find all the text in a list. Pass an array of strings to assert the text content of all matching elements.

Get specific list item by text with getByText()

Use the getByText() method to locate an element in a list by its text content and then click on it.

Get specific list item using Locator.nth(), first(), or last()

If you have a list of identical elements and the only way to distinguish between them is the order, you can choose a specific element from a list with Locator.first(), Locator.last() or Locator.nth(). However, use this method with caution because the page might change and the locator will point to a completely different element.

Iterate elements using Locator.all()

You can iterate over elements using the Locator.all() method, which returns all matching elements.

Evaluate JavaScript on locators with evaluateAll()

The Locator.evaluateAll() method runs code in the page and can call any DOM apis. The code receives a list of elements and can return any value.

Opt-out of strictness with first(), last(), and nth()

You can explicitly opt-out from strictness check by telling Playwright which element to use when multiple elements match, through Locator.first(), Locator.last(), and Locator.nth(). These methods are not recommended because when your page changes, Playwright may click on an element you did not intend.

Page-free locators with 'by' object (JavaScript only)

A Locator is bound to a page, so it can only be created once a page exists. By describes the same element without a page, which means it can be defined once at module scope and shared between tests. Build one with the top-level 'by' object and bind it with Page.get(), Frame.get() or Locator.get().

By supports the same chaining, filtering and operators as Locator

A By supports the same chaining, filtering and operators as a Locator, and resolves to exactly the same element. Since a By is immutable, scoping one never changes the original.

Test IDs are resolved when By is bound to a page

Test ids are resolved when the By is bound to a page, so a module-scope By still honours the testIdAttribute option from the config.

Example: getByLabel and click for sign-in form

Basic example of locating and filling form fields: ```js await page.getByLabel('User Name').fill('John'); await page.getByLabel('Password').fill('secret-password'); await page.getByRole('button', { name: 'Sign in' }).click(); await expect(page.getByText('Welcome, John!')).toBeVisible(); ```

Example: getByRole with name parameter

Example of using getByRole with the name parameter: ```js await expect(page.getByRole('heading', { name: 'Sign up' })).toBeVisible(); await page.getByRole('checkbox', { name: 'Subscribe' }).check(); await page.getByRole('button', { name: /submit/i }).click(); ```

Example: chaining locators with frameLocator

Example of chaining locators across frame boundaries: ```js const locator = page .frameLocator('#my-frame') .getByRole('button', { name: 'Sign in' }); await locator.click(); ```

Example: getByText with exact match

Example of using getByText with exact match: ```js await expect(page.getByText('Welcome, John', { exact: true })).toBeVisible(); ```

Example: getByText with regular expression

Example of using getByText with a regular expression: ```js await expect(page.getByText(/welcome, [A-Za-z]+$/i)).toBeVisible(); ```

Example: configure custom test id attribute

Example of configuring a custom test id attribute in playwright.config.ts: ```js import { defineConfig } from '@playwright/test'; export default defineConfig({ use: { testIdAttribute: 'data-pw' } }); ```

Example: CSS and XPath locator usage

Example of using CSS and XPath locators (not recommended): ```js await page.locator('css=button').click(); await page.locator('xpath=//button').click(); await page.locator('button').click(); // auto-detected as CSS await page.locator('//button').click(); // auto-detected as XPath ```

Example: filter by text with regex

Example of filtering locators by text using a regular expression: ```js await page .getByRole('listitem') .filter({ hasText: /Product 2/ }) .getByRole('button', { name: 'Add to cart' }) .click(); ```

Example: filter by not having text

Example of filtering locators by not having text: ```js // 5 in-stock items await expect(page.getByRole('listitem').filter({ hasNotText: 'Out of stock' })).toHaveCount(5); ```

Example: filter by child element

Example of filtering locators by having a child element: ```js await page .getByRole('listitem') .filter({ has: page.getByRole('heading', { name: 'Product 2' }) }) .getByRole('button', { name: 'Add to cart' }) .click(); ```

Example: filter by not having child element

Example of filtering locators by not having a child element: ```js await expect(page .getByRole('listitem') .filter({ hasNot: page.getByText('Product 2') })) .toHaveCount(1); ```

Example: chain locators and reuse

Example of chaining locators and reusing them: ```js const product = page.getByRole('listitem').filter({ hasText: 'Product 2' }); await product.getByRole('button', { name: 'Add to cart' }).click(); await expect(product).toHaveCount(1); ```

Example: and() to match multiple criteria

Example of using Locator.and() to combine multiple locators: ```js const button = page.getByRole('button').and(page.getByTitle('Subscribe')); ```

Example: or() for alternative locators

Example of using Locator.or() to match alternative locators: ```js const newEmail = page.getByRole('button', { name: 'New' }); const dialog = page.getByText('Confirm security settings'); await expect(newEmail.or(dialog).first()).toBeVisible(); if (await dialog.isVisible()) await page.getByRole('button', { name: 'Dismiss' }).click(); await newEmail.click(); ```

Example: filter to show only visible elements

Example of filtering locators to only show visible elements: ```js await page.locator('button').filter({ visible: true }).click(); ```

Example: count list items

Example of counting list items: ```js await expect(page.getByRole('listitem')).toHaveCount(3); ```

Example: assert all text in a list

Example of asserting all text in a list: ```js await expect(page.getByRole('listitem')).toHaveText(['apple', 'banana', 'orange']); ```

Example: get specific item by nth position

Example of getting a specific item from a list by position: ```js const banana = await page.getByRole('listitem').nth(1); ```

Example: iterate elements with all()

Example of iterating over list elements: ```js for (const row of await page.getByRole('listitem').all()) console.log(await row.textContent()); ```

Example: chain filters on list items

Example of chaining multiple filters: ```js const rowLocator = page.getByRole('listitem'); await rowLocator .filter({ hasText: 'Mary' }) .filter({ has: page.getByRole('button', { name: 'Say goodbye' }) }) .screenshot({ path: 'screenshot.png' }); ```

Example: evaluateAll for batch operations

Example of using evaluateAll to extract data from multiple elements: ```js const rows = page.getByRole('listitem'); const texts = await rows.evaluateAll( list => list.map(element => element.textContent)); ```

Give your agent this brain