Nexial Automation

Test Automation Platform for everyone!

X

mobile

Description

As the name suggests, this is a collection of commands to support mobile automation, with mobile testing as the common form. Generally speaking, there are 3 strategies for mobile testing:

  • via emulators
  • via real devices connected to the automation host
  • via cloud testing provider (such as BrowserStack or CrossBrowserTesting)

Nexial intends to support all 3 types of mobile testing for both iOS and Android devices. However, the availability of these capabilities will be rolled out over time.

Nexial internally uses Appium to perform the communication and data transport between your scripts and the target devices. Unless of urgent or critical matter (such as a high priority security patch), Nexial will only ship with the last official stable release of Appium.

To perform mobile automation, here are the steps to follow:

  1. Install and Configure Appium
  2. Install Android SDK and Emulators - if you are targeting Android devices
  3. Install Xcode and iOS Emulators - if you are targeting iOS devices
  4. Configure Mobile Device Profile
  5. Scripting with Emulator
  6. [Run your Mobile Automation on BrowserStack] - if you are planning to run your test via BrowserStack COMING SOON!

Click on each of the links above to get started.

Locators

Those who are familiar with Web Automation know that there are multiple types of locators (also known as selectors) to identify Web elements and interact with them. For mobile automation, the use of locators is equally critical. However, there are some differences between these two types of automation. For one, not all the locators are available in mobile automation due to the underlying implementation mismatch (CSS, for example). Mobile automation also brings about a few new/unique locators as well.

For more details about using Appium Desktop to inspect elements and find locator, please visit Appium documentation on Finding and interacting with elements.

Quick Tip: ID locators are prefixed by id=

Reference an element by its ID is, by far, the simplest type of locator. Unfortunately, just like its web counterpart, the "ID" in reference isn't always unique as one would hope. For simpler applications, this locator usually works well. For more complex applications where an "ID" might be repeated across multiple elements, a different locator strategy (such as XPATH) might be a better way to go.

For Android applications, the "resource-id" property is also considered as an "ID". One can use either the id=... or res=... syntax. Here's an example of finding an "ID" of an element via the Appium inspector:


For the above example, one may express this locator as:
  • id=com.google.android.calculator:id/digit_5
  • res=com.google.android.calculator:id/digit_5
In contrast, iOS automation uses the "name" property as the "ID". Note that there isn't an actual property named "ID" or "id". However, one may use either id=... or name=... syntax. Nexial will appropriately resolve it to the correct type of locator.


For the above example, one may express this locator as:
  • id=Remind me on a day
  • name=Remind me on a day
Quick Tip: Accessibility ID locators are prefixed by a11y=

The design purpose of an accessibility ID is to improve usability for users with visual or hearing impairments. Accessibility tools like screen readers or TTS software utilize these IDs to provide additional usability support. From the test automation standpoint, the same accessibility ID can be utilized as the basis for identifying an element. As a convenience, Nexial recognizes a locator by accessibility ID via the a11y prefix (there are 11 characters between a and y of accessibility).

On Android, this locator strategy uses contentDescription or content-desc property:


For the above example, the locator would be a11y=Dark theme.

On iOS, the accessibility id, the id, and the name locator strategies are all identical. Behind the scene, they are implemented the same way.


For the above example, one would specify this locator as a11y=Back.

Generally speaking, it is preferred to use the accessibility ID over ID (although on iOS they are the same) because the accessibility ID is:
  1. beneficial to both testers and users with visual or hearing impairment.
  2. generally more readable than plain ID.
Quick Tip: XPATH locators are prefixed by xpath= or without any prefixes.

The tried and true XPATH locator is available for mobile automation, as in the case of web or desktop automation. And as it is in the case of other automation uses, XPATH is both powerful and potentially troublesome.

With XPATH, one can search for an element via its hierarchy, its attributes, and its text. Whereas the power lies, so is the danger thereof ( Peter Parker principle).

It is often prudent NOT to use the XPATH locator provided by the Appium inspector. Instead, one should put some effort into simplifying it. For example,


The provided/suggested XPATH for the "Connected devices" link is as follows (broken into lines for readability):
/hierarchy/android.widget.FrameLayout
  /android.widget.LinearLayout
    /android.widget.FrameLayout
      /android.view.ViewGroup
        /android.widget.ScrollView
          /android.widget.LinearLayout
            /android.widget.FrameLayout[2]
              /android.widget.LinearLayout
                /android.widget.FrameLayout
                  /androidx.recyclerview.widget.RecyclerView
                    /android.widget.LinearLayout[2]
                      /android.widget.RelativeLayout
                        /android.widget.TextView[1]
Surely this would work (since Appium provides this). It is also incredibly difficult to decipher and to maintain. Instead, one could reduce this to something like:
  • //android.widget.TextView[@text='Connected devices']
  • //*[@text='Connected devices']
The benefits of optimizing the XPATH are:
  1. Easier to read, hence easier to maintain
  2. No longer dependent on the hierarchy or placements of UI elements
  3. Potentially faster than the long-winded version
To use the XPATH locator in Nexial, simply use the XPATH as is or prefix it with xpath=.
Quick Tip: Name locators are prefixed by name=

Only applicable for iOS automation. Alias to the ID locator. See ID locator for more details.
Quick Tip: Resource ID locators are prefixed by res=

Only applicable for Android automation. Alias to the ID locator. See ID locator for more details.
Quick Tip: Predicate locators are prefixed by predicate=

Only applicable for iOS automation. Also known as -ios predicate string. This type of locator represents a recursive element search using the iOS Predicate (iOS 10.0 and above). The syntax is similar to the XPATH query but comes with its own set of logical and comparative operators. While this type of locator is powerful, one would essentially be writing another "mini" query language. Consult the following links for more details: Since this only works on iOS and has a dependency on the underlying iOS object model, this form of identifying elements should not be considered as the first choice. Nonetheless, at times the iOS-specific technique might be the only viable option.

For this type of locator, prefix it with predicate=.
Quick Tip: Class Chain locators are prefixed by cc=

Only applicable for iOS automation. This type of locator strategy is designed to replace XPATH (albeit only available on iOS platform) to quickly locate hierarchical elements. It is possible to use class chain (from this point, cc) to search for direct child element using / or search for descendent elements using **/ syntax. Filter criteria should be enclosed within back tick (`...`) for matching predicate, and enclosed within dollar ($...$) for containing predicates. For example, the following XPATH:
//XCUIElementTypeTable[@name="table"]/XCUIElementTypeCell[@visible="true" and .//XCUIElementTypeTextField[@name="input]]
... would be translated into cc locator like this:
**/XCUIElementTypeTable[`name == "table"`]/XCUIElementTypeCell[`visible == 1`][$type == "XCUIElementTypeTextField" AND name == "input"$]
\_____________________/\_________________/\__________________/\______________/\________________________________________________________/

 find an
 "XCUIElementTypeTable"  that has an
 element...              attribute named
                         "name" with value
                         equals to "table"   followed by an
                                             "XCUIElementTypeCell"
                                             cell...            that is visible  and it contains under its hierarchy
                                                                                 another element of type "XCUIElementTypeTextField"
                                                                                 which has an attribute called "name" with value equals
                                                                                 to "input".

While not necessarily less verbose than its XPATH counterpart, cc locator promised to be more performant without losing much of the flexibility found in XPATH. Here are a few more examples,
  • XCUIElementTypeWindow[2] - selects the second window in the hierarchy.
  • XCUIElementTypeWindow[label BEGINSWITH “foo”][-1] - selects the last window whose label begins with foo.
  • **/XCUIElementTypeCell[name BEGINSWITH "C"]/XCUIElementTypeButton[10] - selects the 10th child button of the first cell in the tree whose name starts with C and which has at least ten direct children of type XCUIElementTypeButton.
One may use Appium inspector to find a suitable cc locator for an iOS device.

For more details about the class chain queries, please visit:
This form of locator is not available in mobile automation. However, one can use the clickByDisplayText(text) to achieve the same effect. Note that this command supports PolyMatcher, a flexible way to qualify the click target via its text. See the command for more details.
Quick Tip: Text locators are prefixed by text=

This is a Nexial-only addition to the world of locators. The central idea here is to simplify automation by providing a simple way to reference an element that contains a unique string of text within the current application screen. For example,
text=Enter your first name here
... references an element that contains an attribute named text with the value of Enter your first name here.

In situations where one needs to automate a form on a mobile app, this type of locator might prove to be most useful. It is both easy to use and to decipher. This form of locator also supports PolyMatcher, which provides further expressiveness and flexibility. For example, to reference a component whose text starts with Welcome home, one can use the following text locator:
text=START:Welcome home
For more details on PolyMatcher, visit assertTextPresent(locator,text) and click on "PolyMatcher Enabled" link.

Note that behind the scene, Nexial converts such locator to an XPATH-based locator.
Quick Tip: Nearby locators are prefixed by nearby=

This is a specialized locator (only in Nexial!) aimed to simplify the task of creating a locator. Instead of identifying an element via its attributes such as content-desc, id, or accessibility id, the nearby locator allows one to identify an element by its surrounding. Nexial takes care of translating to the appropriate reference during execution time and thus saving time during scripting. While this technique does not yield the same benefit in every scenario, it is often a great time saver and a significant reduction in the cost of maintaining automation artifacts.

Let's consider the following example:

To identity the text box, we would need to inspect its attributes (typically via Appium Inspector). With the nearby locator, we can simply specify it as: nearby={below:Cellphone} (reads: Locate the element that is immediately below the element with text Cellphone). This simplified form is both easy to read and maintain.

Here's another example:

The nearby locator to identify the "Male" radio button is simply nearby={left-of:Male}.

In the above example, the radio buttons do not possess any visible text. Typically, one would need to construct suitable locators using these buttons' other attributes - likely with the help of Appium Inspector (or equivalent). With the nearby locator, we can use the "visible" surrounding of the element instead.

Here's the syntax of this nearby locator:
nearby={[relative-to]:[visible-text]}{item:[index]}{attribute=value,attribute=value,...}
where,
[relative-to] One of these values:
  • left-of - indicates that the element of interest is to the left of the visible-text
  • right-of - indicates that the element of interest is to the right of the visible-text
  • above - indicates that the element of interest is above the visible-text
  • below - indicates that the element of interest is below the visible-text
  • container - indicates that the element of interest is the parent/container of the visible-text, and that it is of the "group" type (such as android.view.ViewGroup).
  • scroll-container - indicates that the element of interest is the parent/container of the visible-text, and that it is of the "scrollable" type (such as android.widget.ScrollView).
[visible-text] The visible text is used to identify the target element.
item:... In situations where there are multiple matches, one can specify the element index (as in, the nth element) via the item keyword. The index must be a positive integer (0-based), or the special keyword last. Use item:last to signify the last match item.

Consider the following example:

nearby={right-of:UNCHECKED}{index:1} would reference the left-most checkbox and nearby={right-of:UNCHECKED}{index:last} would reference the last (right-most) checkbox.
attribute=value,... OPTIONAL. One can supply additional attributes of the target element to improve the locator precision. This is generally not needed. At times when there are many elements nearby the same text element, one may want to consider adding additional attributes to filter out the conflicting elements.
Not available in mobile automation.
Not available in mobile automation.
Not available in mobile automation.
Quick Tip: Image locators are prefixed by image=

Coming soon, stay tuned!!
Quick Tip: "One Of" locators are prefixed by one-of=

This is yet another Nexial-only, specialized locator aiming at simplifying platform-specific locator management. The main design idea is to allow one to specify multiple locators - some for a specific platform, while some as generalized locators - and allow Nexial to pick the best locator at runtime. With the one-of locator (more like locators), the multiple locators specified are filtered at execution time to the appropriate ones. This allows for cleaner automation scripts and a simpler way to maintain platform-specific or even build-specific locators. Here's an example to demonstrate this type of locator:
one-of={text=Clear all}{android;id=dismiss_text}{ios;id=clear_all_button}
The above read:
First, look for a component whose text is "Clear all".
If that can't be found and the current device is Android, then look for a component with an ID of "dismiss_text".
However, if the current device is iOS, then look for a component with an ID of "clear_all_button".
The multiple decision points here are neatly synthesized into a series of {...}{...}. This simplifies the automation effort since we wouldn't need to maintain device-specific scripts or device-specific locators.

It is noteworthy to state that the order of these "inner" locators is important. Nexial will filter out all the irrelevant ones (android for iOS and ios for Android) and "test" the relevant ones from left to right. It is generally a good idea to order the most likely "inner" locator ahead of the other ones.

Here's the syntax of this one-of locator:
one-of={[android|ios];[locator]}{[locator]}{[locator]}...
where,
[android|ios]; android or ios - each specified locator may be prefixed with android or ios to signify its platform/device dependency. During execution, Nexial will filter out the irrelevant locator(s) based on this. Note that this must be suffixed with a semi-colon. For example: {android;id=FirstName}
[locator] The device-specific or generalized locator. One may choose from any of the supported locators such as ID, Accessibility ID, Text, etc.



Available Commands

In almost all cases, one would start with the use(profile) command to establish connectivity between Nexial, Appium server, and the target device. Without proper connectivity, none of the “mobile” commands would run correctly. When finished, use the closeApp() command or shutdown(profile) to close down the application configured for a profile. One then can switch to another profile via the use(profile) command – potentially to connect to another device or another Appium server.

If the Appium server is configured to start internally within Nexial, one can also terminate it via the shutdown(profile) command.

Click on one of the links below to learn about each command.