public interface AutoTestLocator
AutoTest
class to reliably identify an
interactive element in a Smart GWT application. Locators allow integration with automated testing tools. For an
overview of automated testing in Smart GWT, see the documentation topic here
. AutoTestLocators are designed to work across browsers, Smart GWT
versions, and even major changes to your application's UI. They do not rely on the DOM structure, and are intended to be
able to identify the target element reliably without requiring pervasive explicitly specified component IDs
.
The AutoTest
class is
responsible for creating locator strings corresponding to DOM elements, Smart GWT components or other objects, and for
resolving locators back to those objects at runtime.
A locator for an element may be retrieved via AutoTest.getLocator()
, or by using the locator shortcut tool
, or the "Show AutoTest Locators"
link on the Results tab of the Smart GWT Developer Console
.
Stored locators may be resolved to target elements via AutoTest.getElement()
(or resolved to target objects via AutoTest.getObject()
).
Best Practices for building applications with reliable locators
Developers should be aware of certain considerations that can make generated AutoTestLocators more reliable when designing their application.
The ReliableLocators
overview topic covers general recommendations to
ensure that AutoTestLocators are robust and reliable within your app.
The PortableAutoTests
topic discusses considerations around recording and playing back test
scripts over different environments with changes to data or user interface, and the capabilities Smart GWT offers to
address these considerations.
AutoTest
locators
consist of a series of segments, delineated by "/" characters. Each segment identifies a step in a hierarchy from a root component to the target element. Individual segments may represent a Canvas, a FormItem, an interior DOM element or some other construction specific to the locator in question.
Note that the segments in an AutoTestLocator do not necessarily match parent-child relationships in the widget hierarchy.
Root locator segment The root component of a locator may designated in one of the following ways:
ID
this may be used
along with the class of the widget to reliably identify it, regardless of where it is in the page's widget
hierarchy."leftPane"
would be identified as:
//VLayout[ID="leftPane"]
Or, if Canvas.locateByIDOnly
is true, the class of the widget will not be recorded - the locator segment to identify the
root will be just the widget ID prefixed by three slash characters - for example:
///leftPane
testRoot
. This component can
then be referenced by the special root locator segment //testRoot[]
This is
useful for cases where a standard widget hierarchy may be dynamically rendered inside some component (such as
a screen
) - see the PortableAutoTests
topic for more information
defining property value
. If a target element is not a
descendant of a component with an explicitly specified ID, and is also not contained within the specified testRoot
for the application, but is contained within a component
that has a specified definingProperty value
, this
may be used to identify the root component for the locator. Base search segments are prefixed with
"//:"
and include the class name for the target component along with the defining property value.
For example - dataSource
is a defining property
for ListGrids. The following locator would identify a ListGrid bound to a dataSource with the ID
"someDS"
wherever it appeared in the page's widget hierarchy:
//:ListGrid[dataSource="someDS"]
AutoTest.getLocator()
will only generate a locator with a base search segment if the defining property value
would unambiguously identify the base component within the application. The above locator would not be generated
in an app with more than one visible ListGrid bound to "someDS"
.
Note that by default hidden
and/or undrawn components are not considered when generating and resolving locator search segments, but the special
"?"
character indicates that both hidden and visible components must be considered when resolving a
search segment.
For example the locator //:?ListGrid[dataSource="someDS"]
would retrieve
a ListGrid bound to "someDS"
whether visible or hidden.
AutoTest.getLocator()
will generate this locator format if the target
element was hidden, or if passed the searchSegmentsIncludeHidden attribute of the settings argument.
In some cases a single segment may be sufficient to identify a target element or object on the page, but in most cases, the root component locator will be suffixed with a number of interior locator segments to identify the path from the root component to the target element.
The format of individual segments within a locator will be different for different widget hierarchies and target elements. Smart GWT does not exhaustively document every possible locator format for every widget, but the patterns used are consistent and can inform application design:
autoChildren
will be
identified within their creator by their autoChild name - for example
//Window[ID="mainWindow"]/body
This happens regardless of the interim widget hierarchy between the creator and its auto-child.
named locator child
relationship will be
identified within their locator parent by name. For example marking a member of a Layout with the locator child
name "myView"
might produce a locator like:
//VLayout[ID="mainLayout"]/myView
Once again, this is regardless of the interim widget hierarchy between the locator parent and its locator-child.
"//"
. Interior search segments indicate that a
component may be uniquely identified by a defining property value
within the component identified by the previous segment in the locator. For
example the following locator would search for a ListGrid bound to "someDS"
within the body of a
window with ID "mainWindow"
:
//Window[ID="mainWindow"]/body//ListGrid[dataSource="someDS"]
Note that the AutoTest.getLocator()
method will never return a locator with a
search segment that is ambiguous in the current application.
If the AutoTest system can uniquely identify a component by defining property across the app as a whole, it will typically be used as a base search segment. If not the system will find the highest-level ancestor containing only one descendant with the specified definingProperty, and ensure the previous segment in the locator identifies that ancestor. This ensures that the final locator string is as compact as possible while unambiguously identifying the target.
As with base
search segments, a "?"
character is used to indicate that hidden or undrawn components should be
considered when resolving search locators. For example the following locator:
//Window[ID="mainWindow"]/body//?ListGrid[dataSource="someDS"]
would include hidden listGrids when searching for the grid bound to the specified dataSource.
For example a locator segment with a full set of fallback attributes identifying a member of a Layout might look like this:
VLayout[ID="mainLayout"]/member[Class=TreeGrid||index=1||length=3||classIndex=0||classLength=1||roleIndex=0||roleLength=1||scRole=tree]/
This specific segment indicates that the target component is a member of a layout. The target is a
TreeGrid, and is the first of 3 members. It also indicates this is the only member TreeGrid in the members array
[indicated by the classIndex
and classLength
attributes], and that it is the only member
with role
set to "tree"
.
The parent layout will use these fallback attributes in the locator as necessary to find the appropriate member. If the layout has three members, and the first is a TreeGrid, the target may be resolved to this member with some confidence.
If this is not the case, but there is exactly one TreeGrid in the members array, or
exactly one element with role
set to tree, it will fallback to those secondary locator strategies. If
fallback locator strategies are used, a warning will be logged so developers are aware of any potentially incorrect
locator parsing.
Developers may influence how recorded locator attributes are resolved via properties
on the locator parent. For Layouts this would include Layout.locateMembersBy
and Layout.locateMembersType
.
For brevity and
readability, when generating locators, developers may choose whether or not to include multiple fallback
attributes in locator segments by setting useMinimalFallbackAttributes
to false globally, or on the settings
parameter passed to AutoTest.getLocator()
.