Page tree
Skip to end of metadata
Go to start of metadata

Last updated: Jan 30, 2020 16:46

Supported from V10.13

As opposed to previous practice, devices running with the XCUITest automation infrastructure will show very slow search performances using an XPath query. This query, with optimizations, takes ~1 second on the average application for each search, while other strategies will take half the time. In this post, we share best practices when writing a locator using other search strategies, rather than Xpath.

The following strategies will improve search results sorted by performance (arranged from fastest to slowest, according to WebDriverAgent documentation;
WebDriverAgent is developed and used at Facebook for end-to-end testing and is successfully adopted by Appium).

Tip: If @visible=true or @hittable=true occurs inside the XPath Query, it will deactivate the Optimization for the Call. This means that it will search through the entire object tree until it finds the element. As a best practice, you should not use these in your XPath. Instead, use a getAttribute("visible"); or getAtribute("hittable"); function to find the value.

To use some of these new strategies, you must upgrade your Appium client to a supported version (recommended: v5.0.4).

1 | Class Name

Class Name example
driver.findElementByXPath('//XCUIElementTypeTable');
//will translate to:
driver.findElementByClassName('XCUIElementTypeTable');

2 | Accessibility Id/Name

Id example
driver.findElementByXPath('//XCUIElementTypeTable[@name="table"]');
//will translate to:
driver.findElementByName('table');
//or
driver.findElementByAccessibilityId('table');

3 | Link Text

Link Text example
driver.findElementByXPath('//XCUIElementTypeTable[@label="tableLabel"]');
//will translate to:
driver.findElementByLinkText('label=tableLabel');
 
//by default linkText will refer to name attribute value
driver.findElementByXPath('//XCUIElementTypeTable[@name="table"]');
//could be used this way as well:
driver.findElementByLinkText('table');

4 | Predicate 

Predicate example
driver.findElementByXPath('//XCUIElementTypeTable[@name="table"]');
//will translate to:
driver.findElementByIosNsPredicate('type == "XCUIElementTypeTable" AND name == "table"');

driver.findElementByXPath('//XCUIElementTypeTable[@name="table" or @label="tableLabel"]');
//will translate to:
driver.findElementByIosNsPredicate('type == "XCUIElementTypeTable" AND (name == "table" OR label == "tableLabel")');

driver.findElementByXPath('//XCUIElementTypeTable[@name="table2" or @name="table1"]');
//will translate to:
driver.findElementByIosNsPredicate('type == "XCUIElementTypeTable" AND name IN {"table2","table1"}');

5 | Class Chain

Searching by class chain is syntactically similar to searching by XPath.

Useful Information for building a query:

  • it Is possible to search for direct children using the slash character ( / ) or searching for an indirect child using double-star and slash ( **/ ).
  • a class chain query will start from the XCUIElementTypeWindow element or with **/ (for an indirect search).
  • predicate strings should be enclosed by ` for a matching predicate and by $ for containing predicates.
  • query's will appear as a chain of elements - each element has an option of adding a predicate and an index. 
  • The predicate will always be put before the index and it is not recommended to use an index on intermediate chain elements.
    Generic example: XCUIElementTypeWindow/XCUIElementTypeAny/**/XCUIElementTypeAny[`PREDICATE`][index]

    Class Chain example
    driver.findElementByXPath('//XCUIElementTypeTable[@name="table"]/XCUIElementTypeCell[@visible="true"]');
    //will translate to:
    driver.findElementByIosClassChain('**/XCUIElementTypeTable[`name == "table"`]/XCUIElementTypeCell[`visible == 1`]');
    
    driver.findElementByXPath('//XCUIElementTypeTable[@name="table"]//XCUIElementTypeTextField[@name='input' and @visible="true"]');
    //will translate to:
    driver.findElementByIosClassChain('**/XCUIElementTypeTable[`name == "table"`]/**/XCUIElementTypeTextField[`name == "input" AND visible == 1`]');
    
    driver.findElementByXPath('//XCUIElementTypeTable[@name="table"]/XCUIElementTypeCell[@visible="true" and .//XCUIElementTypeTextField[@name="input]]');
    //will translate to:
    driver.findElementByIosClassChain('**/XCUIElementTypeTable[`name == "table"`]/**/XCUIElementTypeCell[`visible == 1`][$type == "XCUIElementTypeTextField" AND name == "input"$]');