Identification of elements in a web interface is one of the toughest challenges of software UI automation. First came accessing by location (x,y coordinates), which quickly faded away due to window resolutions, rendering differences etc. Then came the concept of identification using code structure. XPath became hugely popular;
Reasons being
- Automation was only attempted by established developers and they understood XPaths
- 5 years back web applications were simple enough to easily look at the DOM and identify XPaths.
- Some (silly!) tools adopted and hugely promoted XPaths for want of innovation on that front.
But XPaths quickly became notorious for being unmaintainable and difficult to understand. If test automation was to spread to non-programmer testers, this would be a huge barrier. Tools then tried to move on to css-selectors, which is still complex for the target test automation teams.
So what could be a possible solution? The answer is in the User Interface.
What is often forgotten in the software industry, is that applications are built to satisfy business needs. So whatever the id, XPath or css-selector is, a textbox meant for "loan amount" will always be near some label saying "Loan Amount". An expand or collapse icon in a tree gets its meaning from the attached "User name" label for that node. These business requirements do not change as often as code or underlying HTML structure. An HTML table may get converted to an ext-js grid with scrollbars, but the cost will still be associated (and aligned) with a product and listed under the heading "Cost". Items related to each other would be shown inside a box with an appropriate heading.
How can we use this information to identify elements? Use UI relations for identification. Sahi, which has been a pioneer in web-automation innovation, handles it as below:
A textbox meant for "loan amount" becomes
_textbox(0, _near(_label("Loan Amount")))
or
browser.textbox(0).near(browser.label("Loan Amount"))
The cost becomes
_cell(0, _near(_div("My product one")), _under(_div("Cost")))
The expand collapse icon becomes
_image("/tree-node-icon/", _near(_span("Expand me")))
- These accessors clearly communicate what the intention of the accessor is, in a straight forward way (within the constraints of programming language constructs).
- These also take away the complexity in identifying and stabilizing XPaths, or understanding complex css-selectors, or writing custom JavaScript loops to accomplish the same thing.
- They are quite stable. _near allows for more elements to come between two related elements, _under is spatially aligned. So you can move different elements around on the UI and still have your scripts working properly.
UI Relations are guaranteed to exist in any business application, irrespective of whether you have ids or not.
One argument that comes up is, what if there are two similar elements which satisfy the same condition. While it is still possible to index the similar accessors and uniquely identify them, it seldom happens in a real world application. If you have two textboxes near "Loan amount", it is going to confuse your end user. User-interfaces do not generally have such anomalies. That said, an added index to the accessor handles that scenario too, if it arises.
There is one other simplification that Sahi does in its accessor APIs. It does not explicitly state what the identifying property is. For example what could have been
_textbox()
is simply given as
_textbox("username")
in Sahi.
Why? Because there are very few cases where one textbox has name="username" and another has id="username". Such naming would obviously confuse the web developer forcing him to not do something like this.
Combined with UI relations, Sahi also takes care of automatically waiting for AJAX requests and page loads. This makes for robust scripts which hardly have unexpected failures. Other features like parallel playback of suites, automatic report generation, ant integration etc. make Sahi one of the most advanced web testing tools in the industry.
If you have not tried it yet, download from http://sourceforge.net/projects/sahi/files/ now.