Problem
Element identification lies at the core of automating web tests because without it, your test automation tool has no clue about how to locate and interact with the correct web elements on your application under test. As recommended by W3C, XPath is today’s solution of choice widely adopted by many web automation solutions including the famous Selenium framework. However, just like mastering a katana, making use of XPath up to the proficient level requires quite some time and deliberate effort. This article aims to help you take full advantage of XPath by unveiling the 3 common yet deadly misconceptions which novice testers might pick up while learning this powerful “secret weapon”.
Misconceptions Unveiled
[1] XPath is an inherent property of the web element
Unraveling XPath this way is natural when you are learning the ropes of XPath but later on, it reveals itself as a dangerous analogy. Let’s say you’re copying the XPath of a button (<input>) on Chrome by right clicking on the element and choosing Copy > Copy XPath:
This is what you get:
//*[@id="Login"]
Meanwhile, if you use Firebug (an add-on of Firefox) on the same particular button, you will receive an utterly different result:
/html/body/div/table/tbody/tr[5]/td/input
How on earth the XPath “property” of the same element is not even remotely similar provided that the element has not changed a wee bit?
It’s because XPath is indeed not a control’s “property” after all. By definition, XPath is a language to tell a browser, a test tool or any other pieces of software how to navigate an XML document and find the specified element. Hence, it’s very normal that different tools return different XPaths for the same exact element.
This implicates that it’s up to you to determine which XPath is the most readable yet reliable to identify an element.
Some test automation frameworks such as LogiGear’s TestArchitect™ offer a built-in feature to purposefully construct an elegant XPath to efficiently locate your web element. For instance, the screenshot below shows TestArchitect’s suggested XPath for the aforementioned button.
This path (//input[@id='Login']) is more elegant because:
· It’s more specific than Chrome’s XPath (//*[@id="Login"]) which accepts all tags as long as it has the predefined ID. Chrome’s suggestion would return the wrong element in case there happens to exist a <td> with the identical ID (very likely).
· It’s less fragile than Firebug’s XPath (/html/body/div/table/tbody/tr[5]/td/input) which could be easily broken (returns null) if let’s say, the <input> tag is somehow moved to another table row (e.g. tr[8])
No matter which suggestion is better than which, at the end of the day, you are still in charge of being the final gatekeeper.
[2] XPath is not reliable
This impression comes from the fact that sometimes your test run fails on a different browser (say Firefox) because the element captured using XPath on the original browser (say Chrome) cannot be found. A closer look explains that the button’s XPath on Chrome is actually:
//input[@id='stdinput-00001']
While on Firefox, that same button’s XPath is:
//input[@id='stdinput-0000A']
This could be the case of dynamically generated elements which is quite popular in web development nowadays. Somewhere along the way, a developer has tied the creation of these web elements to a specific web browser. Although this practice doesn’t promote testability, it still exists out there in the wild.
If you didn’t pay attention, you could blame XPath for doing a lousy job. But in fact, the culprit is not XPath. Instead, it is the application’s peculiar method of generating different IDs on different browsers. While waiting for the developers to fix this inconsistency and improve the app’s testability, you can continue testing by adding a little tweak to your XPath as follows:
//input[contains(@id, 'stdinput-00001') or contains(@id, 'stdinput-0000A')]
Bravo! Your test can now run on both Chrome and Firefox.
[3] XPath is the silver bullet
Relying on XPath too much without carefully dissecting your web application would result in a big frustration when you receive unexpected failures. It’s worth emphasizing that one single XPath can fetch different elements in different contexts. For instance, let’s examine the following XPath:
//a[.='Mac']
What you want to interact with is the below <a> element:
But to your surprise, it’s not the case in reality. Instead, this element is the one being clicked:
Therefore, to be absolutely sure about what you get, you should invest in a good insight of the page’s hierarchy. In this particular example, you can easily distinguish the two elements based on their different ancestors.
XPath for the product’s name of the search result (case #1):
//div[@id='content']//a[.='Mac']
XPath for the breadcrumb button (case #2):
//div/ul/li/a[.='Mac']
Conclusion
Hopefully unveiling these deadly misconceptions could help you understand XPath on a deeper level so that your tests will become more robust and automating web apps is as effortless as possible. Stay tuned for the upcoming article dedicated to XPath’s best practices.