Test Synchronisation in Appium | Mobile Automation
Most of the time test script will because of application takes to load the web page due to this element will not be loaded to perform the actions specified in the script. If two or more components are working together in parallel at the same pace or rate, synchronisation comes into play.
We see it in almost every application whenever the screen changes it takes a few milliseconds (or seconds) to load, and if you do not manage the proper synchronisation in your code then you might face the dreaded “ElementNotVisibleException” or “NoSuchElementException” exceptions. This is because the screen hasn’t finished loading and is not synchronised with your test code. That is, your test code is over eager and starts trying to perform an action on an element that hasn’t been loaded yet. To avoid this we need to implement proper synchronisation in our automation script.
Broadly there are two types synchronisation:
1) Unconditional synchronisation,
2) Conditional
Now let’s discuss each of them in detail.
1) Unconditional synchronisation:
Unconditional Synchronisation is also known as
Static Synchronization or Static Wait.
As the name suggests, it specifies a particular fixed (static) time
to wait before starting the execution. Here Appium(or any program)
will wait the specified amount of time and then it will resume the
execution. During this wait, it will not perform any action, that is
big drawback of this unconditional synchronisation.
Sometimes you put this wait with 10 seconds to
make sure element get displayed, if element loaded and displayed
within 2 seconds also still it waits for 10 seconds. Due to this our
automation script execution may take longer.
The standard example of Unconditional Synchronisation is
below:
try{
Thread.sleep(5000);
} catch(InterruptedException e)
{
System.out.println( e);
}
Here the Thread.sleep(5000) function would take 5000 ms to execute.
Key to note is that this wait will be absolute, even if the underlying condition you were waiting on has been met. For example, you may put in a wait for 3 seconds waiting for the screen to load. Even if that screen loads in 2 seconds, the system will still wait for the additional second. The converse is also true - Sometimes the wait finishes before the underlying operation and execution proceeds.
In test automation, for example, limited network connectivity may slow the mobile application response time and a screen change may now take 5 seconds while the script only waits 3 seconds. Due to this, we will face “ElementNotVisibleException” or “NoSuchElementException” exceptions.
So unconditional synchronisation or static wait is not the preferred way to deal with dynamic responses.
However it is a viable strategy to use it when you are working with some 3rd party interfaces and where you can not identify the underlying condition you need to wait on OR you are sure about the response time.
2) Conditional synchronisation:
Conditional synchronization depends on some underlying condition. So
in addition to a specified absolute time to wait, the condition is
also passed into the method. Here the script(or program) will resume
execution as soon as the condition is met - or, in the event the
condition isn’t met, it will resume after the specified time.
Appium provides 3 types of conditional synchronisation.
- Implicit wait
- Explicit wait
- Fluent wait
1) Implicit wait:
Implicit wait tells the Appium’s webdriver object to poll the DOM for
the specified amount of time while trying to find the element before
throwing an “ElementNotVisibleException” or “NoSuchElementException”
exceptions.
The big advantage of using Implicit wait is it’s lifespan. As we
apply Implicit wait on the Webdriver object, it will be valid for
the webdriver object’s lifespan.
Below is the code to apply the Implicit wait of 10 seconds on the
Webdriver object.
//Define AppiumDriver
AppiumDriver driver = new AppiumDriver(new URL(APPIUM_SERVER_URL), capabilities);
//Set implicit wait upon AppiumDriver
Driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
NOTE:
Ideally you should set the implicit wait as soon as you
initialize the WebDriver.
Please remember that Implicit wait works with only
driver.findElement() and driver.findElements()
methods - it won’t work for other methods.
Let’s look at a simple example for better understanding.
You want to click on the Login button on the home screen but the home
screen itself takes some to appear when the Appium script runs.
So ideally you need to specify a condition that Appium should locate
the Login Button element(on the home screen) within 10 seconds after
starting the script and if the element is not present (or the home
screen has not appeared) after 10 seconds, only then throw Exceptions.
You can write the following statement after writing the above
(webdriver initialization and set implicit wait of 10 sec.) code:
You will notice that we don’t need to specify anything else to the
code as we already added the 10 seconds implicit wait to the
AppiumDriver object. Now
it will be polling the DOM for 10 seconds until the Login Button is
found and as soon as the button is found, it will be clicked.
However there are a few limitations to using Implicit wait:
-
As you know it’s only useful for driver.findElement() and
driver.findElements() methods - we can’t check other
conditions. For example if you want to wait until a particular button
is displayed on the screen as well as on the DOM, you can’t check it
with Implicit wait. There is a chance that the particular button is in
the DOM but it’s hidden or it’s not visible on the screen, so in that
case Implicit wait executes successfully but would not give us the
accurate answer about the element’s visibility.
- There is a chance that the time for the implicit wait isn’t enough. For example as we mentioned earlier where we’re waiting 5 seconds but limited network connectivity causes the screen to take 10 seconds to load. In that case Implicit wait will break.
2) Explicit wait:
driver.findElement() & driver.findElements()
- These limitations are resolved by the Explicit wait.
Explicit waits are the best synchronization methods for dynamic
responses in the application.
Explicit wait informs the AppiumDriver to wait
- Until the specified condition is met OR
- The specified time has elapsed
...before throwing the “ElementNotVisibleException” or
“NoSuchElementException” exceptions.
And if the AppiumDriver is able to meet the condition within the
specified amount of time then the code will get executed.
In explicit wait we need to tell the WebDriver object to wait for a
specific condition using the ExpectedConditions class. So, actually
this wait is specific to a particular single element rather than the
whole WebDriver object (unlike implicit wait).
The WebDriverWait class will call the ExpectedCondition every
500 milliseconds by default until the output is True. So if you have
given 10 seconds of timeout, ExpectedCondition would be called 20
times at 500 milliseconds intervals to check if the condition has been
met. Now let’s take one simple example to understand the use of Explicit wait.
In almost all mobile applications when you perform a Login it takes some time to load the dashboard or home screen and its elements. For example purposes, let’s say there is a menu button on the dashboard screen. You can use an Explicit wait with the condition of wait till menu button element is visible:
(ExpectedCondtions.visibilityOf(<menu_button_element>)) on Dashboard screen.
When we initialize new object of WebDriverWait class, we need to pass 2 parameters:
- WebDriver object.
- Number of seconds
Condition Name
|
Purpose
|
elementToBeClickable(By locator)
Example:ExpectedConditions.elementToBeCli ckable(By.id(“loginButton”)); |
An expectation for checking an element is visible and enabled
such that you can click it. In this method you need to pass the object of By class. |
elementToBeClickable(WebElement element)
Example:
ExpectedConditions.elementToBeCli
ckable(driver.findElement(By.id("me nubutton"))); |
An expectation for checking an element is visible and enabled
such that you can click it. In this method you need to pass the
object of WebElement class. |
presenceOfElementLocated(By locator) |
An expectation for checking that an element is present on the
DOM of a page. This does not necessarily mean that the element
is visible. |
visibilityOfElementLocated(By locator) |
An expectation for checking that an element is either invisible
or not present on the DOM. |
elementToBeSelected(WebElement element) |
An expectation for checking if the given element is
selected. |
numberOfElementsToBe(By locator, java.lang.Integer
number) |
An expectation for checking number of WebElements with given
locator. |
titleIs(java.lang.String title) |
An expectation for checking the title of a page.
This is not applicable to Appium Mobile Application. |
textToBePresentInElement(WebEle ment element, java.lang.String
text) |
An expectation for checking if the given text is present in the
specified element. |
|
|
3) Fluent wait:
Fluent wait is part of WebDriverWait, The only difference is it’s
more configurable than Explicit wait.
You can configure the:
1.
1) Pollfrequency :
The is the Time Interval to check whether the expected condition for
the webelement is met or not. So if poll frequency is 1 second and
total wait time is 10 seconds, fluent will check if the condition is
met or not at every 1 second for a maximum of 10 times.
2.
2) IgnoretheException :
If you want to ignore a specific exception such as
NoSuchElementExceptions while searching for an element.
3.
3) Maximumwaittime :
The total maximum amount of time to wait for a condition is met
before throwing an exception.
FluentWait<AppiumDriver> wait = new FluentWait<AppiumDriver>(driver);
wait.pollingEvery(Duration.ofSeconds(1));
wait.ignoring(NoSuchElementException.class);
wait.withTimeout(Duration.ofSeconds(10));
Which types of Wait you should use When?
Wait Type
|
Purpose
|
Implicit
|
When you need to apply common wait without any condition.
|
Explicit
|
When you need to test expected condition for an element
|
Fluent
|
When you need to test expected condition for an element after
a specific amount of time every x seconds/minutes
|
No comments:
Post a Comment
If any suggestions or issue, please provide