Locating elements on a web page is the life-line to any web based automation tool, which supports UI automation testing. Starting with Selenium, there are various locator strategy, like
xpaths, for locating a specific element – may be a button, an input box, a combo box, a drop down etc. from a given web page.
One of such selector locating mechanism is
CSS Selector. Using attributes like class, tags, specific to an element, we can identify a specific element on the web page.
For e.g. consider this HTML snippet
<div> <p class="first">I am first</p> <div>I am second</div> <p class="second">I am 3rd</p> </div>
Let’s say I want to identify the first
p element inside the first
div tag. So I can use this
css selector in Selenium ( Python) to identify this element
However, when automating applications , we rarely find such simple scenarios. There are lot of web controls on modern web pages, build with front end libraries like React, Angular, which make it hard to use simple CSS locators.
Generally when automating web pages, we come across scenarios, where there is a parent tag, and then there are child elements present inside the parent tag – an example would be a drop down, implemented using a
Select tag, or an un-ordered list , inside which there are multiple list elements
<ul class="sample"> < li class="sample1"> first </li> < li class="sample1"> second </li> < li class="sample1"> third </li> < li class="sample1"> fourth </li> </ul>
Here, all the
li elements have the same class
sample1 and neither do they have any distinct
id or such attribute. So in order to automate such scenarios, we can use the
nth ordering of the element inside the CSS selectors.
Playwright is a new e2e automation library, which is currently gaining a lot of attention and tracking in the e2e automation market. Playwright has it’s roots in the erstwhile Puppeteer, which was developed by team at Google. The same team, is behind Playwright, but now with MS.
Playwright, has a lot of features, and recently a lot of comparisons have shown that it is vastly improved in terms of speed, reliability, and execution than it’s peers like Cypress, WebdriverIO, TestCafe etc – here is a detailed comparative study reflecting this. I’m not going to go deep into the features of Playwright. There are many articles on the web, like this, which explains the details of Playwright.
One of the very interesting feature of Playwright is the ease and versatility of how it allows us to locate elements on the web page. Apart from the usual xpaths, css, there are a host of other locator mechanisms, which coupled with css and text attributes, help a lot in identifying elements on the page. You can refer to this detailed documentation on Playwright’s website.
Nth Selectors in Playwright – nth-child and nth-of-type
One of the reasons, why I, personally love Playwright is the number of different ways I can get elements that are not easy to be identified using normal locators. And I’ll take example of the list example that I’ve given above.
Now consider this following two HTML structure –
<section> <p>Playwright</p> <p>Puppeteer</p> <!-- We want this one --> </section>
<section> <h1> Selenium Alternatives </h1> <p>Playwright</p> <h2>WebdriverIO</h2> <p>Puppeteer</p> </section>
Now, how can we select the second element of the
p tag in the first HTML – here we can use the
nth-child() concept of CSS selectors.
The same thing can also be achieved using the
nth-of-type() concept of the CSS selectors
basically would return the same thing as the selector with
However, for the second HTML, there is a
h1 tag inserted between two
p tags, so using the first locator using
nth-child method will not return any element. However, the
p:nth-of-type() still holds good and will return the second
li child here.
Now, since we have talked about the
nth-child and the
nth-of-type concepts using CSS Selectors, there are a couple more that you can use in Playwright.
Consider this HTML snippet –
<div class="multipleclass secondclass"> <button type="button" class="btnclass"> <span>Button</span> </button> <button type="button" class="btnclass"> <span>Button</span> </button> </div>
Let’s say we have a scenario, where there are multiple buttons on page, which reside inside a single
div with same classes and have same button text, something similar to what is mentioned above. Here we have a
div with two buttons inside the
div. Both the button have same class and same text too. We could use the
nth-of-type to get the second element
we can use the
nth index to get the element in Playwright. Suppose we want to click on the second button, we can use
nth=1 to click to the button.
await page.locator('button >> nth=1').click();
await page.locator('button >> nth=0').click();
to click on the first button.
If you see carefully, the indexing is starts with
0 and not
1 as is generally in case of
Using nth-match concept
Consider a scenario, where on a single page, there are form elements with same name, for e.g. there are three button elements with the same name
Buy but there are under different tree-structure on the page.
<section> <button>Buy</button> </section> <article> <div> <button>Buy </button> </div> </article> <div> <div> <button>Buy </button> </div> </div>
Let’s say suppose you want to select the third button – with the text
Buy. So in Playwright we can use the
:text pseudoclass along with another CSS concept
nth-match to directly get to the element like
await page.locator(':nth-match(:text("Buy"), 3)').click();
Here, in this case, unlike the
nth selection concept, the indexing starts at
1. So we have to be very careful if you are using the
nth vs the
nth-match concept in this scenario.
Now, many may argue as to why do this, when instead, I could use any unique identifier from the last
div tag and then combine with the
button tag to get the element. Something like this
await page.locator('div.someclassinlastdiv > button');
will also work. However, I think it boils down to choice that you can make. I think since Playwright has already given us a specific way to working around this scenario, so we can use this. However, the second one is also fine and would work in the same way as well.
If you want to know how
nth-match internally works, you can follow this question I’ve raised on Playwright’s github.
nth index with locator
Kaushik, one of my favorite tech-vlogger about Playwright, also pointed out on LinkedIn, there we can use the following syntax also
This will also work if you’re trying to get the
nth index based element from a list, similar to what we have discussed above. The documentation clearly states about this here.
If you want to deep-dive on how Playwright allows us to locate elements, you should head over to the documentation on selectors in Playwright here.
Hope this post helps people who are starting with Playwright and how to use the different power of CSS Selector methods to locate elements on the page.