Most Underrated WebDriver Locator – XPath

WebDriver
39 Shares
Most Underrated WebDriver Locator - XPath

One of the most underrated locators in Selenium WebDriver or any other Web Automation Framework is the XPath locator. Most probably people don’t use XPath because they think that it’s too hard to learn or write. Earlier generating XPath used to be a tedious task but now with the help of Chrome Developer Tools, Firebug and other tools, it became hell easy.
If you are not familiar with Selenium WebDriver, I suggest you to read my previous post Getting Started with WebDriver C# in 10 Minutes. Here I will show you how you can use the full power of the XPath Locators to find the hardest to locate elements.

What Is XPath?

  • XPath is a syntax for defining parts of an XML document.
  • XPath uses path expressions to navigate in XML documents.
  • XPath contains a library of standard functions.
  • XPath is a major element in XSLT.
  • XPath is a W3C Recommendation.

XPath Expressions

<?xml version=1.0 encoding=UTF-8?>
<bookstore>
<book>
<title lang=en>Harry Potter</title>
<price>29.99</price>
</book>
<book>
<title lang=en>Learning XML</title>
<price>39.95</price>
</book>
</bookstore>
  • /bookstore/book[1] – Selects the first book element that is the child of the bookstore element.
  • /bookstore/book[last()] – Selects the last book element that is the child of the bookstore element
  • /bookstore/book[last()-1] – Selects the last – 1 book element that is the child of the bookstore element
  • /bookstore/book[position()<3] – Selects the first two book elements that are children of the bookstore element
  • //title[@lang] – Selects the lang attribute of the current node
  • /bookstore/book[price>35.00] – Selects all the book elements of the bookstore element that have a price element with a value greater than 35.00
  • /bookstore/book[price>35.00]/title – Selects all the title elements of the book elements of the bookstore element that have a price element with a value greater than 35.00

XPath Axes

axisname::nodetest[predicate]
  • ancestor – Selects all ancestors (parent, grandparent, etc.).
  • descendant – Selects all descendants (children, grandchildren, etc.).
  • following-sibling – Selects all siblings after the current node.
  • preceding-sibling – Selects all siblings before the current node.
  • child – Selects all children of the current node.
  • parent – Selects the parent of the current node.
  • attribute – Selects all attributes of the current node.

To demonstrate the power of the XPath Axes, I’m going to use the following page: http://sharepoint.telerik.com/aspnet-ajax/web-parts/Pages/Single-List-Binding.aspx
XPath Axes Chrome
We want to locate the td element with Book Author for the book with id = 17. You can open Chrome Developer Tools via the F12 key. When you hit CTRL + F, the search form, marked with yellow on the image above, will be displayed. There you can test your XPath expressions. In order to find the book author we can use the following expression: “//td[contains(text(),’17’)]/following-sibling::td[2]“. Which means, find the second td element that is below the td that contains the text “17“.
Also, another very useful and oftenly used XPath expression: “//div[contains(id(),’myElementPartId’)]”.  You can use it to locate elements which have dynamically generated IDs.

WebDriver XPath Example

I will use the following page for my next example: http://www.tutorialspoint.com/html/html_tables.htm
WebDriver XPath Example
In the test below, we want to find the name of the man with a salary that is equal to 5000.

[TestClass]
public class XpathExpressions
{
private IWebDriver _driver;
[TestInitialize]
public void SetupTest()
{
_driver = new FirefoxDriver();
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(30);
}
[TestCleanup]
public void TeardownTest()
{
_driver.Quit();
}
[TestMethod]
public void Find_Column_Table_XPath()
{
_driver.Navigate().GoToUrl(@”http://www.tutorialspoint.com/html/html_tables.htm”);
var element = _driver.FindElement(By.XPath(//td[contains(text(), ‘5000’)]/preceding-sibling::td[1]));
Assert.AreEqual(Ramesh Raman, element.Text);
}
}
In the TestInitialize method, we initialize the WebDriver instance and set the implicit wait timeout so that we will wait until the elements are displayed. This way we will be sure that the page is completely loaded. Then we use complex XPath Axes Expression to find the desired part and lastly assert the inner text of the searched td element.
You can find more details and examples about XPath syntax on the following page or this one.
  • Saad

    I heard that same Xpath does not work on every browser. In place of Xpath, people prefer to use CSS selectors…? Is it true?

    • Thank you for commenting!

      I heard that some people prefer CSS selectors over XPath. However, I have run all my tests in all major browsers, and similar XPath selectors are working as expected. Is this answering your question?

      • Saad

        Thats good to hear. The main reason people describe is that css selectors are faster than Xpath. as Xpath search the element top to bottom as well as bottom to top while css selectors are one way only. So they are much faster.
        I have also written an article on CSS selectors. Please visit and share your feedback.

        http://binaryclips.com/2015/02/16/css-selectors-for-selenium-webdriver/

        • Thank you. I have just subscribed for your blog. I will check the article tonight. I will also include any relevant new articles in my weekly best articles roundup Compelling Sunday. You can also, subscribe to Automate The Planet to receive any new articles to your mailbox. :)

  • Nicholas

    Hi, great article.

    You mention an Xpath expression, ’myElementPartId’ which lets you locate dynamically generated ID’s. I can’t locate this expression anywhere else on the internet.
    Can you please provide more detail or a link where I can read how to use it?
    Thanks very much!

    • Hi, Nicholas,

      You need to replace ‘myElementPartId’ with the part of the ID of the element you try to locate in the “//div[contains(id(),’myElementPartId’)]” expression.