Working with Selenium Webdriver locators

In my last blog I described Selenium Webdriver as an automation tool and the advantages of it.  In this blog I will share my experience working with locators which are supported by Webdriver. Locator types are the ways to locate some particular element or a group of elements on the page.

Locators provided by Webdriver 

Most of the work with Webdriver involves WebElement entity, which is nothing more than web elements located on the page. To perform any actions on web elements, you need to find them. Here are the ways how you can do it with Selenium Webdriver:

WebElement element = driver.findElement(By.<Selector>);

This is how Webdriver locates elements. By is a class that consists of static methods for elements identification. 

  1. id

Example:

<div id=”element”>
     <p>some content</p>
</div>

Locating the element:  
WebElement element = driver.findElement(By.id(“element”));

This locator type is the most simple and reliable way of finding an element because id is a unique attribute which guarantees that you will find the element. It’s also the fastest way, because it’s the most optimized in all the browsers. You can find elements by id with the help of CSS selectors (“#element”) or XPath selectors (“//div[@id=’element’]”), but we’ll come to that later. It would be great for all the elements on the page to have constant id attributes, but the world is not an ideal place.  As practice shows, this locator type is not used as frequently as you would like. If an element doesn’t have an id or it’s a dynamic one, go down the list.

  1. name

Example:

<div name=”element”>
     <p>some content</p>
</div>

Locating the element:
 WebElement element = driver.findElement(By.name(“element”));

Finding an element by name is usually comfortable and fast in most browsers. However, you need to remember that “name” is not a unique attribute and if there are some elements in the DOM with the same name, you may get a different element than you intended. Let’s go down.

  1. className

Example:

<img class=”logo”>

Locating the element:
WebElement element = driver.findElement(By.className(“element”));

While finding elements by id or name can be useful, CSS locator type provides more capabilities for finding elements by class.  For example we need to find <img class=”logo img-small”>. The element has several classes, both of which we want to use to identify the element. By.className will match the whole class attribute string or a particular class. If you use XPath selector (“//img[@class=’logo img-small’]”)  and you don’t mention all the classes, you will get an exception (NoSuchElementException), because it treats class attribute as a string like any other attribute .  

You may wonder, “So what’s the problem?  We can type the whole string over ‘class’ attribute.” That variant has a lot of disadvantages. Firstly, there can be many classes and the string will be too long and brittle. Secondly, with the help of JavaScript some classes can be added or deleted and you’ll get an incorrect locator. Thirdly, sometimes you need to find a couple of elements with the same class. In that case you should use By.cssSelector: img.logo, img.img-small or .img. img-small. These are different CSS selectors that will find the picture(s) you need. Personally, I have never used the By.className locator, replacing it with the more flexible By.cssSelector.

  1. tagName

Example:

<div>
    <a class=”logo” ref=”..”>…</a>
    <a class=”support” ref=”..”>…</a>
</div>

Locating the element:
List<WebElement> elements = driver.findElements(By.tagName(“a”));

This locator is searching for elements by their html-tags. What can be simpler? But By.tagName is not always the best way to find exact elements. You may get something different from what you are searching for. By pairing By.tagName with findElements you will get all the links on the page. For example, we have found two links in the case above. 

  1. linkText. 6.By.partialLinkText

<div>
    <a ref=”..”>text</a>
    <a ref=”..”>Another text</a>
</div>

Locating the element:
WebElement element = driver.findElement(By.linkText(“text”));
WebElement element = driver.findElement(By.partialLinkText(“text”));

By.linkText and By.partialLinkText are self-describing. They have a lot in common in that they are only searching for elements with tag <a> and the search is performed by containing text in the element (<a> text</a>).  The difference between them is By.linkText searches only for elements with exact text matching, and By.partialLinkText searches anything that contains searched text.  By.linkText(“text”) will return one link, while By.partialLinkText(“text”) – two links. In general, these two locators are a simple way for finding links by text. You can achieve the same result by using XPath selector: “//a[text()=’text’] – corresponding to the first example and  “//a[contains(text(),’text’)] – for the second one. CSS locator type fails to cope with this task. That’s because CSS 3 specification does not have a pseudo-class contains() in it anymore, and now driver.findElements(By.cssSelector(“a:contains(‘text’)”)) is not going to work.

In my next blog I will describe when you should use CSS and XPath selectors for more proficient locator strategies.