# Element Locators

When testing web and mobile applications, you'll need locate elements of the page/screen to interact with. Gondola supports many locators for mobile and web testing. You can also use the ILocator interface to write one Page Object for Android, iOS, and web.

# Web Locators

You can locate elements with css, XPath, className, and tagName as locators. You can find the best locator for a web element using POM Builder.

# Locating an element using POM Builder

Install POM Builder

# Gondola SE

You can copy and paste this locator into Gondola SE

  1. Navigate to https://demo.gondolatest.com
  2. Right click on the Sale's link in the top right hand corner.
  3. Go to the POM Builder-Quick Copy section and select XPath
    POMB Quick Copy

# TypeScript

Use this format for writing code.

  1. Navigate to https://demo.gondolatest.com
  2. Right click on the element and click on Inspect
  3. In the inspector click on the tab labeled POM Builder
  4. Under Output, select Gondola
  5. Click the copy button POM Builder Copy Icon next to the locator type you want

POM Builder

TIP

For more see the tutorial here

# Testing a locator with POM Builder

  1. Navigate to https://demo.gondolatest.com
  2. Right click on the element and and click on Inspect
  3. In the inspector click on the tab labeled POM Builder
  4. Click the test button POM Builder Test Icon next to the locator type you'd like to test.
  5. When you click test the button next the tagName locator, notice how the field turns orange. This is because there's more than one element using the li tag. POM Builder Bad Locator
  6. In this case POM Builder recommends using an XPath. When you test the XPath locator, you can see that there's only one element it points to. POM Builder Good Locator

TIP

For more on POM Builder and choosing good locators, see the article 5 tips to distinguish good and bad locators.

# Mobile Element Locators

In Mobile Testing, you have to locate the element(s) in order to interact with the automation flow. Appium supports a subset of the WebDriver locator strategies. Refer to this list of locator strategies.

# Appium Desktop

TIP

To inspect an element, you first have to specify the Desired Capabilities to tell the Appium Server which platform and kind of application you would like to automate.

# Identifying Locators with Appium

Prerequisite: make sure you've configured your machine for mobile testing.

  1. Open Appium Desktop and start a new server
  2. Go to the File menu and click "New Session Window"
  3. Fill out the Desired Capabilities

Here is an example Desired Capabilities you can paste into the json representation section of the server settings dialog

{
  "platformName": "android",
  "deviceName": "emulator",
  "udid": "emulator-5554",
  "automationName": "UiAutomator2",
  "newCommandTimeout": 600,
  "app": "E:\\path\\to\\your.apk"
}
  1. Start the session
  2. Go the to screen in your app you wish to find a locator on and hit the refresh button in Appium.
    Appium Refresh Button
  3. Click on the element you want to use or find it in the XML tree
  4. Copy the accessibility id, id, or XPath
  5. Use an ILocator to store the property

Appium Desktop Inspector

Appium Desktop displays your apps hierarchy as an XML tree.

To install Appium Desktop or for more information click here:

# ILocators

  • The ILocator interface allows you to use the same Page Object with multiple platforms. You can define one ILocator interface and enter the properties for iOS, Android, and the web. Gondola will automatically choose the correct one for the current AUT.

  • When running automation tests on mobile devices, it is preferable to define locators that can be used in cross-platform tests.

  • To declare ILocator in Gondola use the ILocator interface.

    public static locatorName: ILocator = {
    //locator type
    xpath: "//li[.='Sale']",
    android: "~Sale"
    iOS: "#iOSLocator"
    };
    
  • iOS supports the following locator types:

    • XPath
      public xpath: ILocator = { 
        xpath: "//XCUIElementTypeButton[@name=\"gondola\"]"
      }
      
    • className: It is the full name of the XCUI element and begins with XCUIElementType
      public className: ILocator = { 
        className: "XCUIElementTypeButton"
      }
      
    • name: Name of the element
      public name: ILocator = { 
        name: "Gondola"
      }
      
    • value: Value of the element
      public value: ILocator = { 
        value: "Gondola"
      }
      
  • Android supports the following locator types:

    • XPath
      public xpath: ILocator = { 
        xpath: "//android.widget.Button[@name=\"gondola\"]"
      }
      
    • className: It is the full name of the UIAutomator2 class (e.g.: android.widget.Button)
      public className: ILocator = { 
        className: "android.widget.Button"
      }
      
    • id: Id of element
      public id: ILocator = { 
        id: "Gondola"
      }
      
  • For the properties android and iOS use the following prefixes:

    • ~ for the accessibility id (this is the most reliable property when capturing a mobile locator element).
      await gondola.checkControlExist("~Gondola");
      
    • # for the id.
      await gondola.checkControlExist("#Gondola");
      
    • // for an XPath.
      await gondola.checkControlExist("//XCUIElementTypeButton[@name=\"gondola\"]");
      
    • for plain text.
      await gondola.checkControlExist("Normal text");
      

TIP

It's recommended that you just declare one locator type for web testing. So css, className, tagName, frame, id, name, value or XPath.

WARNING

If you haven't defined the android property and use an ILocator with an Android app, the default property will be used (whichever one has been set).

# Building an XPath Query

Sometimes the elements we want to capture do not have a unique property like an accessibility id (~). In this case we can build an XPath Query, using an html tag and some properties, to access the element. This is called an XPath Query. Here are some useful points for building a query:

For mobile testing

XPath is powerful tool for finding elements, but on mobile, it comes with a pretty big performance cost. This is because XML and XPath-type queries are not natively supported by Google and Apple, at least not in the way that we’d like them to be. This forces Gondola and the libraries it uses to make a lot of expensive calls under the hood to reliably find elements using XPaths. So you can use XPath, but there are even better locator strategies you can use, like accessibility IDs.

  1. To come up with an XPath query we need to define a property that has a unique value to help distinguish the element from other elements on the current page.

    • Common formula for a query : //type[@property ='value']
    • Example: //android.widget.EditText[@content-desc ="User Name"]
    • Explanation: This query locates an element whose type is android.widget.EditText and whose property content-desc has the value User Name.
  2. To search for an element that contains a certain string -> use contains().

    • //android.widget.EditText[contains(@text, "User")]
  3. To search for an element whose text matches a string exactly -> use @text for android , @label for iOS.

    • //android.widget.EditText[@text = "UserName"]
    • //XCUIElementTypeTextField[@label ="UserName"]
    • The property text on Android usually appears as the label property on iOS.
  4. To combine two conditions -> use or , and

    • This one works for both Android and iOS //*[@text = "UserName" or @label ="UserName"]
    • Example using and:
      • //*[@text = "UserName" and @label ="UserName"]
    • You can also use and in this form: [ ][ ]:
      • //*[@text = "UserName"][@label ="UserName"]
    • Using " * " searches through all elements and can cause a reduction in performance.
    • A Gondola query should be optimized for performance and cross-platform testing:
    {
      android:{xpath:"//android.widget.EditText[@text = 'UserName']"},
      ios:{xpath:"//XCUIElementTypeTextField[@label ='UserName']"}
    }
    
  5. If the query returns a group of elements, you can access a specific element using the returned array's index. For example, if you want to access the 3rd element in an array with a depth of 1:

    • (//*[contains(@text, "us")])[3]
    • You can also use last() to access the last element in the an array.
      • (//*[contains(@text, "us")])[last()]
  6. To search for elements that do not have a certain property -> use not()

    • //android.widget.EditText[not(@visible)]
  7. If locating the element proves to be quite complex, we can use an anchor with a unique/stable property, and find the element in relation to it. Here's a few examples using an element tree:

    <book category="layer1">
        <book category="web" cover="paperback">
        <title>Learning XML</title>
        <author>Erik T. Ray</author>
        <year>2003</year>
        <price>39.95</price>
        </book>
    </book>
    
    • To go up the element tree -> use ancestor:
      • //title/ancestor::book -> returns two book elements
    • To go down the element tree -> use child:
      • ./book/child::title -> returns the title element
    • To navigate on the forwards on the same level of the element tree -> use following-sibling:
      • //book/child::title//following-sibling::price -> returns the price element.
    • To navigate backwards on the same level of the element tree -> use preceding-sibling:
      • //book/child::price//preceding-sibling::title -> returns the title element.
Last Updated: 8/14/2020, 12:49:56 PM