Part 1: Working with Element Locators…

This is one of the biggest topic in Selenium Automation. Selenium Automation scripts executes by identifying the correct elements or objects (like textboxes, buttons, dropdowns etc.) in a web page and then by performing actions (like click, enter etc.) to them. If you are able to identify the elements preciously in a web page then your scripts becomes dependable and when executed they will be able to identify any changes to the captured elements.

There are numerous ways to identify the elements correctly. Not one method is better than the other as all these methods helps us in identifying the correct element.

Locating By ID:

Most of the elements in a web page have IDs but its always not necessary. Using IDs we can easily identify the elements in the web page as they are supposed to be unique.

If you refer to our last automation script that we created, there is a set of code that we used to identify the text box and search icon in Google website.

/*Find the Web Element Search Text Box. After finding the Web Element, enter the word "selenium"into the text box*/
driver.findElement(By.id("lst-ib")).sendKeys("selenium");

//Find the Web Element Search icon. After finding, click the search icon driver.findElement(By.id("_fZl")).click();

While referring to the above code you can see that we have used the text box ID as “lst-ib” and search icon ID as “_fZl” to identify the text box and search icon in the Google webpage.

While script creation, you can open the web page in any of the browsers and right click on the element and select ‘Inspect Element’. This will allow you to view the HTML code. From here you can get the ID attribute of the element. as mentioned its not necessary for the ID to be available. If its not there, then we have to look for other methods to identify the element.

Screen Shot 2017-02-22 at 1.09.07 PM.png
ID = “lst-ib”

Locating By Name:

Like the ID attribute, name attribute can also be used for element identification. Names are unique most of the times, but it’s not always necessary. If not unique then it will identify the first element with the name attribute. Name locators are good to use for Forms having uniques name attributes.

//Code Sample for name locator
driver.findElement(By.name("q"));

Here for the Google text box, instead of ID, we can also use name attribute for element identification. The code will successfully identify the text box only if there is one name attribute with value ‘q‘.

Locating By Class Name:

You can locate a web element using class name also. Like the IDs, class name is also an attribute that can be present inside different html tags. Like in the above screenshot for the Google text box, there is an attribute class=”gsfi” also present along with ID and name attributes. We can use the below code sample to identify web elements using class names.

//Code Sample for name locator
driver.findElement(By.className("gsfi"));

The only problem with class names is that they are not unique like IDs. Same class names can be used for multiple web elements as a result it very hard to locate a web element using class names only.

Locating By Link Text:

Link Text locators are applicable to hyperlink texts. Its used to locate the text inside anchor tags in html. Like in our last script, after clicking the search icon, Google displays list of website links. Our scripts searches for the link which has a text “Selenium – Web Browser Automation”. Of course it finds the link and clicks on it but how did it identify?

Screen Shot 2017-02-23 at 4.57.06 PM.png
Link Text “Selenium – Web Browser A…”

We can use the below code sample to identify web elements using Link Text.

//Find the first link displayed using the link text and click the link
driver.findElement(By.linkText("Selenium - Web Browser Automation")).click();

Link Text is best to identify the hyperlinks in web page.

Locating By Partial Link Text:

Partial Link Text is almost same as Link Text. The only difference is that you don’t have to mention complete text in order to find the hyperlink. You can just mention partial text. However you need to make sure that the partial text is unique otherwise it will locate the first element from the list. We can use the below code sample to identify web elements using Link Text.

//Find the first link displayed using the link text and click the link
driver.findElement(By.partialLinkText("Selenium - ")).click();

Locating By Tag Name:

Tag Name can also be used in identifying the web elements. However finding web elements using Tag Names aren’t much popular as there are better methods to identify the elements. Like for example if the web page has only one drop down, you can use the Tag Name to locate the html tag “select”. We can use the below code sample to identify web elements using Tag Name.

//Find the first link displayed using the link text and click the link
driver.findElement(By.tagName("select"));

Locating By CSS Selector:

CSS Selector is one of the faster ways to identify a web element. There are different ways by which we can use the the CSS Selectors to locate a web element. Lets take multiple instances of Google text box. We will use CSS Selector in multiple ways to locate the text box. Refer the screenshot for easy understanding.

screen-shot-2017-02-23-at-5-59-19-pm
input tag of Google text box

Using ID only:

//css selectors using ID
driver.findElement(By.cssSelector("input#lst-ib")).sendKeys("selenium");

Please note for ID attribute we need to use ‘#’

Using Class Name only:

//css selectors using class name
driver.findElement(By.cssSelector("input.gsfi")).sendKeys("selenium");

Please note for class name attribute we need to use ‘.’

Using any one of the attributes:

//css selectors using name attribute
driver.findElement(By.cssSelector("input[name='q']")).sendKeys("selenium");

Please note that for any attributes we can use the above code in the format “element_name[<attribute_name>=‘value’]”. Like the name attribute there are other attributes present in the ‘input‘ tag which we can use to find the text box.

Using more that one attribute:

//css selectors using more than one attributes
driver.findElement(By.cssSelector("input[name='q'][role='combobox']")).sendKeys("selenium");

Please note if we need to use more than one attributes to identify a web element, we can use the above code in the format “element_name[<attribute_name>=‘value’][<attribute_name>=‘value’]”. 

Using parent child relationship:

//css selectors parent child relationship
driver.findElement(By.cssSelector("div#gs_lc0 input#lst-ib")).sendKeys("selenium");

As mentioned, ‘#‘ refers to ID in CSS Selector. Please note that the same code can be written using other attributes:

//css selectors parent child relationship
driver.findElement(By.cssSelector("div[id='gs_lc0'] input[name='q']")).sendKeys("selenium");

If we need to access to an element inside the unordered list (inside the ul tag), we can use the following example.

screen-shot-2017-02-24-at-9-46-50-am
Selenium web site with tabs under unordered list (ul)

We can identify any of the listed item (li tag) inside the unordered list (ul) using the “nth-of-type” in the CSS Selector.

//css selector for clicking the first listed item in unordered list
driver.findElement(By.cssSelector("ul li:nth-of-type(1)")).click();

Using css selectors for random attributes:

Sometimes attributes like IDs are not constant. They keep on changing with every session.  Like the case of below screenshot where you can notice the value of ID is a combination of alphanumerical. Sometimes the numerical value changes with each session. In that case we can consider only partial value of an attribute.

Screen Shot 2017-02-24 at 11.09.49 AM.png
IDs are not constant

For random attributes, we can use different ways like ‘starts with’, ‘ends with’, ‘contains’ in the CSS Selector to identify the web element. Let’s assume the attribute values of the ‘Sign in’ button in the above screenshot keeps changing with every new session. We will use different methods to identify the ‘Sign in’ button.

//css selector where id starts with 'uh-sign'
driver.findElement(By.cssSelector("a[id^='uh-sign']")).click();

Please note we have to use ‘^=‘ for attributes ‘start with’

//css selector where id ends with 'signin'
driver.findElement(By.cssSelector("a[id$='id$='signin']")).click();

Please note we have to use ‘$=‘ for attributes ‘ends with’

//css selector where id has sub string or contains 'h-sign'
driver.findElement(By.cssSelector("a[id*='h-sign']")).click();

Please note we have to use ‘*=‘ for attributes ‘sub string’

Above were the most commonly used CSS Selectors, however you can still play around with CSS Selectors for identifying the elements. Please visit the below URL for more information:

CSS Selectors

Locating By XPath:

XPath locator is one of the most used locators for finding elements in a web page. XPath is defined as XML Path and it locates an element by traversing between various elements across the entire page and thus finding the desired element with reference to another elements. There are many free plugins available for the browsers using which we can get an XPath of an element. ‘Firebug’ and ‘Firepath’ are most commonly used add ons for Firefox browser and ‘XPath Helper’ for Chrome browser. Here I will be using the add ons from Firefox browser to view the XPath.

There are two types of XPaths:

Absolute XPath:

Absolute XPath begins from the root path with a single forward slash(/) and followed by complete path of the web element. For example in Google web page, the Absolute XPath for the text box is ‘html/body/div/div[3]/form/div[2]/div[2]/div[1]/div[1]/div[3]/div/div/div[3]/div/input[1]’

screen-shot-2017-02-25-at-11-50-36-am
FirePath add-on in Firefox browser

As you see Absolute XPath is the complete path starting from the root of the web page to the actual element. The code for Absolute XPath will be:

//Absolute XPath for the text box
driver.findElement(By.xpath("/html/body/div/div[3]/form/div[2]/div[2]/div[1]/div[1]/div[3]/div/div/div[3]/div/input[1]")).sendKeys("selenium");

However there is one big disadvantage in using Absolute XPath locators. There is a high possibility of failure even if small changes are made to the reference elements. Due to this sole reason Absolute XPaths are seldom used.

Relative XPath:

Relative XPath starts from the middle of the HTML DOM structure. Its start with the double forward slash (//), which means it can search the element anywhere at the web page. For example the same Google text box can have the Relative XPath as displayed below:

Screen Shot 2017-02-25 at 12.31.18 PM.png
FirePath add on to find Relative XPath

The code for Relative XPath will be:

//Relative XPath for the text box
driver.findElement(By.xpath(".//*[@id='lst-ib']")).sendKeys("selenium");

As you can see Relative XPath does not uses the complete path, rather it starts in the middle of the web page. ‘.//*[@id=’lst-ib’]‘ means to search for the ID relative to the current node reference.

The same XPath code can be written in a much better way:

//Relative XPath for the text box
driver.findElement(By.xpath("//input[@id='lst-ib']")).sendKeys("selenium");

You can use any of the attributes of the element in this code but make sure to use ‘@‘ in front of the attribute. By replacing ‘*‘ with ‘input‘ tag, we are specifically instructing the driver to search for the ID in ‘input‘ tag only otherwise it will look for the ID in all tags.

Some more examples for identifying Google text box using Relative XPath:

Screen Shot 2017-02-26 at 11.32.18 AM.png
XPath for Google text box
//Xpath of text box with Class attribute
driver.findElement(By.xpath("//input[@class='gsfi']")).sendKeys("selenium");

//Xpath of text box with Name attribute
driver.findElement(By.xpath("//input[@name='q']")).sendKeys("selenium");

Relative XPath using contains():

When the partial value of an attribute is dynamic, we can use contains() method in Relative XPath to locate the web element. The same code for identifying the Google text box can be written using contains() method:

//Xpath of text box with Class attribute using contains() method
driver.findElement(By.xpath("//input[contains(@class,'gsfi')]")).sendKeys("selenium");

//Xpath of text box with Name attribute using contains() method
driver.findElement(By.xpath("//input[contains(@name,'q')]")).sendKeys("selenium");

Please note that we need to be careful when using the contains() method as it will try to locate all elements which contains the value that we mentioned in the code.

We can also use the contains() method to locate an element using text.

Screen Shot 2017-02-26 at 12.14.46 PM.png
XPath locator for Sign in

In the above screenshot of Yahoo web site, we can locate the text ‘Sign in’ using contains() method.

//XPath of Sign in button using contains() method 
//Locating using text
driver.findElement(By.xpath("//a[contains(text(),'Sign')]"));

Relative XPath using starts-with():

Like contains() method, starts-with() method can be used for elements with dynamic values. The same code for locating the Sign in button in Yahoo web site can be written using starts-with() method:

//XPath of Sign in button using starts-with() method 
//Locating using ID
driver.findElement(By.xpath("//a[starts-with(@id,'uh-sign')]"));

Similar to contains() method, starts-with() method can be used for other attributes and text(). The same code can be written locating the web element using text():

//XPath of Sign in button using starts-with() method 
//Locating using text
driver.findElement(By.xpath("//a[starts-with(text(),'Sign')]"));

Relative XPath using OR & AND:

OR expression can be used when any one or all conditions are met. The same code for Sign in can be written as:

//XPath of Sign in button using OR conditions 
driver.findElement(By.xpath("//a[@id='uh-signin' OR @class='xxx']"));

In the above case the driver successfully locates the Sign in button as one of the condition is met.

The same code fails when we use AND expression as there is no class attribute in anchor tag with value ‘xxx’

//XPath of Sign in button using AND conditions 
//Code fails to locate the Sign in button
driver.findElement(By.xpath("//a[@id='uh-signin' AND @class='xxx']"));

Relative XPath using axes methods:

Sometimes when locating a web element becomes extremely difficult when they don’t have any fixed attributes. In that case we can use the help of different axes methods to navigate to correct element.

  1. Following method can be best explained by this example:
Screen Shot 2017-02-26 at 3.08.53 PM.png
XPath locator using following

In this example we are first locating ‘input‘ tag with ‘id=lst-ib’ and then using this as reference we will list out all ‘input‘ tags following the first located ‘input‘ tag. Always remember that following will list out all tags. However in this case you can locate a specific ‘input‘ by adding an index. Code sample for following:

//XPath Locator using following method
driver.findElement(By.xpath("//input[@id='lst-ib']/following::input[1]"));

Here we are first locating the ‘input‘ tag with ‘id=lst-ib’ and then using this ‘input‘ tag as reference, locate all other ‘input‘ tags in downward direction using following command. And then navigating to first ‘input‘ tag using ‘[1]‘ in our code.

2. Preceding works the same way. Only difference, instead of navigating in forward direction it travels in reverse direction. The code using Preceding can be written as:

//XPath Locator using preceding method
driver.findElement(By.xpath("//input[@id='gs_htif0']/preceding::input[1]"));

In the above example we are first locating the ‘input‘ tag with ‘id=gs_htif0’ and then using this ‘input‘ tag as reference, locate all ‘input‘ tags in upward direction using preceding command. And then navigating to first ‘input‘ tag using ‘[1]‘ in our code.

3. The ancestor axis selects all ancestors element (grandparent, parent, etc.) of the current node as displayed below:

Screen Shot 2017-02-26 at 1.52.24 PM.png
XPath locator using ancestor

In the above example, we are first locating one child ‘div‘ tag using ‘id=mega-bottombar’ and then using it as reference, locate all the ‘div‘ ancestors for the ‘div‘ tag.

Code sample for the ancestor method:

//XPath using ancestor method
driver.findElement(By.xpath("//div[@id='mega-bottombar']/ancestor::div"));

 

4. The Child axis works similarly as ancestor method but in the opposite direction.

screen-shot-2017-02-26-at-2-04-17-pm
XPath using child

In the above example we are first locating the ancestor ‘div‘ with ‘id=mega-uh-wrapper’and then using it as a reference, list out all the child ‘div‘ tags. Code sample for this example:

//XPath using child method
driver.findElement(By.xpath("//div[@id='mega-uh-wrapper']/child::div"));

 

5. Following-sibling method is used to identify all the siblings at the same level of the current node.

Screen Shot 2017-02-26 at 2.22.07 PM.png
XPath using following-sibling

In this example we are first locating the ‘div‘ element with ‘id=mega-topbar’ and then using it as reference, locate all other ‘div‘ tags which are siblings and are following to the located ‘div‘ tag. Code sample for this example:

//XPath using following-sibling method
driver.findElement(By.xpath("//div[@id='mega-topbar']/following-sibling::div"));

 

6. Preceding-sibling just works in the opposite direction of following-sibling. Instead of moving into forward direction, it moves in a reverse direction.

Screen Shot 2017-02-26 at 2.42.59 PM.png
XPath using preceding-sibling

In this example we are first locating the ‘div‘ tag with ‘id=mega-bottombar’ and then using it as reference, locate all other ‘div‘ tags which are siblings and are preceding to the located ‘div‘. Code sample for this example:

//XPath using preceding-sibling method
driver.findElement(By.xpath("//div[@id='mega-bottombar']/preceding-sibling::div"));

 

7. Using parent method we can locate the parent of the current node.

screen-shot-2017-02-26-at-3-28-37-pm

 In this example we are first locating the ‘div‘ tag with ‘id=mega-bottombar’ and then using it as reference, locate the parent ‘div‘ tag with ‘id=mega-uh-wrapper‘. Code sample for this example:

//XPath using parent method
driver.findElement(By.xpath("//div[@id='mega-bottombar']/parent::div"));

 

8. Using descendant method we can select all the descendants of the current node.

Screen Shot 2017-02-26 at 4.02.29 PM.png
XPath locator using descendant

In this example we are first locating the ‘td‘ tag with ‘id=yui_3_18_0_4_1488151541532_940’ and then using it as reference, list out all the descendants having ‘input‘ tags. Code sample for this example:

//XPath using parent method
driver.findElement(By.xpath("//td[@id='yui_3_18_0_4_1488151541532_940']/descendant::input"));

 

With this we came to an end to the first part of Element Locators. Although the topic was lengthy, its also an important one. I would suggest to try out each of the Element Locator in Eclipse so that you can clearly understand the way Selenium identifies the elements in a web page.

Additional Note:

What is the difference between following and following-sibling?

The below two links will help you understand the difference between following and following-sibling.

Following axis

Following-sibling axis