PageObject Generator Utility for Selenium WebDriver

Today I saw an interesting tweet lined up in my twitter stream about a Page Recorder utility developed by Dmitry Zhariy which aids in generating PageObjects for Selenium WebDriver tests. I could not resist to get hands-on with this tool and write this post.

I was playing with an idea to build such an utility and someone already done such a good work developing this cool tool. You can read the original blog post about SWD Page Recorder utility here (translated in English)

This project is hosted on GitHub https://github.com/dzhariy/swd-recorder and licensed under The MIT License.

First Impressions

The SWD Page Recorder utility helps automation developers in finding and locating elements as well as creating page objects through a nicely built user interface. You don’t need to juggle around browsers and tools like Firebug/Developer tools in Google Chrome or IE to find/create locator strategies. This tool allows you to launch various types of browsers, navigate to page and spy on elements, look at their attributes, create & test locators. You can then use this information to generate page objects in various programming languages.

SWD Recorder can be used to test locators just like Selenium IDE on browsers like IE, Chrome and Safari.

This is still in beta phase and have some areas for improvements. Read on the original blog for more details. I played with the utility to create a page object for http://demo.magentocommerce.com/customer/account/login/ with following steps:

Launch the SwdPageRecorder application. On the main Window you need to select & configure Browser that you want to use from Browser Settings tab. It also allows option to connect to RemoteWebDriver instance.

Select the desired Browser and hit Start button to start the Browser instance. By default utility points to http://www.yahoo.com. You can change this by entering desired URL in Browser textbox above Browser Settings tab and click on Go button.

It will navigate to the URL as shown in below screenshot:

Browser Settings

Browser Settings

Switch to Locators tab and click on Start button in In-Browser Web Element Explorer section. Now switch to the Browser instance opened by SWD Page Recorder.

Focus on a desired element in the Browser window and press Ctrl + Right click. This will open a popup window as shown in below screenshot:

Element Information

Element Information

Add a desired element by specifying a logical/descriptive name in Code Identifier textbox and click on Add element button. In this example I will specify emailTextBox in Code identifier textbox

Go on adding elements that are needed for test with above steps.  You can see the elements from the page added to the tree in below screenshot:

Login Page Elements

Login Page Elements

You can also add elements manually or edit elements that are already added by using WebElement section. Elements can be highlighted using Highlight button to test that locator information is sufficient or debug the locator values.

Generating PageObject Code

Once you capture all the elements needed for your PageObject, switch to Source Code tab. The source code tab provides templates for generating PageObject code in various languages (C#, Java, Perl, Python, Ruby etc.). Select a desired template and click on Generate button to generate the code. SWD Page Recorder generated following code the elements added from Login page.

PageObject Code

PageObject Code

You can either copy the code back to the editor or save this in a file and done!

Conclusion

Overall this utility worked pretty good. There are few glitches which I hope should be gone after beta is over. There is a scope for improvement in overall usability of the tool. Along with PageObjects I also want to see utility generating a sort of XML/Properties file based UI-Map.


Using DOM, XPath & CSS for Object Identification in QTP – Part 3

We saw how to use HTML DOM and XPath for Web Object Identification in Part 1 & Part 2. In this final Part we will explore using CSS for Object Identification in QTP 11.

Introduction to CSS (Cascading Style Sheets)

CSS (Cascading Style Sheets) is a language used for formatting and rendering of HTML and XML documents.

CSS uses Selectors for binding style properties to elements in the document. These Selectors can be used by QTP as another object identification strategy.

Finding elements with XPath can be costly in terms of performance. CSS Selectors can be more efficient as they are forward only. However they do not provide backword search flexibility as XPaths.

Using CSS for Web Object Indetification

Along with XPath, QTP 11 has added CSS Object Identification Property to all Test Objects in Web Add-In. You can specify CSS Selectors by using css Property.

You can enable and use css Property in Object Repository or in Descriptive Programming. In following example CSS class attribute is used identify Sign In Button on Gmail Home Page:


Browser("title:= Gmail: Email from Google").Page("title:= Gmail: Email from Google").WebButton("css:=input.g-button").Click

Using CSS class attribute is most common and simplest method to indetify the elements. You can identify the elements using class attribute in following way:


element.class_attribute

In above example we identified Sign In Button on Gmail Home Page. Here is the HTML Syntax for Sign In Button. You can see developers have assigned class attribute as g-button:

<input id="signIn" class="g-button" type="submit" value="Sign in" name="signIn" style="background-color: rgb(77, 144, 254);">

Identifying Elements using ID

As we saw in XPath, we can identify elements using their IDs, CSS also has similar way to identify elements using ID. Following is the syntax for identifying elements using ID:

element#id

We need to specify a # between element type and its ID. In following example we will identify User Name Text Box on Gmail Home Page using its ID:


Browser("title:= Gmail: Email from Google").Page("title:= Gmail: Email from Google").WebEdit("css:=input#Email").Set "myname"

Identifying Elements using Attributes

Similar to XPath, we can also use element attributes to identify objects. Following is the syntax for identifying elements using their attributes:

element[attribute=value]

In following example, we will identify and check Stay signed in Checkbox on Gmail Home Page using type attribute:


Browser("title:= Gmail: Email from Google").Page("title:= Gmail: Email from Google").WebCheckBox("css:=input[type='checkbox']").Set "ON"

We can also perform partial match on attribute values using following operators:

Operator Description
^=attribute_value Finds the element attribute starting with the value passed. This is similar to starts-with() function in XPath
*= attribute_value Finds the element attribute which contains the value passed. This is similar to contains() function in XPath
$= attribute_value Finds the element attribute ending with the value passed. This is similar to ends-with() function in XPath

In following example, developers have assigned dynamic attribute values for all the input elements in following way:

<div id='login_area'>
<input type='text' name='text_1'>
</div>

We can use either ^= or *= function to identify this object in following way:


Browser("title:= Test App").Page("title:= test App").WebEdit("css:=div#login_area input[name^='text_']").Set "somevalue"

Browser("title:= Test App").Page("title:= test App").WebEdit("css:=div#login_area input[name*='text_']").Set "somevalue"

Identifying Elements using Text Contents

Locating elements by the text they contain can be quite useful. To identify elements, we need to use CSS contains pseudo class. This will match the entire contents of the element.


element:contains('text')

In following example, we will use contains pseudo class to identify the Create an account link on Gmail Home Page:


Browser("title:= Gmail: Email from Google").Page("title:= Gmail: Email from Google").Link("css:=a:contains('Create an account')","index:=0").Click

Identifying Elements using Relationships

Similar to XPath Axes, we can identify elements using relationships in CSS. Following are some exmaples  for identifying elements by their relationships:

Child/Descendent Elements nth-child orE1 >E2
Element <E1> following some sibling <E2> E2 ~ E1
Element <E1> immediately following sibling <E2> E2 + E1
Element <E1> following sibling <E2> with one intermediary E2 + * + E1

For more combinations please refer here.

We will use the Shopping Cart example from Part 2 to understand identifying elements using relationships in CSS. In following example we select an item by entering the quantity and click the Shopping Cart image to add the item in Cart:


Browser("title:= ShopX").Page("title:= ShopX ").WebEdit("xpath:=td:contains('0002')+td+td+td>div>form>div>input[name='qty']").Set "10"
Browser("title:= ShopX").Page("title:= ShopX ").Image("xpath:=td:contains('0002')+td+td+td>div>form>div>input[name='add']").Click

Here is another example I created for a custom Dropdown control. This control is created with combination of a Text Box, a Button and a DIV containing multiple LI elements. QTP identify this control in following way:

Custom Dropdown Control

When clicked on the Dropdown Button which is identified as WebButton, a dynamic DIV is displayed with values available for selection in HTML LI elements. This is automated using CSS in following way:

Browser(title:=MyApp").Page("title:=MyApp).WebButton("id:=item_Dropdown").Click
Browser(title:=MyApp").Page("title:=MyApp).WebElement("css:=div#item_Dropdown>li:contains('Value2')").Click

There are endless possibilities to identify objects using CSS and XPath. However these are some of the example to understand the basics.

I will close this series with a caution that DOM, XPath, CSS type of identifiers are dependent on locations and page structure and may not work always where developers change the UI frequently.


Using DOM, XPath & CSS for Object Identification in QTP – Part 2

XPath is another important Web Object Identifier introduced in QTP 11. It is one of the widely used identification strategy in open source tools. In this tutorial we will understand using XPath for locating Web objects in your application with QTP.

Introduction to XPath

XPath is used for locating nodes in an XML document and it can also be used for locating HTML elements in XHTML. XPath opens up all sorts of new possibilities for locating complex & dynamically rendered elements.

Awkwardly, developers not always follow best practices or testability guidelines while building the applications. XPath comes to your help when you don’t have a suitable id or name attribute for the element you wish to identify. You can use XPath to either identify the element in absolute terms or relative to an element that does have an id or name attribute. XPath locators can also be used to specify elements via attributes other than id and name.

Using XPath for Web Object Identification

QTP 11 has added XPath Object Identification Property to all Test Objects in Web Add-In. QTP offers two ways to use XPath, you can either instruct QTP to record Automatic XPath by settings Options in Tools menu or you can specify User Defined XPath in xpath Property.

You can also enable and use xpath Property in Object Repository or in Descriptive Programming. In following example a direct XPath query is used to identify Search Text Box on Google:


Browser("title:=Google").Page("title:=Google").WebEdit("xpath:=//input").Set "What is XPATH"

In above example we used //input to identify the Search Text Box. Using // in XPath query is called greedy query as it parses the entire HTML DOM until it finds the desired element. This way is useful when objects are dynamically positioned; however it takes certain amount of time to find the element.

However if you are certain about position of the desired element, you can use a direct XPath query by using single /, however please make you sure that the HTML is first node in your query. Following example shows direct XPath query for User Name Text Box on Gmail Home Page:

Browser("title:= Gmail: Email from Google").Page("title:= Gmail: Email from Google").WebEdit("xpath:=/html/body/div/div[2]/div/div/form/label/input").Set "myname"

Direct XPath query will find the element quicker, however if application GUI is going to change, it may fail if the element is moved into a different area of the Page.

Using Element Attributes in XPath

We can use various element attributes such as ID, Name, Value, Type etc. to identify element in following way:


//element [@attribute='attribute value']

In following example, ID attribute is used to identify User Name Text Box on Gmail Home Page:


Browser("title:= Gmail: Email from Google").Page("title:= Gmail: Email from Google").WebEdit("xpath:=//input[@id='Email']").Set "myname"

We can also use combination of attributes in XPath query so that we can try to make the element more unique for identification:


//element[@attribute='attribute value' and @attribute='attribute value']

In following example, we will identify and check “Stay signed in” Checkbox on Gmail Home Page:


Browser("title:= Gmail: Email from Google").Page("title:= Gmail: Email from Google").WebCheckBox("xpath:=//input[@id='PersistentCookie' and @type='checkbox']").Set "ON"

Identifying Elements using partial match on Attribute values

We can use XPath functions such as contains(), starts-with() & ends-with() to perform partial match on attribute values while locating the elements. This is useful when developers use Dynamic IDs or Name attributes while rendering the elements on a Page. This is commonly used in AJAX applications & frameworks.


//element[starts-with(@attribute,’attribute partial value')]
//element[contains(@attribute,’attribute partial value')]
//element[ends-with(@attribute,’attribute partial value')]

In following example, developers have assigned dynamic ID’s for all the input elements in following way:

<div id='login_area'>
    <input type='text' id='text_1'>
</div>

We can use either starts-with() or contains() function to identify this object in following way:


Browser("title:= Test App").Page("title:= test App").WebEdit("xpath:=//div[@id='login_area']/input[starts-with(@id, 'text_')]").Set "somevalue"

 

Browser("title:= Test App").Page("title:= test App").WebEdit("xpath:=//div[@id='login_area']/input[contains(@id, 'text_')]").Set "somevalue"

Identifying Elements using Text Contents

Locating elements by the text they contain can be quite useful. To identify elements, we need to use text() function in XPath query. This will match the entire contents of the element.


//element[text()='inner text']

In following example, we will use text() function to identify the Create an account link on Gmail Home Page:


Browser("title:= Gmail: Email from Google").Page("title:= Gmail: Email from Google").Link("xpath:=//a[text()='Create an account']").Click

We can also use XPath functions contains(), starts-with() or ends-with() for matching partial text.


//element[contains(text(),'text value')]

Exmaple:


strLotsOfStorageMessage = Browser("title:= Gmail: Email from Google").Page("title:= Gmail: Email from Google").WebElement("xpath:=//p[contains(text(),'Over')]").GetROProperty("innerText")

Identifying Elements with XPath Axes

In simple terms XPath Axes helps to identify elements based on element’s relationship with other elements in a document. For more information, there is a nice tutorial available on W3Schools on XPath & XPath Axes.

For example in an e-commerce web application, we want to select and add items to shopping cart. However the items are listed in a table dynamically with complex HTML structure. Following figure shows the structure of the table:

ShoppingCart

Shopping Cart Page

The textbox to enter the Quantity and image to add item was buried under layer of div elements inside a td element in a table. The ids for these elements were generated dynamically and it is difficult to add an item dynamically from the test script. Here is html code for Quantity textbox:

For Product 1


<input type="text" id="count_670756" value="" maxlength="3" size="3" name="qty">

For Product 2


<input type="text" id="count_670759" value="" maxlength="3" size="3" name="qty">

As you can see in the above code, we cannot rely on id attribute as it changes every time page is refreshed and secondly name of textbox is not unique.

We need to find a unique way to identify a Product in the table. There are two columns which contain unique values namely Product & Article column. However Article column contains primary key from the database so it is highly recommended to use this value as basis to identify the product. We can also use Product column otherwise. Following XPath Query will identify the cell containing the specified Article using XPath functions contains() & text():


xpath:=//td[contains(text(),'0002')]

Now we need to find the cell which contains the elements. Here we will use following-sibling axis and find the third cell from the current cell. Following query will return the cell containing Quantity & Add to cart image:


xpath:=//td[contains(text(),'0002')]/following-sibling::td[3]

In next step we need to get the actual elements which are located inside the layer of div elements. Here we need to use descendent axis to find the child elements in the cell:


xpath:=//td[contains(text(),'0002')]/following-sibling::td[3]/descendant::div[2]/input[@name='qty']

xpath:=//td[contains(text(),'0002')]/following-sibling::td[3]/descendant::div[3]/input[@name='add']

We can remove the nth element, or element Index to make this XPath query more flexible in following way:


xpath:=//td[contains(text(),'0002')]/following-sibling::td/descendant::div/input[@name='qty']
xpath:=//td[contains(text(),'0002')]/following-sibling::td/descendant::div/input[@name='add']

VBScript code to enter quantity for an Item and add selected Item to the Shopping Cart in QTP:


Browser("title:= ShopX").Page("title:= ShopX ").WebEdit("xpath:=//td[contains(text(),'0002')]/following-sibling::td/descendant::div/input[@name='qty'").Set "10"
Browser("title:= ShopX").Page("title:= ShopX ").Image("xpath:=//td[contains(text(),'0002')]/following-sibling::td/descendant::div/input[@name='add']").Click

These actions will be used to add multiple items in various test cases. We need to make these actions more generic and remove the hardcoded Article Id. Following example shows user defined function in QTP for above steps:


Public Function fnAddItemToShoppingCart(ByVal strArticleID, ByVal strQTY)

Browser("title:= ShopX").Page("title:= ShopX ").WebEdit("xpath:=//td[contains(text(),'" & strArticleID &  "')]/following-sibling::td/descendant::div/input[@name='qty'").Set strQTY
Browser("title:= ShopX").Page("title:= ShopX ").Image("xpath:=//td[contains(text(),'" & strArticleID & "')]/following-sibling::td/descendant::div/input[@name='add']").Click

End Function

However while using XPath we need to consider the fact that these locators are dependent on structure of the page and the layout of the elements. Any changes to the structure or layout will affect the locators and tests will result into failures.


Using DOM, XPath & CSS for Object Identification in QTP – Part 1

QTP 11 introduced new features to identify Web objects using HTML DOM, XPath & CSS. These object identification strategies are widely used in open source tools like Selenium, WATIR etc.

In this series, I will explain how to use HTML DOM, XPath and CSS for identifying objects in your Web application. In Part 1, I will use HTML DOM for identifying the Web objects.

Document Object Model

The W3C Document Object Model (DOM) is a platform and language-neutral interface that allows programs and scripts to dynamically access and update the content, structure, and style of a HTML document.

The HTML DOM defines the objects and properties of all HTML elements, and the methods (interface) to access them. JavaScript uses DOM to add interactivity to HTML pages.

We can use the combination of JavaScript and HTML DOM interfaces to identify objects within Web Pages and Frames. This strategy can be useful for testing AJAX applications when object are dynamically added to the Web Page or Frame. While QTP’s Object Repository & AJAX testing features should suffice your need, this strategy can be used as a workaround for identifying the objects.

Document Object Model Methods (Interfaces)

Following HTML DOM document object methods (interfaces) can be used in QTP for identifying objects:

Method Description
getElementById Returns the first element with the specified id
getElementsByName Returns all elements with a specified name in an JavaScript array
getElementsByTagName Returns all elements with a specified tagname in a JavaScript array

Calling JavaScript Code in QTP

QTP 11 introduced RunScript method to the Page and Frame Test Objects in Web Add-In. We can use this method to inject and execute JavaScript code in Page or Frame Test Objects. This method has number of uses for example testing JavaScript code within your page, invoking JavaScript events etc. This feature comes handy while testing complex AJAX Web applications.

Following example will display a JavaScript popup with Hello There!! message. This example uses Descriptive Programming to identify Browser and Page objects:

Browser("title:=Google").Page("title:=Google").RunScript("alert('Hello There!!');")

Using HTML DOM Methods & Properties in QTP

To access the HTML DOM methods we need to use the document object. We can use getElementById method to access the element using its HTML ID. This method will return the first element it finds in HTML DOM with specified ID. For example on Gmail Login Page, we can access the User Name text box by following way.

HTML Syntax for User Name Text Box:

<input id="Email" type="text" name="Email" />

QTP VBScript Syntax to access User Name Text Box:

Set objUserNameTextBox = Browser("title:=Gmail: Email from Google").Page("title:=Gmail: Email from Google").RunScript("document.getElementById('Email');")
objUserNameTextBox.value = "myname" 'Uses value property to set the contents of Text Box

This is most recommended method to identify the objects using HTML DOM. However this method might not work for elements where HTML IDs are not defined. We can use getElementsByName method to identify the elements by specifying the name attribute value. In following example we will use same Gmail Login User Name Text Box, however this time we will identify this element using the name attribute value:


Set objUserNameTextBox = Browser("title:=Gmail: Email from Google").Page("title:=Gmail: Email from Google").RunScript("document.getElementsByName('Email')(0);")
objUserNameTextBox.value = "myname" 'Set  User Name Text Box value

The getElementsByName returns a JavaScript array for all the elements whose name matches with the specified value. In above example we use array index to access the 0th element, which is the User Name Text Box.

However there is another method which comes handy when you don’t have either IDs or Names specified for HTML elements. Using getElementsByTagName you can identify the object by Tag name. This is least preferred way to access the elements.


Set objUserNameTextBox = Browser("title:=Gmail: Email from Google").Page("title:=Gmail: Email from Google").RunScript("document.getElementsByTagName('INPUT')(12);")
objUserNameTextBox.value = "myname" 'Set  User Name Text Box value

The getElementsByTagName returns a JavaScript array for all the elements whose HTML Tag name matches with the specified value. In above example we use array index to access the 12th element which is the User Name Text Box. This method needs efforts to find out exact index of the intended element. If the index changes, your script will fail.

We can also use combination of HTML DOM methods to identify the objects. In following example a Text Box is embedded in DIV element, however this Text Box does not have enough identification properties. We will use getElementById to identify the parent DIV element and getElementsByTabName to identify the Text Box:

HTML Syntax:

</pre>
<div id="<span class=&quot;hiddenSpellError&quot; pre=&quot;&quot;>mainArea</span>"> </div>
<pre>
	<p>Enter Amount: <input type=text></input></p>
</div>

QTP VBScript Syntax to access Text Box:


Set objAmountTextBox = Browser("title:=MyApp").Page("title:=MyApp").RunScript("document.getElementById('mainArea').getElementsByTagName('INPUT')(0);")
objAmountTextBox.value = "100" 'Set the Text Box value

We can also identify elements using the relationships. Following table explains using various relationship identifiers:

document.getElementById(‘mainArea’).firstChild Returns the first child element of element returned from getElementById
document.getElementById(‘mainArea’).lastChild Returns the last child element of element returned from getElementById
document.getElementById(‘mainArea’).parentNode Returns the parent element of element returned from getElementById
document.getElementById(‘mainArea’). nextSibling Returns the next sibling element of element returned from getElementById
document.getElementById(‘mainArea’). previousSibling Returns the previous sibling element of element returned from getElementById

In the next instalment we will see how to use XPath for locating the objects in QTP.


Using XPath Axes for locating elements in Selenium

XPath is a very powerful and widely used mechanism in Selenium for locating elements on a Web Page. XPath is used for locating nodes in an XML document and it can also be used for locating HTML elements in XHTML. Selenium supports XPath along with various other locator strategies. XPath in Selenium extends beyond the simple methods of locating by id or name attributes, and opens up all sorts of new possibilities for locating complex & dynamically rendered elements.

Developers not always follow best practices or testability guidelines while building the applications. XPath comes to your help when you don’t have a suitable id or name attribute for the element you wish to locate. You can use XPath to either locate the element in absolute terms or relative to an element that does have an id or name attribute. XPath locators can also be used to specify elements via attributes other than id and name.

Recently a team approached me for solving a locator problem in Selenium. They were testing an e-commerce web application. They had a difficulty in selecting & adding an item to shopping cart. The table listing the items was rendered dynamically using dynamic ids and complex HTML structure. Following figure shows the structure of page:

ShoppingCart

Shopping Cart Page

The textbox to enter the Quantity and image to add item was buried under layer of div elements inside a td element in a table. The ids for these elements were generated dynamically and it was difficult to add an item dynamically from the test script. Here is html code for Quantity textbox:

For Product 1


<input type="text" id="count_670756" value="" maxlength="3" size="3" name="qty">

For Product 2


<input type="text" id="count_670759" value="" maxlength="3" size="3" name="qty">

As you can see in the above code, we cannot rely on id attribute as it changes every time page is refreshed and secondly name of textbox is not unique.

XPath Axes comes to a great help to resolve this problem and develop a generic location strategy. In simple terms XPath Axes helps to locate elements based on element’s relationship with other elements in a document. For more information, there is a nice tutorial available on W3Schools on XPath & XPath Axes.

Coming back to the problem, first we need to find a unique way to identify a Product in the table. There are two columns which contain unique values namely Product & Article column. However Article column contains primary key from the database so it is highly recommended to use this value as basis to locate the product. We can also use Product column otherwise. Following XPath Query will locate the cell containing the specified Article using XPath functions contains() & text():


xpath=//td[contains(text(),'0002')]

Now we need to find the cell which contains the elements. Here we will use following-sibling axis and find the third cell from the current cell. Following query will return the cell containing Quantity & Add to cart image:


xpath=//td[contains(text(),'0002')]/following-sibling::td[3]

In next step we need to get the actual elements which are located inside the layer of div elements. Here we need to use descendent axis to find the child elements in the cell:


xpath=//td[contains(text(),'0002')]/following-sibling::td[3]/descendant::div[2]/input[@name='qty']

xpath=//td[contains(text(),'0002')]/following-sibling::td[3]/descendant::div[3]/input[@name='add']

Following screen-shot shows the Selenium IDE commands to enter the Quantity and click on the Shopping Cart image:

seleide

Selenium IDE

These actions will be used to add multiple items in various test cases. We need to make these actions more generic and remove the hardcoded Article Id. Following example shows the custom command implemented in Selenium User Extension and Selenium IDE:


Selenium.prototype.doAddItemToShoppingCart = function(locator, value){

                this.doType("xpath=//td[contains(text(),'"+locator+"')]/following-sibling::td[3]/descendant::div[2]/input[@name='qty']", value);

                this.doClick("xpath=//td[contains(text(),'"+locator+"')]/following-sibling::td[3]/descendant::div[3]/input[@name='add']");

}

custcommand

Custom Command in Selenium IDE

We can also create reusable function around these actions in following way for Selenium RC in Java:


public void addItemToShoppingCart(String ArticleId, String Qty) throws Exception
	{
		selenium.type("xpath=//td[contains(text(),'" + ArticleId + "')]/following-sibling::td[3]/descendant::div[2]/input[@name='qty']", Qty);
		selenium.click("xpath=//td[contains(text(),'" + ArticleId + "')]/following-sibling::td[3]/descendant::div[3]/input[@name='add']");
	}

However while using XPath we need to consider the fact that these locators are dependent on structure of the page and the layout of the elements. Any changes to the structure or layout will affect the locators and tests will result into failures.

Update:

Sometimes XPath queries may not work well or tests run slow in browsers that do not have good support for XPaths. CSS selectors is a good alternative in such situations. CSS selectors are considerably faster than XPath. Selenium supports CSS 1.0, 2.0 & 3.0. Following code sample describes CSS selectors for locating the elements from above example:


css=td:contains('0002')+td+td+td>div>form>div>input[name='qty']
css=td:contains('0002')+td+td+td>div>form>div>input[name='add']