• Jobs
  • About
  • Locating page elements using WebDriver August 31, 2011

    Types of Locators

    Locators have changed with Selenium 2 with the WebDriver API. Out of the box WebDriver supports several ways to locate elements on the page using the By abstract class.

    Finding elements by ID

    ids are the preferred way to locate elements on a page for 2 main reasons:

    • According to w3c ids are supposed to be unique on an html page. This makes ids a very explicit and reliable way to locate elements on the page.
    • Also, all browsers also have highly efficient methods to get an object on the page using their ids. This makes id locators the fastest type of locator in Selenium.

    Let us now look at how to use id locators using this html code as an example:

    <form name="loginForm">
        Login Username: <input id="username" name="login" type="text" />
        Password: <input id="password" name="password" type="password" />
        <input name="login" type="submit" value="Login" />
    </form>
    

    In the above code, the username and password text fields are can be set using their ids. The locators for them would be

    driver.findElement(By.id(username));

    Even though this is a great locator, it is not realistic for all elements on a page to have ids. The developers add ids to key elements on the page to better control the look and feel or provide the dynamic user interaction. However, ids should also be added to elements that are frequently interacted within tests … to make the pages more testable. Automated test script authors should consider adding, or requesting addition of, ids to these key elements on the page.

    In some cases, the ids on an element cannot be reliably used in a test. For instance, if you are displaying objects stored in the database, the objects ids could contain the database id in it, for instance book1347 could be the id for book who’s database id is 1347. In such situations it may not be possible to predict and use the ids and so you may need to use other ways described below to find elements.

    Finding elements by name

    Generally ids are added to elements when they want to be referenced from css or javascript and names are added to form fields. When referencing element from javascript either can be used. From a test automation standpoint, whenever id is not available/ usable, you should try to use the name instead.

    Using the same example above, the way you would find the submit button would be:

    driver.findElement(By.name("login"));

    There is one big difference between the id and name attributes though … name attributes don’t have to be unique in a page. If there are multiple elements with the same name, then the first element in the page is selected. So, in this example, if another button or form named “login” was present of added later, it could cause the test to fail.

    Finding links by text

    This locator identifies links by the text in them. Let us look at an example:

     <html>
     <body>
        ...
        <a href="signin.html">Sign In</a> to modify your account details.
        ...
    </body>
    </html>
    

    To click this hyperlink using the anchor tag’s text, you can use the By.linkText() locator:

    driver.findElement(By.linkText("Sign In"));

    If there are multiple elements with text “Sign In”, the first one is selected.

    Btw, this is called linkText because it is used for hyperlinks. In Selenium if you used the link=textPattern locator, you could use it to locate other elements like div, span, td etc. In WebDriver, this locator works only for links.

    Another common case is when we need to find links by a portion of the text it contains. In such cases you can find it by specifying the partial text. For example:

    driver.findElement(By.partialLinkText("Sign"));

    Finding elements by XPath

    XPath is a very powerful language to express which element to identify. If you use it correctly, it can produce very reliable and low maintenance locators, but if you use it incorrectly, it can create very brittle test cases.

    Let us see some examples:

     <table name="cart">
        <tr id="item1">
            <td class="name item">Mp3 Download: foobar.mp3</td>
            <td class="name item"><input name="qty" class="name item formfield disabled" /></td>
        </tr>
        <tr id="item2">
            <td class="name item">Mp3 Player</td>
            <td class="name item"><input id="item2_quantity" name="qty" class="name item formfield required" type="text" /></td>
        </tr>
        ...
    </table>
    

    You can target the highlighted input field using the following XPath expressions:


    //table/tr[2]/td/input
    //input[@id='item2_quantity']
    (//table[@name='cart']//input)[2]
    //input[contains(@class,'required')]
    //input[contains(@class,'required') and type='text']

    And for the last option, your java call would look like:
    driver.findElement(By.xpath("//input[contains(@class='required') and type='text']"));

    As you can guess, some of these expressions will not be as reliable as others. Of these //table/tr[2]/td/input is the worst because it would break even with slightest modification to the page structure. It can take some time to learn XPath if you aren’t familiar with it, but it is worth the time if you plan to spend a lot of time writing UI automated tests. In any case do not rely on tools, including selenium IDE, to generate the right xpath expression for you. They can help you get started but they are usually bad at identifying the more reliable XPaths.

    XPath namespaces

    There are some special cases you should be aware of when you work with XPath, like when you are trying to interact with SVG. Like in the example here, the html looks something like this:

    <div id="svgchart">
      ...
        <svg xmlns="http://www.w3.org/2000/svg">
            <g>
                <path .../>
            </g>
            ...
        </svg>
      ...
    </div>
    

    Here, if you use XPath like:

    //svg

    you will get ERROR org.openqa.selenium.NoSuchElementException: Unable to locate element. This is because the svg element is in a different namespace. You will have to specify your xpath with the namespace uri like this instead:

    //*[local-name()='svg' and namespace-uri()='http://www.w3.org/2000/svg']

    XPath performance

    So, if XPath’s are so versatile, why doesn’t everyone prefer these? It’s because they are often the slowest, especially in older versions of IE! There are some ways you can make XPath’s faster, but they still are a few times slower than ids or names.

    Finding elements by CSS

    css locators can be used to identify a large number of elements on a page. Let us look at this html snippet for instance:

     <table name="cart">
        <tr id="item1">
            <td class="label">Mp3 Download: foobar.mp3</td>
            <td class="item"><input name="qty" class="formfield disabled" /></td>
        </tr>
        <tr id="item2">
            <td class="label">Mp3 Player</td>
            <td class="item"><input id="item2_quantity" name="qty" class="formfield required" type="text" /></td>
        </tr>
        ...
    </table>
    

    In this case the css locator variations possible for the highlighted input field are:


    input.required
    input[class~='required']
    input.required[type='text']
    #item2_quantity
    input#item2_quantity

    The css locator may not be as expressive as XPath, but it generally executes faster.

    Finding elements by class

    This is more of a convinience mechanism to identify elements. In the css example above, instead of using

    driver.findElements(By.css("input[class~='required']"));

    you could use

    driver.findElements(By.class("required"));

    Getting elements by DOM

    DOM stands for Document Object Model. DOM is convention for representing objects in HTML documents.

    <form id="loginForm">
        Login Username: <input id="username" name="username" type="text" />
        Password: <input name="password" type="password" />
        <input name="login" type="submit" value="Log in" />
    </form>
    

    In this page, the dom expression for the highlighted input field would be:


    document.forms[0].elements[0]
    document.forms['loginForm'].elements['username']
    document.forms['loginForm'].username
    document.getElementById('username')

    For those who have used Selenium 1 API, you would expect to find a By.dom() equivalent api, but it doesn’t exist. However, you still can get a handle to these elements using dom expressions by using the following code snippet instead:

    ...
        driver.findElement(byDom("document.forms[0].elements[0]"));
    ...
    
    public By byDom(String domExpression) {
        final Object o = ((JavascriptExecutor) driver).executeScript("return " + domExpression + ";");
    
        if (o instanceof WebElement) {
            return new By() {
                @Override
                public List<WebElement> findElements(SearchContext searchContext) {
                    return new ArrayList<WebElement>() {
                        {
                            add((WebElement) o);
                        }
                    };
                }
            };
        }
    }
    

    The three key aspects of this code that you should note,

    • The driver can be casted to JavascriptExecutor and other interfaces which will provide additional capabilities.
    • executeScript() in JavascriptExecutor returns an object which can be casted to a WebElement if the javascript expression returns a dom element.
    • You can create your own implementation of By

    Some things to note for Selenium 1 users

    • You will notice that Implicit locators are not supported in WebDriver.
    • When using name in Selenium 1, you could add other attributes in the expressions to filter the results. For example name=login type=text was valid. You cannot do that any more with the By.name() call.

    findElement() and findElements()

    As you might have noticed in the examples above, the By locators were used within findElement and findElements methods. The purpose of these methods is to return a WebElement, in case of findElement, and a list of WebElements in the case of findElements.

    The WebElement represents an html element on the page. In the next section you will see that it is this WebElement object that you would interact with or read attributes of for validations etc.

    When you use these methods on the WebDriver object, the scope within with the elements are located is the entire page.

    Getting child elements

    The WebElement interface also has findElement() and findElements() methods. In this case, it is within the scope of this parent element that child elements are located. This is useful when you want to narrow the scope to find several elements that you would interact with. In most cases, narrowing the scope improves the execution times for locating the elements.

    Posted by Rahul Poonekar in : Selenium

    38 Responses to “Locating page elements using WebDriver”

    1. PeterK says:

      Hi,

      I was wondering when “Interacting with page elements” will be published.
      This is the fist location I’ve found that actually explains things properly.

      I’ve been trying to understand how findElements() works and I’m hoping this section will do it.

      Tx
      Peter

    2. Rahul Poonekar says:

      Thanks for your comment. I am hoping to publish it in the next few days.

    3. Pallavi says:

      Very precise and informative, I found this really helpful,
      waiting for the next article.

      Thanks,
      Pallavi

    4. Rahul Poonekar says:

      Thanks Pallavi. I added the Interacting with html page elements using WebDriver recently. Feedback is appreciated!

    5. Sue says:

      Really help me a lot…appreciated!

    6. Bharath Madishetti says:

      I am novice to WEBDRIVER…Thanks alot… It helped me a lot on how to user WEBDRIVER to identifying the objects..

    7. Dharaneesha says:

      It’s really a great job and I learnt a lot of things about SELENIUM from this document. Thanks a lot

    8. Dharaneesh says:

      Hi, Could you please help me with the Selenium wait commands instead of using Thread.sleep(2000)? I tried in so many ways in order to achieve it, but it was not successful. I hope i will get the solution for this.

    9. Reena says:

      Awesome documentation . Great job Rahul .i could learn many new things

      am looking forward for any help , to locate svg elements .I have searched in many forums but found no solution . Could you kindly help me
      ?
      I use python with Selenium
      I have tried elem = self.browser.find_element_by_xpath(“//svg[@class='sap-piechart']/path[@title='Handhelds : 1']“)
      but element not found.I need to click on each element within the tag with different title

    10. Reena says:

      HTML code looks like this

      <div id="pie4" class="left-top sp-workareaitem-content sap-chart" data-color="blue" data-charttype="pie" data-dimension="CATEGORY" data-title="CATEGORY-PIE" data-sap-widget="chart" style="display: block;">
      <svg class="sap-piechart" width="82" height="82">
      <g>
      <path style="pointer-events: all;" transform="translate(41, 41)" fill="rgb(120,160,200)" title="Others : 13" d="M2.38499964133947e-15,-38.949999999999996A38.949999999999996,38.949999999999996 0 0,1 37.793018538450056,9.422857833607061L19.89106238865793,4.959398859793191A20.5,20.5 0 0,0 1.255262969126037e-15,-20.5Z">
      <path style="pointer-events: all;" transform="translate(41, 41)" fill="rgb(81,122,162)" title="Products: 12"  d=........>
      <path style="pointer-events: all;" transform="translate(41, 41)" fill="rgb(81,122,162)" title="Steel: 13 " : d=........>
      <g>
      <svg>
      <div>
      
    11. MC says:

      One of the best articles on XPATH I’ve come across.

      Very helpful.

      Thank you.

    12. Scott Sims says:

      You should rename ‘Finding elements by text’ to ‘Finding links by text’. I was searching to find elements by text but this does not work unless it is a link. I am trying to click an item in a java script drop down menu without specific id. So I can’t use link text to locate it because it is a . I usually us a css contains “li:contains(‘my text’)” but that does not seem to work anymore.

    13. Mat says:

      Awesome, you have the best tutorials. Very beginner-friendly, much appreciated.

    14. Rahul Poonekar says:

      Thanks Scott. I modified the post to say find links by text and not find elements by text. I can’t say with certainty, but, I think it might have even located elements that were not links when I was trying Selenium-WebDriver when it was in beta.

      The li:contains('my partial text') works if you use the Sizzle js library. You can always inject that library with WebDriver and then use that syntax.

    15. Vikrant Rana says:

      Nice tutorial,As a beginner quite helpful for me!

    16. xianglong says:

      Hi Rahul,
      thanks a lot for your article
      but I ‘m very confused findElement(); and findElements();
      it’s easy to understand findElement();
      but how to use findElements(); or what can findElements(); do ?
      eg:

      Mp3 Download: foobar.mp3

      Mp3 Player

      when I use findElements(BY.name(‘cart’));
      it will return a list that contains what ? children notes of this table ?

    17. xianglong says:

      god…
      my example was not published successful…

      please refer the css locator section of your article

      sorry for this inconvenience

    18. yedukondalu says:

      I am trying to select a radio button which is within a browser
      I’m using

      driver.FindElement(By.CssSelector(“//*[@id='Dealer']“)).Click();
      so
      Please help me in selecting the radio button.

    19. Raj says:

      Hey yedukondalu,

      driver.FindElement(By.xpath(“//*[@id='Dealer']“)).Click();
      driver.FindElement(By.CssSelector(“*[id='Dealer']“)).Click();
      driver.FindElement(By.id(“Dealer“)).Click();

      you can use any one of these

    20. Nick Halden says:

      You mentioned that when using By.linkText() selenium will select the element for the first time the link appears. Is there an easy way to have it select the second time the link appears?

    21. GiRi says:

      Hi All,
      I am trying automate a mail-engine..

      Able to locate all the fields except the area where we write the mail content…tried using By.* :(
      could u assist..
      Regards
      GiRi

    22. GiRi says:

      to be more precise…I am trying automate compose a mail…

      Able to locate : to, subject ,send etc…But not able to locate the composing area /text area
      Regards
      GiRi

    23. yedukondalu says:

      Hi Raj,

      I am using selenium webdriver with in java application but I am tring click on radio buttons with in a chrome browser then doe’s not selecting radio button. so please help me.
      My test case is:-
      Browser.findElement(By.id(“type”).click;

    24. arthi says:

      greatly helpful!!!thanks!!!

    25. Abdul says:

      Very nice article to understand how webdriver interact with web elements

    26. Igor says:

      Hi there!

      In Telerik it’s possible to search elements within an element that was already found. E.g. I found a , that has some elements. After that I can invoke find() directly from the element.

      Is there such possibility using the WebDriver?

    27. jitendra says:

      awesome information ……

    28. Ganesh says:

      Hi, I am not using Webdriver API, but directly controlling Selenium RC using PERL.

      a) Let us say I was able to invoke google.com using Perl, how do I use $Locator and Click($Locator) commands to actually clock on “Sign In ” button of Google.

      b) Sometimes webpages have two data entry fields.
      How do I type into a particulat data entry field again using Locator and type($locator,$value) commands

      Can somebody kindly give examples for these ?

      c) How do I install and use Webdriver API on top of Selenium RC ?

    29. Zain says:

      Hi i am having problem to click on a element on javascript. In HTML ID for that element is not given only Class Name is mention. I am using following code

      public static void JseClickById(String selector, IJavaScriptExecutor JSE)
      {
      if(selector==PROFILE_WINDOWCLOSE_Xpath)
      {
      //JSE.ExecuteScript(“document.getElementByxpath(‘” + selector + “‘).click();”);
      // JSE.ExecuteScript(“$(arguments[0].click()”, selector);
      Driver.FindElement(By.XPath(“//a[contains(@class,'selector')]“)).Click();
      }
      else
      {
      JSE.ExecuteScript(“window.document.getElementById(‘” + selector + “‘).click();”);
      }
      }

      Can anybody help me with this. How to use Xpath or Class name in the string which i am giving to ExecuteScript??

      Thanks in Advance

    30. pureshore says:

      Very helpful!

    31. eshwar says:

      suppose iam writing for email field my css will be
      findElement(By.cssSelector(“input[value="#EmailID"]“).getText(“eshwar@gmail.com”)……

      is it correct

    32. Dhananjay says:

      Hi Rahul,
      I am facing lot of problems related to XPath. Can you please let me know any good site, book…etc to learn XPath.

    33. Basant says:

      Hi,

      Its good to understand the identifier. But i’m not able to find and handle a object identity. Can someone help me- See, there is a movie web apps and its dynamic contents .. There are three fields – Region, Movie and Date. all are drop down and after selecting region Movie fields are enable then Date will be enable. each week movie has changed and date is changing. when we search movie then getting show time in result. But some time some cinemas is not there and sometimes movie is not in that specified region or cinema.

      SO how can we handle this condition ?

    34. sagar says:

      hi,

      why cant we just use selece scripts instesd of exporting/generating the test scripts in java,php or html

      i think selence scripts are easy and less complex

      example:

      type //td[@id='first_name-bodyEl']/input sa
      type //td[@id='last_name-bodyEl']/input khanna

      clickAt //div[2]/table[2]/tbody/tr/td[2]/table/tbody/tr/td[2]/div

      verifyText//li[3] Supplies Office

      click //li[3]

      type //td[@id='item_name-bodyEl']/input richa

      click //table[5]/tbody/tr/td[2]/table/tbody/tr/td[2]/div

      verifyText //li[7] Kids Accessories

      click //li[7]

      click //table[6]/tbody/tr/td[2]/table/tbody/tr/td[2]/div

      verifyText //tr[4]/td/a/em/span 20
      click //tr[4]/td/a
      click //div[11]/div[3]/div/div/div/em/button

    35. Srilu says:

      Hi,
      I am using python script and facing issue with Elements which have same name which have different Xpath.
      Can some one help me.
      To give you more idea.. am finding elements from a table view and entering data into text boxes.

      So I have text boxes with name labels like Country and state, which indeed have different Xpath.

      When i use find_element_by_name and send data its works fine for the first element but not next element.

    36. Vinay says:

      Is CSS locator possible for this xpath:
      driver.findElement(By.xpath(“//span[contains(text(), 'Submit')]“)).click();
      “Submit” is the text on button.
      Please help it’s urgent.

    37. Geethanjali says:

      If two elements have the same attributes and same values,which method is prefered to locate the element.Please give example

    38. Niharika says:

      Hi ,

      I have multiple clickable option in div tag while on on clickable option I ma not able to move to another clickable tab.I am using Findby (xapth ) but its throwing the exception by saying Nosuchelement found exception.

    Leave a Reply