Blog

Object Identification with IDs, CSS and XPath

Gordon Marsh Uncategorized Leave a Comment

One of the key challenges with user interface (UI) level testing is identifying which objects on screen you want to interact with. How does your automated test know that you want to click on button X? Or type text into textbox Y?

Although some tools such as Sikuli try to identify objects by image recognition, most major web automation tools try to interrogate the page’s Document Object Model (DOM). There are three main methods that can be used by examining the DOM – Object IDs, CSS Selectors and XPath.

It’s worth noting that solutions like CodeFuse utilise all three. If one fails, it falls back on the next to try and identify the object.

Object IDs

An object ID is usually an ID that a web developer has attached to an object to allow easy identification of that object. If this is the case, then this is your best option to locate on-screen objects as they are usually unique.

Sometimes object IDs are generated dynamically by the web server or client-side JavaScript. This unfortunately renders the ID useless for the purpose of automation.

It is also worth noting that while IDs are meant to be unique, this is not strictly enforced by most browsers. It is however considered best practice by most in the development community.

CSS Selectors

Cascading Style Sheets (CSS) is used to style web content. For that styling to be applied, a set of rules is needed to identify which objects should use the style. It is this mechanism that can be leveraged to find on-screen objects for other purposes. Like test automation.

Pro’s

– Often more robust than XPath – less likelihood of parent objects or structure causing problems for individual objects

– Often more concise than XPath

– Some evidence that they are faster than XPath

– More widespread browser support than XPath

Con’s

– Trickier to learn and master than XPath

Operators

This table shows the most common CSS Selector operators.

Name Operator Example Description
Direct child > div > select
Child or sub child whitespace div select
ID # div select#myid
Class . div select.myclass
Next sibling + div select + input Get the next adjacent matching element inside the same parent
General sibling ~ div select  ~ input Get any matching element inside the same parent
Attribute [x] div[id] Searches for one or more elements with an id attribute
Attribute value [x=’y’] Div[id=’myid’] Searches for an attribute/value pair
No attribute :not[] img:not[pic] Matches all img’s without a pic attribute
Child match nth-of-type

nth-child

ul:nth-of-type(3)

ul:nth-child(3)

*nth-child(3)

Find 4th ul

Return 4th item only if ul

Return 4th child

Sub string match ^=

$=

*=

li[id^=’id-prefix’]

li[id$=’id-suffix’]

li[id*=’id-ss’]

Match any id with prefix

Match any id with suffix

Match any id that contains

Match by inner text contains li:contains(‘myword’) Matches any object which contains the specified innertext
Is checked? :checked input:checked Matches any input that is selected
Helpful Hints

– Make selectors unique by combining multiple classes. E.g. button.green-btn.primary-btn

– Make selectors unique by combining multiple attribute/value pairs. E.g. div[id=’myid’][name=’myname’]

– You can still make use of IDs to add a degree of robustness to your CSS Selectors even if the actual object CSS is not very useful. If you can identify a parent, then you can find a parent with an ID then work down. For example div#myid>div>select.

XPath

Pro’s

– Easy to understand – it’s easy to follow the Xpath in the DOM

– Precision – Can uniquely identify any object

– More text recognition operators than CSS

Con’s

– Can get very long and unwieldy

– Some browsers have limited XPath support

– More brittle than CSS selectors in many circumstances

Operators

This table shows the most common XPath operators.

Name Operator Example Description
Node name name myname Selects all nodes named ‘myname’
Root node / myname/books Selects all the books under the node myname
Start search from current node // //books Selects all books
Current node . ./myname Selects all nodes named ‘myname’
Parent node .. //book[@title=’book1’]/.. Select the parent of book1
Attribute selection @ books[@style] Selects all books with a style attribute
Occurrence [x] .//book[2] Returns the second book
OR or //input[@type=’submit’ or @class=’Login’] Selects all inputs with type=submit or class=login
AND and //input[@type=’submit’ and @class=’Login’] Selects all inputs with type=submit and class=login
NOT not //a[not(contains(@id, ‘xx’))] Selects all ‘a’ elements which have id’s that don’t contain ‘xx’
Starts with starts-with //input[starts-with(@class,’tbl_’)] Returns any input whose class name starts with ‘tbl_’
Ends with ends-with //input[ends-with(@class,’_name’)] Returns any input whose class name ends with ‘_name’
Contains contains //input[contains(@id,’username’)] Returns any input with an id that contains the string ‘username’
Match value to any  attribute *= //input[@*= ‘username’)] Returns any input with any attribute with a value of ‘username’
Axes child::

parent::

 

following::

 

 

following-sibling::

 

preceding::

 

 

preceding-sibling::

 

child::table

//input[@id=’email’]/parent::*

 

//input[@id=’email’]/following::*

 

 

//select[@id=’month’]/following-sibling::*

 

//input[@id=’pass’]/preceding::tr

 

 

//select[@id=’day’]/preceding-sibling::*

Child nodes of table

Parent of input with id=email

Node immediately following input where id=email

Return sibling nodes that occur after the current node

Node immediately preceding input where id=email

Return sibling nodes that occur before the current node

 

Helpful Hints

1. Make use of relative XPaths, not absolute ones. One of the core problems with absolute Xpaths is that any change to a parent node structure will break your selector. By using relative xpath you can minimise this. For example:

<html>

<div>

<div id=’mydiv’>

<a>hello</a>

</div>

</div>

</html>

The absolute XPath would look like html/div/div/a but the relative XPath may look like //div[@id=’mydiv’]/a. This has largely removed the threat of any changes above ‘mydiv’ breaking your selector.

2. When matching an object which has multiple classes, you will find that an object <div class=”tag1 tag2” will not match with //*[@class=’tag1’]. You will need to use contains in the following way //div[contains(@class, ‘atag’) or contains(@class ,’btag’)]

General Helpful Hints

These hints are guidelines for both XPath and CSS Selectors!

– Generalise as far as possible. If you are identifying objects using values that may alter, is there a part of them which will remain consistent? Make use of contains, starts-with and ends-with for XPath and substring functions for CSS Selectors.

– Minimise the elements you need to validate. If there is more than one class included for an object, use only the ones you need. Otherwise unnecessary updates will need to be made.

– Overall, try to make your selectors as short as possible while still uniquely identifying the object.

Performance

When discussing XPath vs CSS Selectors a comment is often made about performance. Are CSS selectors faster at locating an object than XPath? Elemental Selenium looked into this and found that there were no significant time differences. However, some research by Santigo Suarez Ordonez here did show CSS selectors to be faster.

Conclusion

We hope that this article has given you some insight into how to write better XPath and CSS Selectors.

On balance from the positives and negatives, it is worth trying to utilise Object IDs followed by CSS Selectors. If that is not possible, then fall back on XPath.

Leave a Reply

Your email address will not be published. Required fields are marked *

Object Identification with IDs, CSS and XPath

01 Jun 2017

One of the key challenges with user interface (UI) level testing is identifying which objects on screen you want to interact with. How does your automated test know that you want to click on button X? Or type text into textbox Y?

Although some tools such as Sikuli try to identify objects by image recognition, most major web automation tools try to interrogate the page’s Document Object Model (DOM). There are three main methods that can be used by examining the DOM – Object IDs, CSS Selectors and XPath.

It’s worth noting that solutions like CodeFuse utilise all three. If one fails, it falls back on the next to try and identify the object.

Object IDs

An object ID is usually an ID that a web developer has attached to an object to allow easy identification of that object. If this is the case, then this is your best option to locate on-screen objects as they are usually unique.

Sometimes object IDs are generated dynamically by the web server or client-side JavaScript. This unfortunately renders the ID useless for the purpose of automation.

It is also worth noting that while IDs are meant to be unique, this is not strictly enforced by most browsers. It is however considered best practice by most in the development community.

CSS Selectors

Cascading Style Sheets (CSS) is used to style web content. For that styling to be applied, a set of rules is needed to identify which objects should use the style. It is this mechanism that can be leveraged to find on-screen objects for other purposes. Like test automation.

Pro’s

– Often more robust than XPath – less likelihood of parent objects or structure causing problems for individual objects

– Often more concise than XPath

– Some evidence that they are faster than XPath

– More widespread browser support than XPath

Con’s

– Trickier to learn and master than XPath

Operators

This table shows the most common CSS Selector operators.

Name Operator Example Description
Direct child > div > select
Child or sub child whitespace div select
ID # div select#myid
Class . div select.myclass
Next sibling + div select + input Get the next adjacent matching element inside the same parent
General sibling ~ div select  ~ input Get any matching element inside the same parent
Attribute [x] div[id] Searches for one or more elements with an id attribute
Attribute value [x=’y’] Div[id=’myid’] Searches for an attribute/value pair
No attribute :not[] img:not[pic] Matches all img’s without a pic attribute
Child match nth-of-type

nth-child

ul:nth-of-type(3)

ul:nth-child(3)

*nth-child(3)

Find 4th ul

Return 4th item only if ul

Return 4th child

Sub string match ^=

$=

*=

li[id^=’id-prefix’]

li[id$=’id-suffix’]

li[id*=’id-ss’]

Match any id with prefix

Match any id with suffix

Match any id that contains

Match by inner text contains li:contains(‘myword’) Matches any object which contains the specified innertext
Is checked? :checked input:checked Matches any input that is selected
Helpful Hints

– Make selectors unique by combining multiple classes. E.g. button.green-btn.primary-btn

– Make selectors unique by combining multiple attribute/value pairs. E.g. div[id=’myid’][name=’myname’]

– You can still make use of IDs to add a degree of robustness to your CSS Selectors even if the actual object CSS is not very useful. If you can identify a parent, then you can find a parent with an ID then work down. For example div#myid>div>select.

XPath

Pro’s

– Easy to understand – it’s easy to follow the Xpath in the DOM

– Precision – Can uniquely identify any object

– More text recognition operators than CSS

Con’s

– Can get very long and unwieldy

– Some browsers have limited XPath support

– More brittle than CSS selectors in many circumstances

Operators

This table shows the most common XPath operators.

Name Operator Example Description
Node name name myname Selects all nodes named ‘myname’
Root node / myname/books Selects all the books under the node myname
Start search from current node // //books Selects all books
Current node . ./myname Selects all nodes named ‘myname’
Parent node .. //book[@title=’book1’]/.. Select the parent of book1
Attribute selection @ books[@style] Selects all books with a style attribute
Occurrence [x] .//book[2] Returns the second book
OR or //input[@type=’submit’ or @class=’Login’] Selects all inputs with type=submit or class=login
AND and //input[@type=’submit’ and @class=’Login’] Selects all inputs with type=submit and class=login
NOT not //a[not(contains(@id, ‘xx’))] Selects all ‘a’ elements which have id’s that don’t contain ‘xx’
Starts with starts-with //input[starts-with(@class,’tbl_’)] Returns any input whose class name starts with ‘tbl_’
Ends with ends-with //input[ends-with(@class,’_name’)] Returns any input whose class name ends with ‘_name’
Contains contains //input[contains(@id,’username’)] Returns any input with an id that contains the string ‘username’
Match value to any  attribute *= //input[@*= ‘username’)] Returns any input with any attribute with a value of ‘username’
Axes child::

parent::

 

following::

 

 

following-sibling::

 

preceding::

 

 

preceding-sibling::

 

child::table

//input[@id=’email’]/parent::*

 

//input[@id=’email’]/following::*

 

 

//select[@id=’month’]/following-sibling::*

 

//input[@id=’pass’]/preceding::tr

 

 

//select[@id=’day’]/preceding-sibling::*

Child nodes of table

Parent of input with id=email

Node immediately following input where id=email

Return sibling nodes that occur after the current node

Node immediately preceding input where id=email

Return sibling nodes that occur before the current node

 

Helpful Hints

1. Make use of relative XPaths, not absolute ones. One of the core problems with absolute Xpaths is that any change to a parent node structure will break your selector. By using relative xpath you can minimise this. For example:

<html>

<div>

<div id=’mydiv’>

<a>hello</a>

</div>

</div>

</html>

The absolute XPath would look like html/div/div/a but the relative XPath may look like //div[@id=’mydiv’]/a. This has largely removed the threat of any changes above ‘mydiv’ breaking your selector.

2. When matching an object which has multiple classes, you will find that an object <div class=”tag1 tag2” will not match with //*[@class=’tag1’]. You will need to use contains in the following way //div[contains(@class, ‘atag’) or contains(@class ,’btag’)]

General Helpful Hints

These hints are guidelines for both XPath and CSS Selectors!

– Generalise as far as possible. If you are identifying objects using values that may alter, is there a part of them which will remain consistent? Make use of contains, starts-with and ends-with for XPath and substring functions for CSS Selectors.

– Minimise the elements you need to validate. If there is more than one class included for an object, use only the ones you need. Otherwise unnecessary updates will need to be made.

– Overall, try to make your selectors as short as possible while still uniquely identifying the object.

Performance

When discussing XPath vs CSS Selectors a comment is often made about performance. Are CSS selectors faster at locating an object than XPath? Elemental Selenium looked into this and found that there were no significant time differences. However, some research by Santigo Suarez Ordonez here did show CSS selectors to be faster.

Conclusion

We hope that this article has given you some insight into how to write better XPath and CSS Selectors.

On balance from the positives and negatives, it is worth trying to utilise Object IDs followed by CSS Selectors. If that is not possible, then fall back on XPath.

Leave a Reply

Your email address will not be published. Required fields are marked *

READY TO GET STARTED

Complete the form below and we’ll be in touch to discuss how we can help