I am trying to use Appium to automated some iOS testing. Everything was going fine until I try to interact with one specific object. The inspector says the xpath is
(//XCUIElementTypeStaticText[@name="Terms and Conditions"])[1]
but when I try to use that with
@iOSFindBy(xpath = "(//XCUIElementTypeStaticText[@name=\"Terms and Conditions\"])[1]")
My app quits out and appium sits there a really long time before returning a NoSuchElementException. Any ideas why this would be happening? I am copying the xpath directly from the inspector.
Unfortunately I do not have the ability to add an accessibility id to the app at the moment, so I need to figure out this xpath thing.
@iOSXCUITFindBy(iOSNsPredicate = "type == 'XCUIElementTypeStaticText' AND name == 'Terms and Conditions' AND visible == 1")
private List<IOSElement> element;
// in code you can
String text = element.get(3).getText(); // get text of 4th element
Is there a way to get that specific element using the predicates? I am trying to do the following:
@iOSFindBy(xpath = "(//XCUIElementTypeStaticText[@name=\"Terms and Conditions\"])[1]")
@AndroidFindBy(accessibility = "Terms and Conditions")
public MobileElement termsAndConditions;
Don’t know why android has an accessibility id and iOS doesn’t, but that’s the situation I am in. I’d rather not have to have two different test flows between the two OSes because the app functions the same on both.
public @interface iOSXCUITFindBy {
/**
* The Class Chain locator is similar to xpath, but it's faster and can only
* search direct children elements. See the
* <a href="https://github.com/facebook/WebDriverAgent/wiki/Queries">
* documentation</a> for more details.
*/
String iOSClassChain() default "";
/**
* The NSPredicate class is used to define logical conditions used to constrain
* a search either for a fetch or for in-memory filtering.
*/
String iOSNsPredicate() default "";
/**
* It an UI automation accessibility Id which is a convenient to iOS.
* About iOS accessibility
* See <a href="https://goo.gl/a3AivX">UIAccessibilityIdentification</a>
*/
String accessibility() default "";
/**
* It is an id of the target element.
*/
String id() default "";
/**
* It is a name of a type/class of the target element.
*/
String className() default "";
/**
* It is a desired element tag.
*/
String tagName() default "";
/**
* It is a xpath to the target element.
*/
String xpath() default "";
/**
* @return priority of the searching. Higher number means lower priority.
*/
int priority() default 0;
}
@iOSXCUITFindBy(iOSNsPredicate = "type == 'XCUIElementTypeStaticText' AND name == 'Terms and Conditions' AND visible == 1")
private List<IOSElement> elList;
System.out.println(elList.size()) // gives it size and you can check what you need it is ONE expected or multiple depending of test
Ok, after reading again original post. I saw that @nwelna mentioned about single object with xpath (//XCUIElementTypeStaticText[@name="Terms and Conditions"])[1]
I was confused why you did private List<IOSElement> element; instead of private IOSElement element ?
I only needed the first (and only in my case) element that matched those conditions on my screen, however if there were multiple elements that matched that Predicate you would use a list, and pick the element you needed from that list. The annotation works both ways.
Try @iOSFindBy(xpath = “(//XCUIElementTypeStaticText[@name=“Terms and Conditions”])”)
without [1], it will search through the whole structure and look for attribute @name in all XCUIElementTypeStaticText elements.
there is also a chance that element with false visibility, so you need to check IOSFindBy method and see what it returns, i have a lot of such cases
if visibility = false i use isPresent method (wait.until(presenceOfElementLocated(locator))
if visibility = true i use iVisible method (wait.until(visibilityOfElementLocated(locator))
I had tried that as well, didn’t work either. App would force close the instant Appium tried to look up the element. Either way, the solution @Aleksei provided works, and I believe is preferred over xpath anyway.