I personally love annotations but I am not 100% sure if they are suitable for my use case. I test Android and iOS native apps (clicking trough different views/screens and checking asserts). Currently, I search for the elements by
Now, I can also search for the elements with Annotations
public class MyClass {
@AndroidFindBy(id="signUpButton")
WebElement signUpButton;
protected void someMethod() {
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
signUpButton.click();
.....
}
I assume that the Annotations are more useful when testing static pages/ views which do not change often? When clicking trough an app (like I do), I would always have to call the initElements method when switching between screens/views.
Or are those Annotations also meant to be used for usecases I described?
public class MyScreen { @AndroidFindBy(id=âsignUpButtonâ)
WebElement signUpButton;
@AndroidFindBy(id="signUpButton")
WebElement oneAnotherElement;
//some more elements marked by @AndroidFindBy
....
public MyScreen(Webdriver driver, some parameters){
....
new AppiumFieldDecorator(driver, this); //it doesn't perform search
//it creates proxies using CGLIB library
}
protected void someMethod() {
signUpButton.click(); //search starts right now (!!!)
//if element is found click will be performed
}
.....
}
So I think it is suitable with not only static pages/screens
If element is rendered not instantly , you can use this
PageFactory.initElements(new AppiumFieldDecorator(driver,
10, //default implicit waiting timeout for all strategies
TimeUnit.SECONDS),
this
);
I already experimented with Annotations and think I will use them soon. Its great to have different annotations for iOS and Android. But, before changing my code finally, I would like to ask you some further questions.
I used âMobileElementâ instead of âWebElementâ. I did not see any troubles with it, but may I run into issues when using MobileElement (because of some cast)?
If I access a element which is not in the tree, I get a âNoSuchElementExceptionâ exception. From my point of view, it would also be a way to return a ânullâ object instead. Like this, I could use Java 8 âOptionalâ syntax to avoid Exceptions. What is your opinion about this?
What is the best workflow to check for non-present elements? E.g., I want to be sure that the user left the screen with âsignUpButtonâ. Means, I donât want the default implicit timeout to be used (PageFactory.initElements(new AppiumFieldDecorator(driver,
10,TimeUnit.SECONDS), this);) for this assert and just want to get sure that the element is not present anymore. Is there a good was or would you recommend using WebDriverWait instead?
Yeah! You can use MobileElement instead of WebElement.
It is possible to use WebElement, RemoteWebElement and MobileElement with AppumFieldDecorator.
You can look at my tests here
iOSPageObjectTest.java and AndroidPageObjectTest.java
Your second question.
If I access a element which is not in the tree, I get a âNoSuchElementExceptionâ exception. From my point of view, it would also be a way to return a ânullâ object instead. Like this, I could use Java 8 âOptionalâ syntax to avoid Exceptions. What is your opinion about this?
Throwing of NoSuchElementException is default behavior. It canât be null because it is already proxy object.
But there are some ways.
For example, you can declare list of elements.
@AndroidFindBy(âsome locatorâ)
List elements;
After you can check list size. This list has 0 size when there is nothing found.
Another way is to use ExpectedConditions and WebDriverWait.
And the third question
What is the best workflow to check for non-present elements? E.g., I want to be sure that the user left the screen with âsignUpButtonâ. Means, I donât want the default implicit timeout to be used (PageFactory.initElements(new AppiumFieldDecorator(driver,
10,TimeUnit.SECONDS), this);) for this assert and just want to get sure that the element is not present anymore. Is there a good was or would you recommend using WebDriverWait instead?
Hi there,
I did not want to open another topic, so Iâm writing here the problem:
it seems that if I use the annotations it will not find the element, whilst using the classic driver.findElement(By.id("id from Localizable.strings")); the element will be found.
The strange issue happens on a registration screen for iOS where we have to test some edit text fieldsâŚHowever the buttons are found on the other screens âŚ
âŚand this will throw the following exception: org.openqa.selenium.NoSuchElementException: Cann't locate an element by this strategy: By.all({By.id: register.firstName.placeholder,By.name: First Name})
I am also invoking
I have same confusion as @hatti when using annotation to find element in my project.
Currently itâs have same screen object as you mention above, however thereâre some issues that i meet
Some elements are existing but not display on screen, therefore I need to define a ListElement to know its exist or not before interacting with it. This solution lead us to duplicating elements also the method to handle that. With the flow i did in another project: Driver.FindElement -> element.isExisting -> element.isVisible -> click or do somethings else, this for me more flexible and easier when working around with elements
Currently I donât know how to pass the value to annotation when running. Im using Cucumber and thereâre values from step that can be used as param for selector. example I have 3 labels: labelA, labelB, labelC and I want to pass to @FindBy(xpath = â//XCUIElementTypeStaticText[@name=âVALUEâ]â)