The problem
Selecting your locators are a core part of writing automated WebDriver tests. However, I have seen this part of automation get overlooked so many times.
If you do not craft you locators carefully you can end up wasting a lot of time debugging brittle test cases.
I have seen development teams lose faith in the tests because they consistently give incorrect results, which can sometimes be a direct result of using poorly written locators.
Iterating on the design off web apps or fixing bugs can cause the dynamics of a page to change. Dependent on the change you may want your test to fail. However, sometimes your test should be resilient to the change (for example, styling changes), and having solid locators plays a big part in this.
Writing solid locators reduce the cost of maintenance, for the reason that reliable locators make the tests less brittle. In turn, you do not need to amend them as often.
Crafting reliable locators
When selecting locators the first thing to look for is an ID, after inspecting the element if it has an ID go for that first. If the element does not have an ID, then look to see if it's parent has an ID that can be used as a starting point to provide support followed by the descendant.
The next option should be CSS class names, but only the class names that are determined by functionality. Choose these locators over CSS class names that are used for styling, because the look and feel of the page can change but the functionality may remain the same.
Another option would be to use "data-" attributes, although the "data-" attributes can only be used in HTML 5 compliant browsers.
When constructing locators try to avoid chaining direct descendants. The reason behind this is that a change to one element in the chain will cause the locator to fail. There will be occasions when you need to use a descendant, don't be afraid to use it. Use it with careful consideration and try not to use more than one or two if possible.
Another thing to avoid is using indexes, web apps change frequently and elements may get moved around (for example, a menu item in a list). In this particular scenario you wouldn't want the test to beak if your test is verifying the functionality of a menu item. Indexes should only be used in scenarios like when you want to select the first item from a list regardless of what the list item is.
Example
If asked to select the Apple from the list above. Copying the XPath straight from Firebug will give you a locator similar to
'/html/body/some/more/direct/descendants/div/ul/li[2]'. Now imagine if the list was wrapped inside an additional div... Will the Apple still be located? No!
I have also seen people create locators like this
'//li[2]' or
'//li[position()=2]'. Now imagine if another fruit was add to the top of the list... Will the Apple still be located? No!
To overcome a problem like this you can carefully construct your XPath as follows:
'//*[@id='Shopping']//li[contains(text(), 'Apple')]'. Here you can see the Xpath uses the id of its parent as an anchor then drills into the list. When selecting the Apple, the contains function is used to ensure that the element that contains the text Apple is retrieved. This Xpath locator will work wherever the Apple is in the list.
The solution
The next time you are about to write a test, give FirePath a try.
https://addons.mozilla.org/en-US/firefox/addon/firepath/
FirePath is a Firebug extension that adds a development tool to edit, inspect and generate XPath 1.0 expressions, CSS 3 selectors and JQuery selectors (Sizzle selector engine).
For FirePath to work properly you will need to install the Firebug addon.
https://addons.mozilla.org/en-US/firefox/addon/firebug/
Before you;
- right click on an element in FireBug and select Copy XPath or Copy CSS Path
- traverse a page for a complex locator
- repeatedly try out various locators in your tests in hope that you get what your looking for
Spend a minute or so of your time and carefully construct the locator and then try it out in FirePath.