How to locate elements in Selenium WebDriver

By: Slav Kurochkin

This week I been participating at meetup organized by local QA hero Ron Harley, we had discussions on how to locate elements in Selenium WebDriver and what is the best practices of locating elements, we also had conversation on topic of xpath vs css. Here is my thoughts on it, and I have to agree with one of my test automation colleague(Freddy) that css might be a better(faster, cleaner) way to do it, but for me xpath still seems to be a bit more powerful.

Lets start from the Agenda:

1. Locating strategy
2. Different ways to locate elements on the page
3. Tips and Tricks
4. Tools
5. Xpath Extra

Strategy

Before we start working on Selenium tests we would need to find locators strategy and the best way to use it. Original idea came from "Need to find element in selenium by css". So before you decide what to use you would need to ask yourself few questions:

1. What I'm more familiar with CSS or XPATH?
2. Will your website have more than one language, if so than using By.partialLinkText and By.linkText probably not the best idea, also xpath "contains" seems to be not usable at that point.
3. Another question, will you work in IE8 and early versions? If so than xpath probably not a good idea, as Jim Evans pointed on stackoverflow XPATH performance would be slower compare to CSS. There is few other things which have been mentioned early in the same question thread:

  • CSS faster
  • CSS more readable
  • CSS is jQuery’s locating strategy
  • No one else uses XPATH anyways!

Well, originally it is from Santiago Suarez Ordoñez (SauceLabs.com) presentation, but Santiago also said in his presentation that the third reason "CSS is jQuery locating strategy" is not applicable in case of WebDriver 2 which is no longer supporting Sizzle.

But wait a second, there is should be another opinion, isn't it? Dave Haffner made his own research and it is actually showing us that performance is not that bad with xpath locators, here is his blog posts on the topic:

- Css Vs. X Path
- Css Vs. X Path, Under a Microscope

4. The strategy proposed on our meetup by Automation Engineer from CareCloud (unfortunately I haven't picked up his name), have to agree it is not that bad, even though I been against it for consistency reason:

- First locate element by ID
- If ID is dynamic locate elements by Name or ClassName.
- If there is more than one element with same Name or ClassName it will pick up the first element which have been found in DOM, then you might consider using cssSelector (which was a problem in HtmlUnitDriver) or XPATH strategy.
- If your website not supporting multiple languages than locate links by linkText ot partialLinkText, do it only if text would stay the same for a while, otherwise as Santi pointed in his presentation marketing people would be able to screw you up, by changing text in a link.

5. And one more point to keep in mind it's at what stage is your application, is it just started and UI will change often or it's been for a while and UI is kind of consistent.

Update: I asked Jim Evans about new EdgeDriver and he basically said that EdgeDriver currently (September 21, 2015) doesn't work with XPath, here is his tweet response:

Locators

First lets find out how to locate elements on the page, two simple ways first use Firebug (Firefox plugin):

Using Firebug to locate elements on the page

and second use Chrome Developer tool:

Using Chrome Dev tool to locate elements on the page

Here is how to do it:

- Find element you wish to locate and right click on it, then select inspect with Firebug (example using Firebug, make sure you have it installed):

Locating webelements with Firebug

It will point exactly to the source code of this element, if you right click on this peace of code you should be able copy css or xpath.

- Meanwhile Firebug opened you can also locate element with finder, just activate it by clicking on it and hover over element you wish to inspect.

Locating webelements with Firebug

Now lets review locating elements by xpath, there is two types of xpath: minimal and absolute, you also can mix minimal with absolute(Firepath [Firefox plugin] used in examples below).

- Locating element on the page by minimal xpath:

@Test
public void locateByXpath() {
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.xpath("//*[@id='searchInput']")).sendKeys("Selenium");
driver.findElement(By.xpath("//input[@class='formBtn']")).click();
assertEquals(driver.getTitle().toString(), "Fail Selenium - Wikipedia, the free encyclopedia");
    }

On screenshot below firepath with generated xpath

Identifying Locating elements in Selenium WebDriver using xpathGenerating xpath with FirePath plugin for Firefox browser

- Locating element on the page by absolute xpath

@Test
public void locateByAbsoluteXpath(){
driver.navigate().to("http://wikipedia.org");

driver.findElement(By.xpath("//div[2]/form/fieldset/input[2]")).sendKeys("Selenium");
driver.findElement(By.xpath("//div[4]/form/input[4]")).click();
assertEquals(driver.getTitle().toString(), "Fail Selenium - Wikipedia, the free encyclopedia");
    }

On screenshot below firepath with generated absolute xpath

Generating absolute path with FirePath plugin for Firefox browser
Generating absolute path with FirePath plugin for Firefox browser

Locating element on the page by id

@Test
public void locateById() {
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.id("searchInput"));
    }
Generating CSS with FirePath plugin for Firefox browserGenerating css with FirePath plugin for Firefox browser

Locating element on the page by name

@Test
public void locateByName() {
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.name("search"));
    }

Locating element on the page by cssSelector

@Test
public void locateByCssSelector() {
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.cssSelector("#searchInput"));
    }

Locating element on the page by partialLinkText

@Test
public void locateByPartialLinkText() {
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.partialLinkText("your donation."));
    }

Locating element on the page by linkText

@Test
public void locateByLinkText() {
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.linkText("Some link text"));
    }

Locating element on the page by tagName

@Test
public void locateByTagName() {
driver.navigate().to("https://en.wikipedia.org/wiki/Selenium");
driver.findElement(By.tagName("td"));
    }

Locating element on the page by className

@Test
public void locateByClassName() {
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.className("formBtn"));
    }

Tips and Tricks

Locating element on the page by locating child Element css selector

@Test
public void locateChildElementByCssSelector() {
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.xpath("//*[@id='searchInput']")).sendKeys("Selenium");
driver.findElement(By.xpath("//input[@class='formBtn']")).click();
assertEquals(driver.getTitle().toString(), "Fail Selenium - Wikipedia, the free encyclopedia");

driver.findElement(By.cssSelector("#mw-content-text > table:nth-child(2) > tbody > tr:nth-child(2) > th"));
    }

Locating element on the page by xpath with containing text

@Test
public void locateElementContainsTextByXpath(){
driver.navigate().to("http://yahoo.com");
driver.findElement(By.xpath("//button[@type='submit' and contains(., 'Search')]"));
    }

or

@Test
public void locateElementContainsTextByXpath(){
driver.navigate().to("http://yahoo.com");
driver.findElement(By.xpath("//div[contains(text(), 'Search')]"));
    }

Locating element on the page by xpath, finding child element

@Test
public void locateParentChildXpath(){
driver.navigate().to("http://wikipedia.org");
// just an example not a real xpath
driver.findElement(By.xpath("//div[contains(@class,'x-grid3-row-first')]/parent::div/child::div[1]"));
    }

You can also find elements on the page using parts of the id, className etc, I got this idea from question asked on stackoverflow and clever answer in my opinion, Santiago Suarez Ordoñez explaining it in his presentation above, you can also go directly to original post on Sauce Labs.

A link with an id that starts with the text "id_prefix_"

@Test
public void locate_id_prefix_(){
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.cssSelector("input[id*='search']")).sendKeys("Selenium");
    }

You can do the same thing using XPATH:

@Test
public void locate_id_prefix_(){
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.xpath("//div[starts-with(@id,'search')]")).sendKeys("Selenium");
    }

A link with an "id" that ends with the text "_id_suffix"

@Test
public void locate_id_suffix(){
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.cssSelector("input[id$='Input']")).sendKeys("Selenium");
    }

And again here is the same thing in XPATH

@Test
public void locate_id_suffix(){
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.xpath("//div[ends-with(@id,'Input')]")).sendKeys("Selenium");
    }

A link with an "id" that contains the text "id_pattern"

@Test
public void locate_id_pattern(){
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.cssSelector("input[id*='chIn']")).sendKeys("Selenium");
    }

Same thing in XPATH:

@Test
public void locate_id_pattern(){
driver.navigate().to("http://wikipedia.org");
driver.findElement(By.cssSelector("//div[contains(@id,'chIn')]")).sendKeys("Selenium");
    }

Using xpath might be a problematic if browser support XPATH 1.0 and not supporting XPATH 2.0, in that case you can implement it yourself

As Santi mentioned in his presentation, it is good idea, to locate one element and then you can locate another element inside the one which been already identified, for example menu and submenu:

   public void  locateElmentInsideElement(){
        WebElement menu = driver.findElement(By.id(""));
        WebElement submenu = menu.findElement(By.id(""));
    }

One trick I'm using, even though some people can find it odd way, but it is been working for me for a while is "removing dynamic id from the source", the idea is tell to DOM finders go to look for some another anchor, cause the closest one does not exist anymore, here is how you do it.
- find element with dynamic id
- remove dynamic id from the source in your debugging tool
- right click on left part and copy your css or xpath

Tools

1. WebDriver Element Locator [Firefox plugin]

Locating Web Elements in Selenium WebDriver

2. Firepath [Firefox plugin]

Locating Web Elements in Selenium WebDriver
Locate Web Element in Selenium WebDriver using FirePath

3. Firebug [Firefox plugin]

4. FireFinder [Firefox plugin]

Locating Web Elements in Selenium WebDriver

5. Selenium IDE - you basically can record your steps and then save it in appropriate format it will generate locators. [Firefox plugin] 6. Selenium Page Object Generator [Chrome plugin]

Locating Web Elements in Selenium WebDriver

7. SelectorGadget [Chrome plugin]

Cheat Sheets by Michael Sorens

And here is short tutorial "Selenium Object Identification using CSS Path" presented by youtube user xTremeSelenium

update:

To verify XPATH in Chrome you can open Chrome console and type next:

$x("your_xpath_here")

And then click enter to see if you located element properly. See screenshot below.

How to verify xpath in Chrome

XPATH locating extra help:

- Following sibbling (select element on the same level as the anchor element)

//li[@id='x-menu-el-ctl00_ctl00_westZone_ctl40']/following-sibling::*

//li[@id='x-menu-el-ctl00_ctl00_westZone_ctl40']/following-sibling::li

- Decendant

//li[@id='x-menu-el-ctl00_ctl00_westZone_ctl40']/descendant::*

//li[@id='x-menu-el-ctl00_ctl00_westZone_ctl40']/descendant::li

//li[@id='x-menu-el-ctl00_ctl00_westZone_ctl40']/child::a

- Preceding

.//*[@id='ext-gen119']/preceding

.//*[@id='ext-gen119']/preceding-sibling::*

.//*[@id='ext-gen119']/preceding-sibling::div

- Get last element in a DOM three:

.//body/div[last()]//button[@type='button' and contains(., 'OK')]

- Find element with containing class:

.//div[contains(@class,'x-window-dlg')]//button[@type='button' and contains(., 'Yes')]
View Comments

Leave a Comment

Use markdown or basic HTML and be nice.