Selenium Testing Tools Cookbook

5 (1 reviews total)
By Unmesh Gundecha
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Locating Elements

About this book

Web technologies are becoming increasingly complex and there is a need to test your web applications against a vast number of browsers and platforms, so you need to build highly reliable and maintainable test automation. This book will help you test your web applications effectively and efficiently with Selenium WebDriver.

"Selenium Testing Tools Cookbook" is an incremental guide that will help you learn and use advanced features of Selenium WebDriver API in various situations for building reliable test automation. You will learn how to effectively use features of Selenium using simple and detailed examples. This book will also teach you best practices, design patterns, and how to extend Selenium.

"Selenium Testing Tools Cookbook" shows developers and testers who already use Selenium, how to go to the next step and build a highly maintainable and reliable test framework using advanced features of the tool.

The book starts with tips on advanced location strategy and effective use of Selenium WebDriver API. Then it demonstrates the use of design patterns such as Data Driven Tests and PageFactory for building maintainable test automation.

It also explains extending Selenium WebDriver API along with implementing custom tasks and setting up your own distributed environment to run tests in parallel.

It concludes with tips on integrating Selenium WebDriver with other popular tools, testing mobile web applications, and capturing videos of test runs. This books provides examples in Java, C#, Ruby, and Python.

"Selenium Testing Tools Cookbook" will help you in building a highly robust and maintainable test automation framework from start to finish.

Publication date:
November 2012
Publisher
Packt
Pages
326
ISBN
9781849515740

 

Chapter 1. Locating Elements

In this chapter, we will cover:

  • Using browser tools for inspecting elements and page structure

  • Locating an element using the findElement method

  • Locating elements using findElements method

  • Locating links

  • Locating elements by tag name

  • Locating elements using CSS selectors

  • Locating elements using XPath

  • Locating elements using text

  • Locating elements using advanced CSS selectors

  • Using jQuery selectors

  • Locating table rows and cells

  • Locating child elements in a table

 

Introduction


The success of automated GUI (Graphical User Interface) tests depends on identifying and locating GUI elements from the application under test and then performing operations and verifications on these elements to achieve the test flow. This boils down to the test tool's ability to recognize various GUI elements effectively.

Selenium WebDriver provides one of the advanced techniques for locating elements on web pages. Selenium's feature-rich API provides multiple locator strategies such as Name, ID, CSS selectors, XPath, and so on. We can also implement custom locator strategies for locating elements.

In this chapter, we will explore more on how to use locator strategies by starting with ID, Name, and Class.

In any web development project, it is always a good practice to assign attributes such as Name, IDs, or Class to GUI elements. This makes the application more testable and conforms to accessibility standards. However, following these practices is not always possible. For such scenarios, we have to use advanced locator strategies such as CSS selector and XPath.

While CSS selector and XPath are popular among Selenium users, CSS selector is highly recommended over XPath due to its simplicity, speed, and performance.

 

Using browser tools for inspecting elements and page structure


Before we start exploring locators, we need to analyze the page and elements to understand how these are structured in the application, what properties or attributes are defined for the elements, how JavaScript or AJAX calls are made from the application, and so on.

Browsers render visual elements of the application for end users by hiding the HTML code and other resources. When we want to automate interaction with the application using Selenium WebDriver, we need to look carefully at the background code written to render pages and elements in browsers. We need to identify information such as attribute values and elements structure for locating elements and perform user actions using Selenium WebDriver API.

Here is an example of a BMI Calculator application page and HTML code written to render this page in a browser as displayed in the following screenshots:

You can view the code written for a page by right-clicking in the browser window and selecting the View Page Source option from the pop-up menu. This will display the HTML code of the page in a separate window. This might look messy and difficult to understand.

We need special tools that can display this information in a structured and easy to understand format. In this recipe we will briefly explore few of these tools before we dive into locators.

How to do it...

In the following sections we will explore some of the tools which are in-built in browsers and plugins to analyze elements and page structure. These tools will help us to understand how elements and their attributes are defined on a page, DOM structure, JavaScript calls, CSS Style attributes, and so on.

Inspecting pages and elements with Firefox using Firebug add-in

The newer versions of Firefox provide in-built ways to analyze the page and elements; however, we will use the Firebug add-in which has more powerful features. You need to install the Firebug add-in in Firefox from https://addons.mozilla.org/en-us/firefox/addon/firebug/.

To inspect an element from the page, move the mouse over the desired element and right-click to open the pop-up menu. Select the Inspect Element with Firebug option as shown in the following screenshot:

This will display Firebug with HTML code in a tree format as shown in the following screenshot:

Firebug provides various other debugging features. It also generates XPath and CSS selectors for elements. For this, select the desired element in the tree and right-click and select Copy XPath or Copy CSS Path option from the pop-up menu as shown in the following screenshot:

This will paste the possible XPath or CSS selector value on the clipboard.

Inspecting pages and elements with Google Chrome

Google Chrome provides an in-built feature to analyze pages and elements. This is very similar to Firebug. You can move the mouse over a desired element on the page and right-click to open the pop-up menu, then select Inspect element option. This will open Developer Tools in the browser, which displays information similar to that of Firebug, as shown in the following screenshot:

Chrome Developer Tools also provide a feature where you can get XPath for an element by right-clicking on the desired element in the tree and selecting the Copy XPath option from the pop-up menu.

Inspecting pages and elements with Internet Explorer

Similar to Google Chrome, Microsoft Internet Explorer also provides an in-built feature to analyze pages and elements.

To open the Developer Tools, press the F12 key. The Developer Tools section will be displayed as shown in the following screenshot:

To inspect an element, click on the pointer () icon and hover over the desired element on the page. Developer Tools will highlight the element with a blue outline and display the HTML code in a tree as shown in the following screenshot:

How it works...

Browser Developer Tools come in handy during test development. These tools will help you in finding the locator details for elements. These tools parse the code for a page and display the information in a hierarchal tree. These tools also provide information on how styles have been applied, page resources, page DOM (Document Object Model), JavaScript code, and so on.

Some of these tools also provide the ability to run JavaScript code for debugging and testing.

In the following recipes we will explore various types of locators that are supported by Selenium WebDriver and these tools will help you in finding and deciding various locator strategies or methods provided by Selenium WebDriver API.

 

Locating an element using the findElement method


Locating elements in Selenium WebDriver is done by using the findElement() and findElements() methods provided by WebDriver and WebElement class.

The findElement() method returns a WebElement object based on a specified search criteria or throws up an exception if it does not find any element matching the search criteria.

The findElements() method returns a list of WebElements matching the search criteria. If no elements are found, it returns an empty list.

Find methods take a locator or query object as an instance of By class as an argument. Selenium WebDriver provides By class to support various locator strategies. The following table lists various locator strategies supported by Selenium WebDriver:

Strategy

Syntax

Description

By ID

Java: driver.findElement(By.id(<element ID>))

C#: driver.FindElement(By.Id(<elementID>))

Python: driver.find_element_by_id(<elementID>)

Ruby: driver.find_element(:id,<elementID>)

Locates an element the using ID attribute

By name

Java: driver.findElement(By.name(<element name>))

C#: driver.FindElement(By.Name(<element name>))

Python: driver.find_element_by_name(<element name>)

Ruby: driver.find_element(:name,<element name>)

Locates an element using the Name attribute

By class name

Java: driver.findElement(By.className(<element class>))

C#: driver.FindElement(By.ClassName(<element class>))

Python: driver.find_element_by_class_name(<element class>)

Ruby: driver.find_element(:class,<element class>)

Locates an element using the Class attribute

By tag name

Java: driver.findElement(By.tagName(<htmltagname>))

C#: driver.FindElement(By.TagName(<htmltagname>))

Python: driver.find_element_by_tag_name(<htmltagname >)

Ruby: driver.find_element(:tag_name,< htmltagname >)

Locates an element using the HTML tag

By link text

Java: driver.findElement(By.linkText(<linktext>))

C#: driver.FindElement(By.LinkText(<linktext >))

Python: driver.find_element_by_link_text(<linktext >)

Ruby: driver.find_element(:link_text,< linktext >)

Locates link using it's text

By partial link text

Java: driver.findElement(By.partialLinkText(<linktext>))

C#: driver.FindElement(By.PartialLinkText(<linktext >))

Python: driver.find_element_by_partial_link_text(<linktext >)

Ruby: driver.find_element(:partial_link_text,< linktext >)

Locates link using it's partial text

By CSS

Java: driver.findElement(By.cssSelector(<css selector>))

C#: driver.FindElement(By.CssSelector(<css selector >))

Python: driver. find_elements_by_css_selector (<css selector>)

Ruby: driver.find_element(:css,< css selector >)

Locates element using the CSS selector

By XPath

Java: driver.findElement(By.xpath (<xpath query expression>))

C#: driver.FindElement(By.XPath(<xpath query expression>))

Python: driver. find_elements_by_xpath (<xpath query expression>)

Ruby: driver.find_element(:xpath,<xpath query expression>)

Locates element using XPath query

In this recipe, we will use the findElement() method to locate elements.

How to do it...

Locating elements using id, name, or class attributes is the preferred way to find elements. Let's try using these methods to locate elements as described in the following sections.

Finding elements by the ID attribute

Using the id attribute is the most preferable way to locate elements on a page. The W3C standard recommends that developers provide an id attribute for elements that are unique to each element. Having a unique id attribute provides a very explicit and reliable way to locate elements on the page.

While processing the DOM, browsers use id as the preferred way to identify the elements and this provides the fastest locator strategy.

Let's now look at how to use id attributes for locating elements on a login form.

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

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

To locate the User Name and Password fields, we can use the id attribute in the following way:

WebElement username = driver.findElement(By.id("username"));
WebElement password = driver.findElement(By.id("password"));

Finding elements by the Name attribute

Locating elements with the id attribute is the most preferred locator strategy, but you might find situations where you cannot use the id attribute due to the following reasons:

  • Not all elements on a page have the id attribute specified

  • The id attributes are not specified for key elements on a page

  • The id attribute values are dynamically generated

In this example, the login form elements use the name attribute instead of the id attribute:

<form name="loginForm">
    <label for="username">UserName: </label> <input type="text" name="username" /><br/>
    <label for="password">Password: </label> <input type="password" name="password" /><br/>
    <input name="login" type="submit" value="Login" />
</form>

We can use the name attribute to locate elements in the following way:

WebElement username = driver.findElement(By.name("username"));
WebElement password = driver.findElement(By.name("password"));

Unlike id, the name attribute may not be unique on a page. You might find multiple elements with similar name attributes and in such a case, the first element on the page with the specified value will be selected, which may not be the element you are looking for. This may cause the test to fail.

Tip

When building a testable application, you should recommend that the developers add the id attribute for key elements as well as other unique attributes to enable the easy location of elements.

Finding elements by the Class attribute

Apart from using the id and name attributes, you can also use the class attribute to locate elements. The class attribute is provided to apply CSS to an element.

In this example, the login form elements use the class attribute instead of the id attribute:

<form name="loginForm">
    <label for="username">UserName: </label> <input type="text" class="username" /></br>
    <label for="password">Password: </label> <input type="password" class="password" /></br>
    <input name="login" type="submit" value="Login" />
</form>

We can use the class attribute to locate elements in the following way:

WebElement username = driver.findElement(By.className("username"));
WebElement password = driver.findElement(By.className("password"));

How it works...

Selenium WebDriver API provides the findElement() method to locate the elements that are required in a test from the page under test.

When locating an element matching specified criteria, it looks through the DOM (Document Object Model) for matching elements and returns the first matching element to the test.

There's more...

The WebElement class also supports find methods that find child elements. For example, imagine that there are some duplicate elements on a page. However, they are located in separate <div> elements. We can first locate the parent <div> element and then locate the child element within the context of the <div> element in the following way:

WebElement div = driver.findElement(By.id("div1"));
WebElement topLink = div.findElement(By.linkText("top"));

You can also a use a shortcut method in the following way:

WebElement topLink = driver.findElement(By.id("div1")).findElement(By.linkText("top"));

NoSuchElementFoundException

The findElement() and FindElements() methods throw up the NoSuchElementFoundException exception when they fail to find the desired element using the specified locator strategy.

See also

  • The Locating elements using findElements method recipe

 

Locating elements using findElements method


Selenium WebDriver provides the findElements() method, which enables the acquisition of a list of elements matching the specified search criteria. This method is useful when we want to work with a group of similar elements. For example, we can get all the links displayed on a page or get rows from a table, and so on.

In this recipe, we will get all the links and print their targets by using the findElements() method.

How to do it...

Let's create a test which will get all the links from a page and verify the count of links and print target for each link as follows:

@Test
public void testFindElements()
{
    //Get all the links displayed on Page
    List<WebElement> links = driver.findElements(By.tagName("a"));
    
    //Verify there are four links displayed on the page
    assertEquals(4, links.size());
    
    //Iterate though the list of links and print
    //target for each link
    for(WebElement link : links)
        System.out.println(link.getAttribute("href"));
        
}

How it works...

The findElements() method returns all the elements matching with the locator specified as a list of WebElements. In Java, we can use the List class to create an instance of list of WebElements.

List<WebElement> links = driver.findElements(By.tagName("a"));

The size() method of the List class will tell us how many elements are there in the list.

assertEquals(4, links.size());

We can iterate using this list in the following way, getting a link and printing its target value:

for(WebElement link : links)
    System.out.println(link.getAttribute("href"));

See also

  • The Locating an element using the findElement method recipe

 

Locating links


Selenium WebDriver provides multiple ways to locate links. You can locate a link either by its text or by partial text.

Locating links with partial text comes in handy when links have dynamic text. In this recipe, we will see how to use these methods to locate the links on page.

How to do it...

Let's create a sample test to see how locating links work in Selenium WebDriver with the following options.

Finding a link by its text

Selenium WebDriver's By class provides the linkText() method to locate links using the text displayed for the link. In the following example, we will locate the GMail link:

WebElement gmailLink = driver.findElement(By.linkText("GMail"));
assertEquals("http://mail.google.com/", gmailLink.getAttribute("href"));

Finding a link by partial text

Selenium WebDriver's By class also provides a method to locate links using partial text. This method is useful where developers create links with dynamic text. In this example, a link is provided to open inbox. This link also displays the number of new e-mails which may change dynamically. Here we can use the partialLinkText() method to locate the link using a fixed or known portion of the link text, in this case it would be inbox.

WebElement inboxLink = driver.findElement(By.partialLinkText("Inbox"));
System.out.println(inboxLink.getText());     

How it works...

The linkText and partialLinkText locator methods query the driver for all the links that meet the specified text and returns the matching link(s).

There's more...

You can also locate links using id, name, or class attributes if developers have provided these attributes.

Note

Locating elements based on text can cause issues while testing applications in multiple locales. Using parameterized text locator value could work in such applications.

See also

  • The Locating an element using the findElement method recipe

  • The Locating elements using findElements method recipe

 

Locating elements by tag name


Selenium WebDriver's By class provides a tagName() method to find elements by their HTML tag name. This is similar to the getElementsByTagName() DOM method in JavaScript.

This comes in handy when you want to locate elements using their tag name. For example, locating all <tr> tags in a table and so on.

In this recipe, we will briefly see how to use the tagName locator method.

How to do it...

Let's assume you have a single button element on a page. You can locate this button by using its tag in the following way:

WebElement loginButton = driver.findElement(By.tagName("button"));
loginButton.click();

Take another example where we want to count how many rows are displayed in <table>. We can do this in the following way:

WebElement table = driver.findElement(By.id("summaryTable"));
List<WebElement> rows = table.findElements(By.tagName("tr"));
assertEquals(10, rows.size());

How it works...

The tagName locator method queries the DOM and returns a list of matching elements for the specified tag name. This method may not be reliable while locating individual elements and the page might have multiple instances of these elements.

See also

  • The Locating elements using findElements method recipe

 

Locating elements using CSS selectors


Cascading Style Sheets (CSS) is a style sheet language used for describing the presentation semantics (the look and formatting) of a document written in a markup language such as HTML or XML.

Major browsers implement CSS parsing engines for formatting or styling the pages using CSS syntax. CSS was introduced to keep the presentation information separate from the markup or content. For more information on CSS and CSS selectors, visit http://en.wikipedia.org/wiki/Cascading_Style_Sheets.

In CSS, pattern-matching rules determine which style should be applied to elements in the DOM. These patterns, called selectors, may range from simple element names to rich contextual patterns. If all conditions in the pattern are true for a certain element, the selector matches the element and the browser applies the defined style in CSS syntax.

Selenium WebDriver uses same principles of CSS selectors to locate elements in DOM. This is a much faster and more reliable way to locate the elements when compared with XPaths.

In this recipe, we will explore some basic CSS selectors and then later on we will dive into advanced CSS selectors.

How to do it...

Let's explore some basic CSS selectors that can be used in Selenium WebDriver. Selenium WebDriver's By class provides the cssSelector() method for locating elements using CSS selectors.

Finding elements with absolute path

CSS absolute paths refer to the very specific location of the element considering its complete hierarchy in the DOM. Here is an example where the Username Input field is located using the absolute path. While providing absolute path, a space is given between the elements.

WebElement userName = driver.findElement(By.cssSelector("html body div div form input"));

You can also use the previous selector in the following way by describing the direct parent to child relationships with > separator:

WebElement userName = driver.findElement(By.cssSelector("html > body > div > div > form > input"));

However, this strategy has limitations as it depends on the structure or hierarchy of the elements on a page. If this changes, the locator will fail to find the element.

Finding elements with relative path

With relative path we can locate an element directly, irrespective of its location in the DOM. For example, we can locate the Username Input field in the following way, assuming it is the first <input> element in the DOM:

WebElement userName = driver.findElement(By.cssSelector("input"));

The following CSS selectors use the Class and ID attributes to locate the elements using relative paths. This is same as the className() and id() locator methods. However, there is another strategy where we can use any other attribute of the element that is not covered in the By class.

Finding elements using the Class selector

While finding elements using the CSS selector, we can use the Class attribute to locate an element. This can be done by specifying the type of HTML tag, then adding a dot followed by the value of the class attribute in the following way:

WebElement loginButton = driver.findElement(By.cssSelector("input.login"));

This will find the Login button's <input> tag whose Class attribute is login.

There is also a shortcut where you can put a . and class attribute value and ignore the HTML tag. However, this will return all the elements with class as login and the test may not return the correct element.

WebElement loginButton = driver.findElement(By.cssSelector(".login"));

This method is similar to the className() locator method.

Finding elements using ID selector

We can locate the element using the IDs assigned to elements. This can be done by specifying the type of HTML tag, then entering a hash followed by the value of the Class attribute, as shown:

WebElement userName = driver.findElement(By.cssSelector("input#username"));

This will return the username <input> element using its id attribute.

There is also a shortcut where you can enter # and a class attribute value and ignore the HTML tag. However, this will return all the elements with the id set as username and the test may not return the correct element. This has to be used very carefully.

WebElement userName = driver.findElement(By.cssSelector("#username"));

This method is similar to the id locator strategy.

Finding elements using attributes selector

Apart from the class and id attributes, CSS selectors also enable the location of elements using other attributes of the element. In the following example, the Name attribute is used to locate an <input> element.

WebElement userName = driver.findElement(By.cssSelector("input[name=username]"));

Using the name attribute to locate an element is similar to the name() locator method of the By class.

Let's use some other attribute to locate an element. In the following example, the <img> element is located by using its alt attribute.

WebElement previousButton = driver.findElement(By.cssSelector("img[alt='Previous']"));

You might come across situations where one attribute may not be sufficient to locate an element and you need to combine additional attributes for a precise match. In the following example, multiple attributes are used to locate the Login button's <input> element:

WebElement previousButton = driver.findElement(By.cssSelector("input[type='submit'][value='Login']"));

Finding elements using Attributes Name Selector

This strategy is a bit different from the earlier strategy where we want to locate elements based on only the specific attribute defined for them but not attribute values. For example, we want to lookup all the <img> elements which have alt attribute specified.

List<WebElement> imagesWithAlt = driver.findElements(By.cssSelector("img[alt]"));

A Boolean not()pseudo-class can also be used to locate elements not matching the specified criteria. For example, to locate all the <img> elements that do not have the alt attribute, the following method can be used:

List<WebElement> imagesWithoutAlt = driver.findElements(By.cssSelector("img:not([alt])"));

Performing partial match on attribute values

CSS selector provides a way to locate elements matching partial attribute values. This is very useful for testing applications where attribute values are dynamically assigned and change every time a page is requested. For example, ASP.NET applications exhibit this kind of behavior, where IDs are generated dynamically. The following table explains the use of CSS partial match syntax:

Syntax

Example

Description

^=

input[id^='ctrl']

Starting with:

For example, if the ID of an element is ctrl_12, this will locate and return elements with ctrl at the beginning of the ID.

$=

input[id$='_userName']

Ending with:

For example, if the ID for an element is a_1_userName, this will locate and return elements with _userName at the end of the ID.

*=

Input[id*='userName']

Containing:

For example, if the ID of an element is panel_login_userName_textfield, this will use the userName part in the middle to match and locate the element.

How it works...

CSS selector is a pattern and the part of a CSS rule that matches a set of elements in an HTML or XML document.

The majority of browsers support CSS parsing for applying styles to these elements. Selenium WebDriver uses CSS parsing engine to locate the elements on a page. CSS selectors provide various methods, rules, and patterns to locate the element from a page. This is also a more reliable and fast method when compared with XPath locators.

Using CSS selector, the test can locate elements in multiple ways using Class, ID, attribute values, and text contents as described in this recipe.

See also

  • The Locating elements using advanced CSS selectors recipe

 

Locating elements using XPath


XPath, the XML path language, is a query language for selecting nodes from an XML document. All the major browsers support XPath as HTML pages are represented as XHTML documents in DOM.

The XPath language is based on a tree representation of the XML document and provides the ability to navigate around the tree, selecting nodes using a variety of criteria.

Selenium WebDriver supports XPath for locating elements using XPath expressions or queries.

Locating elements with XPath works very well with a lot of flexibility. However, this is the least preferable locator strategy due its slow performance.

One of the important differences between XPath and CSS is, with XPath we can search elements backward or forward in the DOM hierarchy while CSS works only in a forward direction. This means that with XPath we can locate a parent element using a child element.

In this recipe, we will explore some basic XPath queries to locate elements and then examine some advanced XPath queries.

How to do it...

Let's explore some basic XPath expressions that can be used in Selenium WebDriver. Selenium WebDriver provides the xpath() method for locating elements using XPaths.

Finding elements with absolute path

Similar to CSS absolute paths, XPath absolute paths refer to the very specific location of the element, considering its complete hierarchy in the DOM. Here is an example where Username Input field is located using the absolute path. While providing absolute path a space is given between the elements.

WebElement userName = driver.findElement(By.xpath("html/body/div/div/form/input"));

However, this strategy has limitations as it depends on the structure or hierarchy of the elements on a page. If this changes, the locator will fail to get the element.

Finding elements with relative path

With relative path, we can locate an element directly irrespective of its location in the DOM. For example, we can locate the Username Input field in the following way, assuming it is the first <input> element in the DOM:

WebElement userName = driver.findElement(By.xpath("//input"));

Finding elements using index

In the previous example, the XPath query will return the first <input> element that it finds in the DOM. There could be multiple elements matching the specified XPath query. If the element is not the first element, we can also locate the element by using its index in DOM. For example in our login form, we can locate the Password field which is the second <input> element on the page in the following way:

WebElement userName = driver.findElement(By.xpath("//input[2]"));

Finding elements using attributes values with XPath

Similar to CSS, we can also locate elements using their attribute values in XPath. In the following example, the Username field is located using the ID attribute:

WebElement userName = driver.findElement(By.xpath("//input[@id='username']"));

Here is another example where the image is located using the alt attribute:

WebElement previousButton = driver.findElement(By.xpath("img[@alt='Previous']"));

You might come across situations where one attribute may not be sufficient to locate an element and you need combined additional attributes for a precise match. In the following example, multiple attributes are used to locate the <input> element for the Login button:

WebElement previousButton = driver.findElement(By.xpath("//input[@type='submit'][@value='Login']"));

The same result can be achieved by using XPath and operator.

WebElement previousButton = driver.findElement(By.xpath("//input[@type='submit'and @value='Login']"));

In the following example, either of the attributes is used to locate the elements using XPath or operator:

WebElement previousButton = driver.findElement(By.xpath("//input[@type='submit'or @value='Login']"));

Finding elements using attributes with XPath

This strategy is a bit different from the earlier strategy where we want to locate elements based only on the specific attribute defined for them but not attribute values. For example, we want to lookup all the <img> elements that have the alt attribute specified.

List<WebElement> imagesWithAlt = driver.findElements(By.xpath ("img[@alt]"));

Performing partial match on attribute values

Similar to CSS selector, XPath also provides a way to locate elements matching partial attribute values using XPath functions. This is very useful for testing applications where attributes values are dynamically assigned and change every time a page is requested. For example, ASP.NET applications exhibit this kind of behavior where IDs are generated dynamically. The following table explains the use of these XPath functions:

Syntax

Example

Description

starts-with()

input[starts-with(@id,'ctrl')]

Starting with:

For example, if the ID of an element is ctrl_12, this will locate and return elements with ctrl at the beginning of the ID.

ends-with()

input[ends-with(@id,'_userName')]

Ending with:

For example, if the ID of an element is a_1_userName, this will locate and return elements with _userName at the end of the ID.

contains()

Input[contains(@id,'userName')]

Containing:

For example, if the ID for an element is panel_login_userName_textfield, this will use the userName part in the middle to match and locate the element.

Matching any attribute using a value

XPath matches the attribute for all the elements for a specified value and returns the element. For example, in the following XPath query, 'userName' is specified. XPath will check all the elements and their attributes to see if they have this value and return the matching element.

WebElement userName = driver.findElement(By.xpath("//input[@*='username']"));

Locating elements with XPath axis

XPath axes help to locate elements based on the element's relationship with other elements in a document. Here are some examples for some common XPath axes used to locate elements from a <table> element. This can be applied to any other element structure from your application.

Here is the graphical representation of the HTML elements:

Axis

Description

Example

Result

ancestor

Selects all ancestors (parent, grandparent, and so on) of the current node.

//td[text()='Product 1']/ancestor::table

This will get the table element.

descendant

Selects all descendants (children, grandchildren, and so on) of the current node.

/table/descendant::td/input

This will get the input element from the third column of the second row from the table.

following

Selects everything in the document after the closing tag of the current node.

//td[text()='Product 1']/following::tr

This will get the second row from the table.

following-sibling

Selects all siblings after the current node.

//td[text()='Product 1']/following-sibling::td

This will get the second column from the second row immediately after the column that has Product 1 as the text value.

preceding

Selects all nodes that appear before the current node in the document, except ancestors, attribute nodes, and namespace nodes.

//td[text()='$150']/preceding::tr

This will get the header row.

preceding-sibling

Selects all siblings before the current node.

//td[text()='$150']/preceding-sibling::td

This will get the first column of third row from the table.

You can find more about XPath axis at http://www.w3schools.com/xpath/xpath_axes.asp.

How it works...

XPath is a powerful language for querying and processing DOM in browsers. XPath is used to navigate through elements and attributes in a DOM. XPath provides rules, function, and syntax to locate the elements.

The majority of browsers support XPath and Selenium WebDriver provides the ability to locate elements using the XPath language.

Using the xpath() method of the By class we can locate elements using XPath syntax. XPath is little slower than the CSS selectors as XPath provides the ability to search elements bi-directionally. You can search for the parent element if you know the child or you can locate a child element using its relationship with the parent and siblings.

Using XPath, a test can locate elements in multiple ways based on the structure of the document, attribute values, text contents and so on, as described in this recipe.

 

Locating elements using text


While testing web applications, you will also encounter situations where developers don't assign any attributes to the elements and it becomes difficult to locate elements.

Using the CSS selectors or XPath, we can locate elements based on their text contents. In this recipe, we will explore methods to locate elements using text values.

How to do it...

For locating elements by using their text contents, CSS selectors and XPath provide methods to find text within the elements. If an element contains specific text, this will return the element back to the test.

Using CSS selector Contains Pseudo-Class

CSS selectors provide the contains() pseudo-class which can be used to see if an element contains the specified text. For example, a test wants to locate the cell of a table using its contents in the following way:

WebElement cell = driver.findElement(By.cssSelector("td:contains('Item 1')"));

The contains()pseudo-class accepts the text to be searched as a parameter. It then checks all the <td> elements in DOM for the specified text.

Note

The contains() pseudo-class may not work with browsers that don't natively support CSS selectors. Also, it has been deprecated from CSS3 specification.

As an alternative for contains() pseudo-class, you can use the innerText attribute (does not work with Firefox) or textContent attribute (for Firefox) in the following ways:

WebElement cell = driver.findElement(By.cssSelector("td[innerText='Item 1']"));

Or

WebElement cell = driver.findElement(By.cssSelector("td[textContent='Item 1']"));

You can also use jQuery selectors which support the contains() pseudo-class.

Using XPath text function

XPath provides the text() function which can be used to see if an element contains the specified text in the following way:

WebElement cell = driver.findElement(By.xpath("//td[contains(text(),'Item 1')]"));

Here we are using the contains function along with the text() function. The text() function returns the complete text from the element and the contains() function checks for the specific value that we have mentioned.

Finding elements using exact text value in XPath

With XPath, elements can be located by exact text value in the following way:

WebElement cell = driver.findElement(By.xpath("//td[.='Item 1']"));

This will locate the <td> element matching with exact text.

How it works...

CSS selector and XPath provide methods with which to locate elements based on their text contents. This approach comes in handy when elements don't have enough attributes or when no other strategies work when attempting to locate these elements.

For locating elements using their text, both CSS selector and XPath search through the DOM for elements that have the specified text value and return the matching element(s).

 

Locating elements using advanced CSS selectors


We saw some basic CSS selectors in earlier recipes. In this recipe, we will explore some advanced CSS selectors for locating elements.

How to do it...

In the Locating elements using CSS selectors recipe, we explored some basic CSS selectors. Let's explore advanced CSS selectors such as adjacent sibling combinators and pseudo-classes as described in the following sections.

Finding child elements

CSS selectors provide various ways to locate child elements from parent elements.

For example, to locate the Username Field in the login form, we can use the following selector. Here, > is used denote the parent and child relationship.

WebElement userName = driver.findElement(By.cssSelector("form#loginForm > input"));

Similarly the nth-child() method can be used in the following way:

WebElement userName = driver.findElement(By.cssSelector("form#loginForm :nth-child(2)"));

Here, the second element in <form> is the Username field. The following table shows some of the structural pseudo-classes used to locate child elements:

Pseudo-class

Example

Description

:first-child

form#loginForm :first-child

This will locate the first element under the form, that is, the label for username.

:last-child

form#loginForm :last-child

This will locate the last element under the form, that is, the Logi n button.

:nth-child(2)

form#loginForm :nth-child(2)

This will locate the second child element under the form, that is, the Username field.

Finding sibling elements

With CSS selector, we can locate sibling elements using the + operator. For example, on the sample page the <p> element with Description for Product 2 text is selected in the following way:

WebElement productDescription = driver.findElement(By.cssSelector("div#top5 > p + p"));

In this example, the first child of div#top5 will be <p> with Description for Product 1 and its immediate sibling will be Description for Product 2. Here are few more adjacent sibling combinators for locating siblings:

p + p

div#top5 > p + p

Immediately following sibling. This will locate Description for Product 2.

p + * + p

div#top5 > p + * + p

Following sibling with one intermediary. This will locate Description for Product 3.

Using user action pseudo-classes

Using the user action :focus pseudo-class, we can locate the element which has current input focus in the following way:

WebElement productDescription = driver.findElement(By.cssSelector("input:focus"));

This will locate any element that currently has the input focus. You can also locate elements using :hover and :active pseudo-classes.

Using UI state pseudo-classes

Using UI state pseudo-classes, we can locate elements for various states such as control is enabled, disabled, and checked. The following table describes these in detail:

Pseudo-class

Example

Description

:enabled

input:enabled

This will locate all the elements that are enabled for user input.

:disabled

input:enabled

This will locate all the elements that are disabled for user input.

:checked

input:checked

This will locate all the elements (checkboxes) that are checked.

How it works...

Apart from the basic CSS selectors, you can also use various advanced CSS selector methods such as pseudo-classes or adjacent sibling combinators to locate the elements with Selenium WebDriver API.

Visit http://www.w3schools.com/cssref/css_selectors.asp for an exhaustive list of CSS selectors and their usage.

See also

  • The Locating elements using CSS selectors recipe

 

Using jQuery selectors


jQuery selectors is one of the important feature of the jQuery library. jQuery Selectors are based on CSS1-3 selectors along with some additional selectors. These selectors use the familiar CSS Selector syntax to allow developers to quickly and easily identify page elements to operate upon with the jQuery library methods. Similar to CSS selectors, these selectors allow us to locate and manipulate HTML elements as a single element or list of elements.

jQuery selectors can be used where CSS selectors are not supported natively by the browsers.

In this recipe, we will explore in brief how to use jQuery selectors with Selenium WebDriver.

How to do it...

Let's create a test which checks that specified checkboxes are selected when page is displayed, as follows:

@SuppressWarnings("unchecked")
@Test
public void testDefaultSelectedCheckbox() { 
    
    WebDriver driver = new ChromeDriver();
    driver.get("http://dl.dropbox.com/u/55228056/Locators.html");
    
    //Expected list of selected Checkbox
    List<String> checked =  Arrays.asList(new String[]{"user1_admin", "user3_browser"});
    
    //Create an instance of JavaScript Executor from driver
    JavascriptExecutor js = (JavascriptExecutor) driver;

    //Locate all the Checkbox which are checked by calling jQuery //find() method. 
    //find() method returns elements in array
    List<WebElement> elements = (List<WebElement>) js.executeScript("return jQuery.find(':checked')");

    //Verify two Checkbox are selected 
    assertEquals(elements.size(),2);

    //Verify correct Checkbox are selected
    for (WebElement element : elements)
        assertTrue(checked.contains(element.getAttribute("id")));
    
    driver.close();
}

How it works...

Selenium WebDriver can be enhanced by jQuery selectors using the jQuery API. However, we need to make sure that the page has jQuery API loaded before using these selectors. The jQuery API provides the find() function through which we can search for elements. We need to use the JavaScriptExecutor class to use jQuery's find() method. In this example, we will locate all the selected checkboxes on a page by calling the find() method.

//Locate all the Checkbox which are checked by calling jQuery find() method. 
//find() method returns elements in array
List<WebElement> elements = (List<WebElement>) js.executeScript("return jQuery.find(':checked')");

The find() method returns a WebElement or list of WebElements matching the selector criteria back to the test. For more details and a list of available jQuery selectors, please visit http://api.jquery.com/category/selectors/.

You can also use the CSS Selectors described in this chapter with the jQuery find()method.

There's more...

For using jQuery selectors, the page under test should have jQuery library loaded. If your application does not use jQuery, you can load the jQuery on the page by attaching jQuery library at runtime with the following utility methods:

private void injectjQueryIfNeeded() {
    if (!jQueryLoaded())
        injectjQuery();
}

public Boolean jQueryLoaded() {
    Boolean loaded;
    try {
        loaded = (Boolean) driver.executeScript("return jQuery()!=null");
    } catch (WebDriverException e) {
        loaded = false;
    }
    return loaded;
}

public void injectjQuery() {
    driver.executeScript(" var headID = document.getElementsByTagName(\"head\")[0];"
    + "var newScript = document.createElement('script');"
    + "newScript.type = 'text/javascript';"
    + "newScript.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js';"
    + "headID.appendChild(newScript);");
}

The injectjQueryIfNeeded() method will internally call the jQueryLoaded() method to see if the jQuery object is available on the page. If the page does not have the jQuery object defined, the injectjQueryIfNeeded() method will call the injectjQuery() method to attach the jQuery library to the page header at runtime. This is done by adding a <script> element, which refers the Google CDN (Content Delivery Network) for jQuery library file, to the page. You may change the version used in this example to the latest version of the jQuery library.

 

Locating table rows and cells


While working with tables, we can locate the rows and cells effectively by using a set of the By class methods.

In this recipe, we will see how to locate rows and columns in table.

How to do it...

Let's create a simple test that will print data from a table, locating its rows and columns as follows:

@Test
public void testTable() { 
    
    WebElement simpleTable = driver.findElement(By.id("items"));
    
    //Get all rows
    List<WebElement> rows = simpleTable.findElements(By.tagName("tr"));
    assertEquals(3, rows.size());
    
    //Print data from each row
    for (WebElement row : rows) {
        List<WebElement> cols = row.findElements(By.tagName("td"));
        for (WebElement col : cols) {
            System.out.print(col.getText() + "\t");
        }
        System.out.println();
    }
}

How it works...

A table in HTML is a collection of <tr> and <td> elements for rows and cells, respectively. In the sample test, the table can be located as a WebElement using its ID as follows:

WebElement simpleTable = driver.findElement(By.id("items"));

To get all the rows from a table, the findElements() method is called on simpleTable and the tagName strategy is used to get all <tr> elements. These are rows of a table.

List<WebElement> rows = simpleTable.findElements(By.tagName("tr"));

Each <tr> element then holds the <td> elements, which are the columns or cells of the table. The test iterates through the row and columns to print the data in the following way:

//Print data from each row
for (WebElement row : rows) {
    List<WebElement> cols = row.findElements(By.tagName("td"));
    for (WebElement col : cols) {
        System.out.print(col.getText() + "\t");
    }
    System.out.println();
}

This method comes in handy when you have a test that needs to verify data in a table.

There's more…

We can also use CSS selectors or XPath for locating table rows and cells using index matching. In the following example, CSS selector is used to locate the first cell of the second row in the table:

WebElement cell = driver.findElement(By.cssSelector("table#items tbody tr:nth-child(2) td"));

Similarly using XPath, it can be done in the following way:

WebElement cell = driver.findElement(By.xpath("//table[@id='items']/tbody/tr[2]/td"));

See also

  • The Locating child elements in a table recipe

  • The Locating elements using FindElements method recipe

 

Locating child elements in a table


Working with simple tables is relatively easy. However, you will come across complex tables where other than data, table cells have child elements for user interaction. For example, in an e-commerce application when you open the shopping cart page, it looks a simple table but inside there are many complex elements.

Furthermore, these elements are dynamically created based on user actions and may have attribute values generated at runtime. Locating these elements may become a challenging task.

In this recipe, we will explore strategies to locate child elements within tables using CSS and XPath.

How to do it...

Here is sample table that lists users of a system and their details including what access rights are assigned to these users. A test needs to select a given checkbox and see if the selected access is granted to the user.

If we look at the code for this table, each record or row has the following code:

<tr>
    <td>Nash</td>
    <td><a href="mailto:[email protected]">[email protected]</a></td>
    <td>
        <div>
            <label for="user128_admin">Admin</label>
            <input type="checkbox" id="user128_admin" checked="true"/>
            <label for="user128_cm">Content Manager</label>
            <input type="checkbox" id="user128_cm"/>
            <label for="user128_browser">Browser</label>
            <input type="checkbox" id="user128_browser"/>
        </div>
    </td>
</tr>

The checkbox has dynamic IDs that we cannot correlate to a user. However, we can deal with such issues by using CSS selectors or XPath. In this example, we want to grant user Nash with admin access. This can be done using CSS selectors in the following way:

WebElement adminCheckBox = driver.findElement(By.cssSelector("td:contains('Nash')+td+td>div>label:contains('Admin')+input"));

adminCheckBox.click();

We can also use XPath in the following way:

WebElement adminCheckBox = driver.findElement(By.xpath("//td[contains(text(),'Nash')]/following-sibling::td/descendant::div/label[contains(text(),'Admin')]/following-sibling::input"));

adminCheckBox.click();

How it works...

Parent, child, and sibling in CSS or XPath axes become a great help in correlating users with roles and developing a generic locator strategy for this feature. In simple terms, these strategies help to locate elements based on the element's relationship with other elements in a document.

Coming back to the problem, first we need to find a unique way to identify a user in the table. For this, we will locate a cell which contains username. We will locate this cell using its inner text in the following way:

CSS

XPath

td:contains('Nash')

//td[contains(text(),'Nash')]

Next, we need to find the cell which contains the child elements. This is the second cell from the cell containing username.

CSS

XPath

td:contains('Nash')+td+td

//td[contains(text(),'Nash')]/following-sibling::td/

In the next step, we need to locate the label with the correct option. The next sibling of this label will be the checkbox we are looking for.

CSS

XPath

td:contains('Nash')+td+td>div>label:contains('Admin')+input

//td[contains(text(),'Nash')]/following-sibling::td/descendant::div/label[contains(text(),'Admin')]/following-sibling::input

See also

  • The Locating elements using CSS selectors recipe

  • The Locating elements using advanced CSS selectors recipe

  • The Locating elements using XPath recipe

About the Author

  • Unmesh Gundecha

    Unmesh Gundecha has over 16 years, experience in Agile software development, test automation, and DevOps methodologies. He is an Agile, open source, and DevOps evangelist with extensive experience in a diverse set of tools and technologies. He has extensive hands-on experience in building sustainable and repeatable test automation solutions for web and mobile platforms, APIs, and CLI apps with continuous integration and delivery pipelines, using best-of-breed open source and commercial tools to do so. He is the author of Selenium Testing Tools Cookbook and Learning Selenium Testing Tools with Python, both by Packt Publishing.

    Browse publications by this author

Latest Reviews

(1 reviews total)
Paid for kindle version and got pdf version instead. Contacted customer service and they said sorry.
Book Title
Access this book, plus 7,500 other titles for FREE
Access now