TESTEROPS

A pragmatic approach to QA and OPS

Selectors

In the last post, I had mentioned about how to use assertions and waiting and other commands in the tests. However, what good would be a test if there are no elements to act upon?

So the first thing that you’d look for is how to identify the target element in the maestro tests. Because unless you’re able to identify which elements to act upon, you will not be able to perform any action on them.

Selector Types

Text

You can directly use the text of an element as a selector and apply any action on it. Let’s say I want to tap on the screen on element with name Pepsi. So I can do this

- tapOn: "Pepsi"

Now you will question, what if there are multiple elements with the same name Pepsi? Then we can use the index to pass the locator/selector parameter.

- tapOn:
    text: "Pepsi"
    index: 2

Note that the indexing is 0 based so index 2 in the above example will actually refer to the third element.

You can also give the regex of the text if you want to match it to a regex pattern.

ID

Second type of selector that you can use is the id attribute of an element. You can directly pass the id value of an element to the tapOn or any other command that you want to do with that element

- tapOn:
    id: android:id/button2

Here I’m using the Appium Inspector to inspect the elements. In this image, you can see the element with text Close has a unique id which can be used in the tests with maestro.

Other Selectors

Apart from visible text and id , there are other ways of selecting elements too that maestro has mentioned in their documentation.

    index: 0         # (optional) 0-based index of the view to select among those that match all other criteria
    point: 50%,50%.  # (optional) Relative position on screen. 50%,50%: Middle of screen
    point: 50, 50    # (optional) Exact coordinates on screen, x:50 y:50, in pixels.
    width: 100       # (optional) Finds element of a given width
    height: 100      # (optional) Finds element of a given height
    tolerance: 10    # (optional) Tolerance to apply when comparing width and height
    enabled: true    # (optional) Searches for view with a given "enabled" state
    checked: true    # (optional) Searches for view with a given "checked" state
    focused: true    # (optional) Searches for view with a given "focused" state
    selected: true   # (optional) Searches for view with a given "selected" state
    optional: false  # (default: false) If set to true, test won't fail if view can't be found

Most of this can be used in conjunction with the earlier text or id selectors. A good example of index is given above. You can use the point selector in this way

 tapOn:
    id: android:id/button2
    point: "50%,90%" # Tap bottom middle to deal with selector alignment

Relative Locators

Apart from the locators and the attributes that can be used, maestro also gives you the ability to locate elements based on a relative locator. If you’re coming from Selenium background, then in Selenium 4, the concept of relative locators was also introduced.

Directly copying from the maestro documentation –

- tapOn: # or any other command that works with selectors
    below: "View above that has this text"     # This will match view *above* that has the given text
    above:
        id: "view_below_id"                    # This will match a view *below* that has the given id
    leftOf: "View to the right has this text"
    rightOf: "View to the left has this text"
    containsChild: "Text in a child view"      # This will match a view that has a *direct* child view with the given text
    childOf:                                   # This will help to select from children of view with id 'buy-now'
        - id: "buy-now"
    containsDescendants:                       # This will match a view that has all the descendant views given below
        - id: "title_id"
          text: "A descendant view has id 'title_id' and this text"
        - "Another descendant view has this text"

Let’s give an example of the how to use this – this is a code snippet from one of the flow files that I have in the repo

- tapOn:
    above: "Schezwan Margherita"

or, you can also use like this

 - assertNotVisible:
                id: "Guests Icon"
                childOf:
                  - id: "some_id"

Caveats

The issue that I see is that maestro does not support native xpaths unlike it’s competitors like Appium or XCUITest. For simple flows, it might not be a big issue, but when there are a lot of similar elements, then there might be issues in locating elements.

Although the concept of indexing is possible with multiple text elements, but since xpath doesn’t only relies on the concept of indexes and there are much more intelligent xpath strategies so it makes it much easier in case of complex hierarchical structure.