Element Selectors
Every basic element and custom element requires a selector
object that locates the element at run time. A container element doesn't require a selector
, because it has a default.
When a selector is used for a custom element, the selector
is reserved for the custom element’s type and can’t be reused for any other type.
UTAM supports all valid CSS selectors.
Selector Properties
A selector
object has these properties:
css
(Required) String. A standard CSS selector, which can also include special selector parameters. UTAM supports all valid CSS selectors.args
(Optional) Array. Parameters to add to the methods that access this element or its nested elements. Each element in the array has these properties:name
(Required) String. A parameter name that is unique in the scope of theargs
array.type
(Required) String. A primitive type, eitherstring
,number
orboolean
.
returnAll
(Optional, default isfalse
) Boolean. To get a list of elements, setreturnAll
totrue
.
{
"elements": [
{
"name": "myDiv",
"selector": {
"css": ".myDiv"
}
},
{
"name": "listItems",
"selector": {
"css": "li a",
"returnAll": true
}
}
]
}
Selector Parameters
A selector
can depend on run-time information from the test, like a label or an index. To access this run-time information, use these format indicators inside a CSS selector. At run time, they’re replaced by values passed as parameters to the element’s public method.
- String (
%s
) - Integer (
%d
)
{
"elements": [
{
"name": "listItemWithTitle",
"selector": {
"css": "li a[title='%s']",
"args": [
{
"name": "titleString",
"type": "string"
}
]
},
"public": true
}
]
}
UTAM generates this code from the JSON.
public Actionable getListItemWithTitle(String titleString) {
// return instance of the element using selector with replaced parameter
}
A nested element can inherit parameters from its parents. In this example, the nested input needs two integer parameters for the enclosing table cell.
{
"elements": [
{
"name": "tableCell",
"selector": {
"css": "tr:nth-of-type(%d) td:nth-of-type(%d)",
"args": [
{
"name": "rowIndex",
"type": "number"
},
{
"name": "colIndex",
"type": "number"
}
]
},
"elements": [
{
"name": "inputInsideCell",
"selector": {
"css": "input"
},
"type": ["editable"],
"public": true
}
]
}
]
}
UTAM collects parameter names for every element from root that leads to the current element and adds them in order of appearance.
public Editable getInputInsideCell(int rowIndex, int colIndex) {
// Apply the provided parameters,
// then find an input element inside a table cell.
}
Mobile Selectors
The Salesforce mobile app is a mobile hybrid application. Some pages are WebView pages, and some pages are native pages. For a native page, CSS selectors aren't sufficient. To find elements in a mobile environment, Appium implements a number of locator strategies for specific mobile devices. For more information, see appium.io: Find Elements.
Appium is an open-source tool for automating native, mobile web, and hybrid applications. Appium allows you to write tests against multiple platforms, such as iOS and Android, using the same API.
Accessibility ID Selector
This selector is supported for Mobile Platform only.
Use the accessibility ID selector, which is a unique identifier for a UI element. This example uses an accessibility ID selector of searchCell.ViewAllCell
.
{
...
"name": "searchCell",
"selector": {
"accessid": "searchCell.ViewAllCell"
},
...
}
Generated Java code:
@Selector.Find(accessid = "searchCell.ViewAllCell")
private ElementLocation searchCell;
iOS Class Chain Selector
This selector is for iOS Platform only.
The iOS class chain selector finds a window element from the root of the page:
Page object JSON:
{
...
"name": "appWindow",
"selector": {
"classchain": "XCUIElementTypeWindow"
},
...
}
Generated Java code:
@Selector.Find(classchain = "XCUIElementTypeWindow")
private ElementLocation appWindow;
You can use double star and slash (**/) to define the next item descendant from the root. This strategy makes the configured locator not sensitive to the hierarchy of the page.
Page object json:
{
...
"name": "button",
"selector": {
"classchain": "**/XCUIElementTypeButton"
},
...
}
Generated Java code:
@Selector.Find(classchain = "**/XCUIElementTypeButton")
private ElementLocation button;
Sometimes, the element type isn't unique enough to identify a specific element. In those scenarios, you can combine the element type with an attribute using a predicate. The predicate string should always be enclosed in ` marks or $
characters inside square brackets. Use `` or $$ to escape a single ` or $
character inside a predicate expression.
A single backtick means the predicate expression is applied to the current children. A single dollar sign means the predicate expression is applied to all the descendants of the current element(s). String values, not the key words, can be enclosed by ' or ".
Page object JSON:
{
...
"name": "newButton",
"selector": {
"classchain": "**/XCUIElementTypeButton[`name BEGINSWITH 'New'`]",
},
...
}
Generated Java code:
@Selector.Find(classchain = "**/XCUIElementTypeButton[`name BEGINSWITH 'New'`])
private ElementLocation newButton;
This selector uses the $
character to apply the attribute to all the descendants of the current element(s).
Page object JSON:
{
...
"name": "newButton",
"selector": {
"classchain": "**/XCUIElementTypeCell[$name == \"My Accounts\"$]",
},
...
}
Generated Java code:
@Selector.Find(classchain = "**/XCUIElementTypeCell[$name == \"My Accounts\"$])
private ElementLocation newButton;
The following attributes are supported:
name
visible
value
enabled
The following comparison types for an attribute are supported:
EQUALS
or==
BEGINSWITH
ENDSWITH
CONTAINS
You can use the following operators to set conditions for multiple attributes in one expression.
AND
OR
For example:
{
...
"name": "newButton",
"selector": {
"classchain": "**/XCUIElementTypeBotton[`name BEGINSWITH 'New' AND visible == true`]",
},
...
}
Generated Java code:
@Selector.Find(
classchain = "**/XCUIElementTypeBotton[`name BEGINSWITH 'New' AND visible == true`]"
)
private ElementLocation newButton;
Similarly to CSS selectors, you can use string or integer parameters. This example uses a string parameter.
{
...
"name": "tabBarBtn",
"selector": {
"classchain": "**/XCUIElementTypeButton[`name == '%s'`]",
"args": [
{
"name": "item",
"type": "string"
}
]
}
}
Generated Java code:
@ElementMarker.Find(classchain = "**/XCUIElementTypeButton[`name == '%s'`]")
private ElementLocation tabBarBtn;
@Override
final TabBarBtnElement getTabBarBtnElement(String item) {
return element(this.tabBarBtn).build(TabBarBtnElement.class, TabBarBtnElementImpl.class, item);
}
Here's more detailed examples for iOS Class Chain.
Android UIAutomator Selector
This selector is for Android Platform only.
Appium uses the UIAutomator selector to enable searching using UiSelectors. We support the following methods only from UiSelector
to find elements:
checkable(boolean val)
checked(boolean val)
className(String className)
clickable(boolean val)
description(String desc)
descriptionContains(String desc)
descriptionStartsWith(String desc)
enabled(boolean val)
selected(boolean val)
resourceId (String id)
resourceIdMatches(String regex)
This example uses the clickable
method:
{
...
"name": "acceptButton",
"selector": {
"uiautomator": "new UiSelector().clickable(true)"
},
...
}
Generated Java code:
@Selector.Find(uiautomator = "new UiSelector().clickable(true)")
private ElementLocation acceptButton;
This example uses the className
method:
{
...
"name": "newButton",
"selector": {
"uiautomator": "new UiSelector().className(\"android.widget.TextView\")"
},
...
}
Generated Java code:
@Selector.Find(
uiautomator = "new UiSelector().className(\"android.widget.TextView\")"
)
private ElementLocation newButton;
This example uses the descriptionContains
method:
{
...
"name": "vfLink",
"selector": {
"uiautomator": "new UiSelector().descriptionContains(\"VfPage Link\")"
},
...
}
Generated Java code:
@Selector.Find(
uiautomator = "new UiSelector().descriptionContains(\"VfPage Link\")"
)
private ElementLocation vfLink;
UIScrollable
is a powerful Android class that performs element lookups in scrollable layouts. In most cases, you should use the scrollIntoView
method, which performs a scroll action until the destination element is found on the screen. You can use UIScrollable
swipe to:
- search elements in a list (for example in a country list)
- search elements outside of the screen (for example, an input field, text, or button)
The scrollIntoView
method has UiSelector as search criteria input to allow you to find elements by supported methods. For example:
{
"implements": "utam-salesforceapp/pageObjects/navigation/navItemsList",
"elements": [
{
"name": "navItemWithLabel",
"selector": {
"uiautomator": "new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(className(\"android.widget.TextView\").text(\"%s\"))",
"args": [
{
"name": "item",
"type": "string"
}
]
}
}
The generated Java code is:
@ElementMarker.Find(
uiautomator =
"new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(className(\"android.widget.TextView\").text(\"%s\"))",
nullable = true
)
private ElementLocation navItemWithLabel;
Here's more details for UIAutomator UiSelector and UiScrollable.