public interface PortableAutoTests
This is useful for the following scenarios:
screens
) may have common
user interface elements nested under different hierarchies in different deployments, or
even for different usersAutoTest variables
The variables
feature allows developers to specify explicit variable names and corresponding
values for use when resolving AutoTest locators.
Variables may be used anywhere within a locator string, but a common use case would be handling different data in different deployments. For example the locator for a ListGrid cell element might be as follows:
//ListGrid[ID="countryList"]/body/row[pk=47||countryCode=WS||countryName=Western%20Samoa||2]/col[fieldName=countryName||1]
This locator includes various fallback attributes to identify the row and column (see the
AutoTestLocator overview
for information about
fallback attributes in locator segments).
If you want to identify the cell by primary key field value and column name only, this could be simplified to be just:
//ListGrid[ID="countryList"]/body/row[pk=47]/col[fieldName=countryName]
In a
different data set, the equivalent record might have a different primary key field value,
meaning any locators that referenced it via hardcoded values like pk=47
would fail
to resolve to the correct target. This can be handled by setting up an AutoTest variable before
the test executes - for example recording the target record as testRecord
, and
referring to it directly in the locators:
//ListGrid[ID="countryList"]/body/row[pk=${testRecord.pk}]/col[fieldName=countryName]
AutoTestLocator root
The testRoot
attribute allows developers to designate some component as the "root" for an
autoTest. With this setting in place, locators for elements anywhere within that root
component will be generated as a path from the testRoot to the target component. These locators
will always start with the special prefix //testRoot[]
.
If the same UI
elements are then rendered inside another container in a different environment, configuring
testRoot
to point to this container will
allow the locators to resolve correctly.
If no global testRoot was specified, any component
with an explicit ID
will be treated as the
root component for the elements it contains. This means that locators for components with
explicit IDs will resolve correctly regardless of where these components are in the page's
struture.
Components with an explicit ID are located by ID and widget class name by
default. You can also set Canvas.locateByIDOnly
- this will cause the generated locator for the component to omit the
widget class name altogether and create a very compact locator of the format
///componentID
AutoChildren and explicit locatorParents
As
documented here
, locators are structured as a
series of segments, with each segment identifying a step in the path from a base component to a
target element on the page.
The Smart GWT AutoTest system uses a variety of mechanisms to
resolve the segments in a locator to their targets. The segments do not match the hierarchy of
widgets on the page. Individual segments do not all represent Smart GWT components, and
segments that are representative of a component may not be a direct child
of the canvas represented by the
previous segment.
Developers interested in having the AutoTest subsystem generate compact and reliable locators should be aware of the following features of locator generation and resolution:
autoChildren
will always be identified by just their
autoChild name. For example the body of a listGrid in a locator string will show up as just
/body/
.Canvas.setLocatorParent()
method allows developers to set up an explicit named
locator-parent / child relationshiop between any two components without requiring one be an
autoChild of the other.locatorParent
feature, the AutoTest
subsystem will directly identify the child component by name. The implementation details of
your nested user-interface - what class of widget the logical child is, what the
widget-hiearchy between the components looks like, etc - will have no impact on the locators,
meaning you can restructure the implementation without losing the ability to use
already-recorded tests. Search segments and defining properties
AutoTest
locators may include search-segments as detailed here
.
A search segment in a locator will identify
a component based on its defining property values
. Search segments are resolved to a component via a depth-first search
within the previous component in the locator chain, or within the entire page if the first
segment is a search segment.
The inclusion of search-segments in locators can help greatly
with the how robustly components can be identified, regardless of where they are rendered in
the widget hierarchy. If an application contains a single visible listGrid bound to some
target dataSource, a search-locator segment such as
//:ListGrid[dataSource="worldDS"]
will find the grid even if it's located in an
entirely different parent in a playback deployment compared to where the test was created.
The set of attributes that act as defining properties vary by component class (See Canvas.getDefiningPropertyName()
),
and developers may define their own defining properties for custom components. For example if
an application consists of a series of customized layouts, by declaring a definingProperty of
"layoutName"
, and populating the layoutName on each layout you can easily cause
the autoTest system to find them, wherever they are displayed.
This pattern, along with the ability to have multiple search locator segments in a locator allows locators to be very robust against changes to the application. For example the following locator:
//:CustomLayout[layoutName='salesView']//ListGrid[dataSource="worldDS"]
... would find the target layout, wherever it is in the page, and then find the target list grid, however it is nested inside that layout.