Playwright Locators: Targeting Elements Efficiently

Cerosh Jacob
3 min readFeb 27, 2024
Photo by Michael Dziedzic on Unsplash

The playwright offers a variety of locator methods such as getByText, locator, querySelector, and more, addressing a wide range of targeting needs. These methods provide simple and efficient ways to identify elements, which improves code readability and maintainability. Locators can be refined using the filter method or can be combined to navigate the DOM structure precisely. Playwright also supports locators based on accessibility roles, thus enhancing inclusivity and usability. The choice of locator method depends on the specific element interaction and the required precision level.

This post is useful for those familiar with Playwright locators. If this is your first time reading about Playwright locators, I recommend referring to the detailed explanations and examples in Playwright’s official documentation. Alternatively, for a concise version, you can continue reading my previous post. https://medium.com/@ceroshjacob/locators-in-playwright-1c2e2fd76ff2

This post highlights various approaches to identify an element, for a better understanding of DOM navigation, including the relevant HTML structure.

<div class="card-container">
<i class="fas fa-expand fa-lg collapsible fa-rotate-90"></i>
<div class="card-title">
<span class="card-title-icon fas fa-laptop"></span>
<span>Cloud Servers</span>
</div>
</div>
The visual representation of the card container is as follows.

Problem Statement: Clicking on the caret icon opens the Cloud Servers card. However, the caret lacks a unique identifier, and the class card-container is used multiple times.

As a result, we must employ a non-traditional approach to automate this simple click. The general problem involves identifying a particular child element via another child element. To address this, we initially identify the parent element using the known child element. Then, we navigate to the desired child element from the parent element.

This caret can be identified using the provided XPath. However, this solution does not use Playwright locators. It finds an element matching the specified selector within the ElementHandle subtree instead. If no elements match the selector, it returns null. This method is deprecated, therefore its use is discouraged.

const spanElement = await this.page.$('div[class="card-container"] span:has-text("Cloud Servers")');
const parentDivElement = await spanElement.$('xpath=../..');
const iElement = await parentDivElement.$('i');

Here is another approach where we’ve eliminated the use of ElementHandle and incorporated Playwright features like the xpath=.. method. This method targets the immediate parent node of the currently selected element. However, it’s less reliable because changes in the DOM structure could break your tests. As a result, the Playwright recommends using the locator.filter() approach.

const spanLocator = this.page.locator("xpath=//div[contains(@class, 'card-container')]//span[text()='Cloud Servers']");
const parentDivLocator = spanLocator.locator('xpath=../..');
const webhookExpandButton = parentDivLocator.locator('i').first();

This alternative method utilizes Playwright’s features. It first identifies the element containing the “Cloud Servers” text using Playwright’s recommended built-in locators. Then, it uses the filter method to locate its parent element with the card-container class, refining the selection based on a child locator and filtering out elements that don’t meet the requirements. Lastly, it recognizes the first <i> element within that parent container.

const child = this.page.getByText('Cloud Servers')
const parentLocator = this.page.locator('.card-container').filter({ has: child });
const webhookExpandButton = parentLocator.locator('i').first();

I prefer this approach because it offers a concise method for navigating the DOM structure to find target elements based on their relationships and content. It emphasizes the use of Playwright’s locator methods for element identification and filtering. Moreover, it highlights the importance of using context and relationships to accurately identify elements, especially in dynamic or complex web pages. As a final note, this approach should be used as a workaround only if adding a unique identifier is not possible. Otherwise, always look for stable unique identifiers. If they don’t exist, convince the relevant stakeholders to add a new one.

--

--