Parent Elements | Bondar Academy
Course: Playwright UI Testing with TypeScript
Module: Locators and Assertions
Instructor: Artem Bondar
Lesson Summary
In this lesson, you will learn how to locate parent elements using Playwright. This technique is particularly useful when you lack a unique locator for the desired element. By identifying the closest unique parent element, you can effectively find child elements. Key Techniques for Locating Parent Elements Use the locator method with a second argument to specify search details. Filter results by text or locator . Utilize the filter method for more complex queries. Example 1: Locating by Text To find an nb-card with specific text, use: await page.locator('nb-card', { hasText: 'using the grid' }) This returns the specific nb-card containing the text, allowing you to chain further commands to find child elements. Example 2: Using Unique Identifiers Instead of text, you can filter by a unique ID : await page.locator('nb-card', { has: page.locator('#input-email1') }) Example 3: Chaining Filters To narrow down results, you can apply multiple filters: await page.locator('nb-card').filter({ has: page.locator('nb-checkbox') }).filter({ hasText: 'Sign in' }) Using XPath As a last resort, you can use XPath to navigate one level up in the DOM: await page.locator('text=using the grid').locator('..').locator('input[type="email"]') In summary, to find web elements using Playwright, leverage the locator method with filters for text or locators, or use the filter method for chaining multiple conditions. For simple parent-child relationships, XPath can be used as a last option.
Video Transcript
In this lesson, you will learn how to locate parent elements. So this technique is very powerful in the situation when you don't have a unique enough locator for the element that you want to find. And you can find the closest unique parent element for this element, and then find a child element from that. So Playwright has several techniques how you can locate the parent elements, and we will talk about it in this lesson. And also, don't forget to commit your changes to the Git branch at the end of the lesson. So let's get into it. I'm going to start a new test. So in the previous lessons, when we were trying to select the input field for the email, we were using such things like a first element or particular index of the form that we want to select. So how we can use the power of the parent elements to find the exact email input field that we want? So we need to find something unique about each of the form in order to exactly locate the form. So we have different forms on this page that have email fields, and what is unique about those is that they all have a unique name, such as using a grid, basic form, an inline form, and so on. So if we open on any of those forms, for example, using the grid, and let's quickly inspect the structure of this form. So the text which is unique for each of the page is nb-card-header, while the rest of the card of the body located in the nb-card-body. So nb-card-header and nb-card-body are sibling elements. So that's why if we would try to locate using the grid first, trying to find the child elements such as email input field, it would not work because nb-card-body simply is not a child element in relation to using the grid. So what is child element is the entire nb-card, but nb-card is a parent locator for using the grid for nb-card-header. So the question, how to find the nb-card locator with definition is that we want to find nb-card only for the text using the grid. So we want to find the text and then a parent. I will show you a few techniques how to do that. So the approach number one, so we put a weight page locator, and we want to find our nb-card, right? Because as we know, this is the target element that we want to find. But we can provide a second argument to the locator method in form of the object that would specify our details for this search. And we want to find nb-card that has text using the grid. That's it. This way, Playwright will give us only nb-card that has this particular text. It doesn't matter where exactly. It can be located any inside of the DOM for this particular nb-card, but only one element will be returned instead of the several elements like we did in the previous lesson. And that's it. And then we can chain the next command out of this locator to find the desired element. In our example, what we wanted to find is this. GetByRoll, email, and perform a click. GetByRoll, text box, email, click. And let's run this. I open Playwright runner. Locating parent elements, running the test. Yeah, you see, it works perfectly fine. We were able to click on the email. Okay, moving on. In the next example, what you can do with the locator is providing a second attribute, but not as text, but as a locator. So, hasPage.locator. And we can provide any other unique locator inside of the nb-card that can be used as a unique identifier for the particular nb-card. And we know for this particular nb-card, we have an ID. So, if we inspect on the ID, we have this ID, input email1. And we can use this as our additional identifier for the exact nb-card. And I put locator, ID, and the rest is the same. GetByRoll, email, click. I'm running this one, and this also was successful. Here, I've selected the step. We can see the click was performed successfully. So, one more time. By providing a second argument into the locator method, you can filter the output of this locator method, and you can filter either by text or by the locator. So, let me show you another example, which is very similar to this one. So, page.locator. And we want to find, again, nb-card. But this time, instead of using built-in feature into this method, I will use a dedicated method called filter, which has pretty much similar capabilities to what is the second argument has for the locator method. But it is independent method in the playwright. So, we can do the same thing. We can do pass text. And then let's select this time, for example, basic form. And click on the basic form email input field. I'm running this again. And here we go. Click was performed on the basic form. And the same exact thing you can do using a locator as a filter. Await page.locator, nb-card. Then we want to filter has page locator. And we need to find some unique locator for the basic form. Let's quickly take a look. So, what we can do is we can take a color of this button. Because other buttons on this page has a different color. So, this color is unique. So, I'm making right click on the button. And we probably can take, let's look, look, look. So, we can take this class status danger. This should work. And I put dot status danger. And the rest is the same. And this time, instead of clicking on email, let's click on password input field. Yeah, the password field was successfully selected. So, you may wonder what is the difference? If locator has an option to filter the result, why do we need to use a filter method? Two reasons. The reason number one is if you want to use a user-facing locator such as getByRoll, getByRoll does not have a filter like that. So, you can chain an independent method filter to filter the result and to find the parent element that you want. And the second reason that you can actually chain a multiple filters one by one in order to filter your result output. So, let me show you this example. Let's say that we want to find the email input field for this particular form. So, let me collapse this. And for example, we have NBForms. This form, this one, and this form has a checkboxes, right? So, we can filter them first by checkboxes. And then we can filter by the name of the button sign in. So, this is sign in button. But we have another sign in button, which is this one. But this form doesn't have a checkbox. That's why Playwright will return us a unique combination of the form that have a checkbox and have a sign in text in there. So, let me show you that. So, I type await page.locator NBCard. Then what? First filter, we want to filter it by the checkboxes. Has page.locator. And the locator for the checkbox is, let's see, right click, inspect. Locator for the checkbox is this NBCheckbox. And we take this one. After the first filter is applied, we're going to have a three NBInputs return. But now we apply a second filter, .filter. And the second filter we want to apply by text. Has text. Sign in. And the rest we put a well-known command. GetTextBoxByEmail and click. Right here. So, going back and running the code. Here we go. And the expected email form was selected. So, going one more time. First, we found all NBCards. Initial input we filtered once, finding only those NBCards that have checkboxes. Then the filtered checkboxes card we filtered one more time, only with those that have a sign in. And since this is a unique combination of those, eventually only one NBCard was returned. And then within this NBCard, we found a text box with name email and we performed the click. This is how it worked. And the very last example of locating a parent element is not recommended, but still possible to use. When you want to just go one level up, for example, here. For our, let's say, using the grid. So, using the grid is located in the NBCard header. For us, in order to access the body, we need to just one level up to NBCard and then find the child element. So, you can do it using the XPath. And this is, I believe, the only one example when you should use XPath in the playwright. So, locator, and let's say we want to find first by the text. Text is using the grid. Then I put locator and as a second locator, I put dot dot. With this combination, we will go one level up to the parent element. And then we will perform the selection of our email input field. So, let's run it. Yeah, you can see it's also worked perfectly well. The email input field was selected. That's it. So, let's quickly summarize what we did in this lesson. In order to find a web element using allocator method, you can use a text filter or allocator filter. And then chain from this parent element all the child elements that you want to select. Also, you can alternatively use a filter method that will do exactly the same thing. What is the benefit of using a filter method? That you can chain multiple filters one by one, narrowing down your output to the unique element until you get the desired result. And if you just want to go one level up in the DOM to the parent element, you can use XPath approach by providing just double dots into the locator element and then find the child element that you want to find. All right, that's it, guys, and see you in the next lesson.