Chapter-8: Test Synchronization

Chapter-8: Test Synchronization

In the last chapter we explored the Page Object Model in some detail. If you recall, we touched on the wait method and its significance and we promised to get back to it. So in this chapter we will understand how wait (or Synchronization) performs a vital role in Automation.

What is the general definition of Synchronization?
If two or more components are working together in parallel at the same pace or rate we call it synchronization.

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 synchronization in your code then you might face “ElementNotVisibleException” or “NoSuchElementException” exceptions. This is because the screen hasn’t finished loading and is not synchronized with your test code. To avoid this we need to implement proper synchronization in our automation script.

We can categorize synchronization in two types:

  1. Unconditional,
  2. Conditional.

Now let’s discuss each of them.

  1. 1. Unconditional Synchronization:

    • Unconditional Synchronization is also known as Static Synchronization or Static Wait. As per the name 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.
    • The standard example of Unconditional Synchronization is below:
try {
	Thread.sleep(1000);
} catch (InterruptedException e) {
	e.printStackTrace();
}
      • Here the Thread.sleep(1000) function would take 1000 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. Once again, you’ll face “ElementNotVisibleException” or “NoSuchElementException” exceptions.
      • So unconditional synchronization 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.
    1. 2. Conditional Synchronization:

        • As per the name conditional synchronization depends on some 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(Or Selenium) provides 3(mainly 2) types of conditional synchronization.
          1. Implicit wait
          2. Explicit wait
          3. Fluent wait
          1. 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 great 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(WebDriver) 
              AppiumDriver driver = new AppiumDriver(new URL(APPIUM_SERVER_URL), capabilities);
              // Set Implicit wait upon AppiumDriver(WebDriver)
              driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
              
            • NOTE: Ideally you should set the implicit wait as soon as you initialize the WebDriver.
            • Also you can use other Time Units such as
              • TimeUnit.NANOSECONDS
              • TimeUnit.MICROSECONDS
              • TimeUnit.MILLISECONDS
            • Please remember that Implicit wait works with only driver.findElement(...) and driver.findElements(...) methods - it won’t work for other methods.
            • Let’s take 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 put the 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,
              • // Click on Login Button from Home screen.
                driver.findElement(By.id("login")).click();
                
              • 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 few limitations to using Implicit wait:
                1. 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 screen as well as on the DOM, you can’t check it with Implicit wait. There might be a chance that 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.
                2. 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.
              • These limitations are resolved by the Explicit wait
          2. 2.) Explicit wait:

            • Explicit waits are the best synchronization methods for dynamic responses in the application.
            • Explicit wait informs the AppiumDriver(WebDriver) to wait
              1. Until the specified condition is met OR
              2. The specified time has elapsed

              ...before throwing an “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 particular single element rather than whole WebDriver object.
            • 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 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:
              • (ExpectedConditions.visibilityOf()) on Dashboard screen.
              • WebDriverWait webDriverWait = new WebDriverWait(driver, 30);     webDriverWait.until(ExpectedConditions.visibilityOfElementLocated(By.id("menubutton")));
                
              • When we initialize new object of WebDriverWait class, we need to pass 2 parameters:
                1. WebDriver object.
                2. Number of seconds
              • After creation of the WebDriver object you need to call the until() method and need to pass the ExpectedConditions.() inside it.
              • There are many conditions are defined in ExpectedConditions class, but we can list down few popular ones:
              • Condition Name Purpose

                elementToBeClickable(By locator)

                Example:

                ExpectedConditions.elementToBeClickable(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.elementToBeClickable(driver.findElement(By.id("menubutton")));

                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(WebElement element, java.lang.String text)

                An expectation for checking if the given text is present in the specified element.
              • You can find more details about ExpectedConditions class and it’s methods on Official Selenium docs, but remember not all are applicable to Mobile Applications, however all the methods are valid for Mobile Web Browser(Chrome/Safari):
          3. 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. Poll frequency: It is Time Interval to check whether 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 condition is met or not at every 1 seconds for maximum 10 times.
              2. Ignore the Exception: If you want to ignore specific exception such as NoSuchElementExceptions while searching for an element.
              3. Maximum wait time: The total maximum amount of time to wait for a condition is met before throwing an exception.
            • Below is the example of Fluent wait:
              FluentWait webDriverWait = new FluentWait(driver);
              
              webDriverWait.pollingEvery(Duration.ofSeconds(1));
              webDriverWait.ignoring(NoSuchElementException.class);
              webDriverWait.withTimeout(Duration.ofSeconds(10));
              

Now the question is 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 specific amount of time like every x seconds/minutes.

Synchronization in Automation Framework (WaitUtils.java)

 

  • In Chapter-7, we defined the Wait Utility in order to handle synchronization in our tests. In this section we will look into the usage of it.
  • We have created the WaitUtils object at 2 places to leverage the synchronization at Page Object or Test Class level:
  1. BasePO.java

Figure-1: WaitUtils object in BasePO

  1. BaseTest.java

Figure-2: WaitUtils object in BaseTest.

  • You can see there are many wait methods(of Implicit and Explicit wait) are defined in WaitUtils.java file, Now let’s create a simple example to use WaitUtils using the WaitUtils object at the Page Object and Test Class level.
  • WaitUtils.java
    public class WaitUtils {
    …….
    …….
        public void staticWait(final long millis) {
            try {
                TimeUnit.MILLISECONDS.sleep(millis);
            } catch (final InterruptedException e) {
            }
        }
    …….
    …….
    }
    
  1. WaitUtils usage on TestCases.javaHere the script is using staticWait(long milliSeconds) method, so after tapping on Login Screen Text View,the script will pause the execution for 2 seconds.
    public class TestCases extends BaseTest{
    
        @Test
        public void test() {
            HomeScreenPO homeScreenPO = new HomeScreenPO(driver);
            homeScreenPO.tapOnLoginScreenTextView();
            waitUtils.staticWait(2000);
        }
    …….
    …….
    }
    
  2. WaitUtils usage on .java
    Here the script is using the same staticWait(long milliSeconds) method of WaitUtils.java class. In HomeScreenPO.java we have defined tapOnLoginScreenTextView() method which clicks on Login TextView - after tapping on Login Screen Text View, execution would pause for 2 seconds.

    public class HomeScreenPO extends BasePO {
    …….
    …….
        /**
         * This method will click on Login Screen textview.
         */
        public void tapOnLoginScreenTextView(){
            loginScreenTextView.click();
            waitUtils.staticWait(3000);
        }
    …….
    …….
    }
    

    So both of them doing the same work but at different places!

    Many beginner Appium developers sometimes wonder when to wait and for how long. Using wait in your scripts will become intuitive the more you use them and the more you run into certain conditions. And don’t worry, you’ll be greeted with exceptions when you forget to include the proper wait!