Table of Contents

We have came very far in this Designing Selenium Cucumber Framework series. We have designed PageObjectManager to manage PageObjects, FileReaderManager to manage ConfigFileReader and JSonFileReader and WebDriverManager to manage WebDriver. But all this helps in better code management and maintenance.

In this chapter, we will work towards to get better test results from Selenium test execution. If you want to build a successful test automation solution all you really need is make it reliable and make it fast. The single most important factor that affects both of these goals in web automation is how you wait after each page interaction. Whether you click or hover over a web element, execute a javascript function, or simulate a keypress, it can cause either a page transition or an ajax operation. You would need to wait for this to complete before you can perform the next operation. If you wait too long, it makes the test execution slower than it needs to be. If you don’t wait or wait too little, it manifests as either consistent or intermittent failures.

We all know that selenium test executions sometimes fails some tests intermittently. When you try to fix the issue and try to debug the same scenario, it works perfectly fine. Most of the time it happens because of delay in element loading. Means Selenium tries to perform any action on the element but it is not yet rendered in the DOM.

I know you must be thinking that, then, in this case, Selenium already has a feature which is called as Implicit-wait, which always waits for an element to load and wait for a specified time. Then why do we have such problems in Selenium execution. The answer is because of Ajax Calls or JQuery.

What is Ajax?

AJAX is a technique to do an XMLHttpRequest (out of band Http request) from a web page to the server and send/retrieve data to be used on the web page. AJAX stands for Asynchronous Javascript And XML.

Means: Ajax is way for the client-side browser to communicate with the server (for example: retrieve data from a database) without having to perform a page refresh.

What is JQuery?

JQuery (website) is a javascript framework that makes working with the DOM easier by building lots of high level functionality that can be used to search and interact with the DOM. Part of the functionality of jQuery implements a high-level interface to do AJAX requests.

  • JQuery is a lightweight client side scripting library while AJAX is a combination of technologies used to provide asynchronous data transfer
  • JQuery and AJAX are often used in conjunction with each other
  • JQuery is primarily used to modify data on the screen dynamically and it uses AJAX to retrieve data that it needs without changing the current state of the displayed page

How to check Ajax/JQuery on the Web Page?

This is very important to check that what is actually working on the application for which the tests are written. One easy way is to talk to UI Developers and understand the technology used for developing the web pages. It will always give you an fair idea what you will be dealing with on automation. Second way is to go and find by your self.

In the below example, I will use Chrome Browser and  shop.demo.com website to demonstrate the Ajax calls. To do the same on your end, please follow the steps below.

  1. Go to the website shop.demoqa.com, add any product to basket/bag and reach to checkout page or the final page where you enter personal details and payment details.

  2. Press F12 to open developer mode in chrome and select Console tab from the menu.

  3. Now type jQuery.active in the console editor and press Enter.

Handle Ajax call Using JavaScriptExecutor in Selenium?

Note: You would see that it has returned the value 0. Zero means that at present no ajax or jquery is running on the page.

  1. Lets see if any Ajax actually works on the page or not. Scroll to at the bottom of the page where there is a radio button SHIP TO A DIFFERENT ADDRESS?.

  2. Select Network tab in the Chrome Developer window and click on the last drop down from the right to select the speed of the connection. Select Slow 3G.

Ajax Wait 3

Note: Select Slow 3G would reduce the connection speed and gives you enough time to check things on the page. Because sometimes Ajax calls happen at the speed of the flash.

  1. Come back to Console tab and type jQuery.active, but do not press Enter. Now the next steps is to be done very swiftly, as you wont get much time to do it. You need to click on the check box and immediately come back to Console editor and hit Enter to jQuery.active statement.

Ajax Wait 3

Note: You would notice value 1 this time. One means the ajax is still active on the page.

Yeah cool, isn't it a nice way to find things. Good, now we move forward to catch Ajax calls using JavaScriptExecutor.

Handle Ajax call Using JavaScriptExecutor in Selenium?

Our test will fail tentatively due to these situations. Hence its always wise idea to wait for Ajax call to complete. This can be done using our JavaScriptExecutor interface. The idea is simple, if all the JQuery executions are completed, then it will return jQuery.active == 0 which we can use in our Wait.Until method to wait till the script return as true.

Wait for Ajax call to finish

To understand this chapter you have to learn the concepts discussed in the earlier WebDriver Waits and Smart Waits in Selenium chapter already. Also you shoud understand the Functions and Predicates in Java.

Here is a sample code to showcase the handling of AJAX controls using Selenium Webdriver. You can integrate it in your test execution class.

Boolean isJqueryCallDone = (Boolean)((JavascriptExecutor) driver).executeScript("return jQuery.active==0");

As the above script would return either True or False. But we need to run this code till the time either we get true or the specified time is over. To do that we need to have the Selenium WebDriver Wait, which would provide us untill method.

private static void until(WebDriver driver, Function<WebDriver, Boolean> waitCondition, Long timeoutInSeconds){
		WebDriverWait webDriverWait = new WebDriverWait(driver, timeoutInSeconds);
		webDriverWait.withTimeout(timeoutInSeconds, TimeUnit.SECONDS);
		try{
			webDriverWait.until(waitCondition);
		}catch (Exception e){
			System.out.println(e.getMessage());
		}          
	}

We will create a until method in our new Wait class which will have logic of WebDriverWait inside. This function will take WebDriver and Function<WebDriver, Boolean> as parameter. Function<WebDriver, Boolean> states that it would take driver and return bool. withTimeout will decide how long it will wait for the condition to become true.

Let's write a complete method, which will be called from Page Objects methods and eventually  which will use the above created until method.

public static void untilJqueryIsDone(WebDriver driver, Long timeoutInSeconds){
	until(driver, (d) ->
		{
		Boolean isJqueryCallDone = (Boolean)((JavascriptExecutor) driver).executeScript("return jQuery.active==0");
		if (!isJqueryCallDone) System.out.println("JQuery call is in Progress");
		return isJqueryCallDone;
		}, timeoutInSeconds);
}

In the above, Until method is called, which pass driver and Function as wait condition as parameter. That wait condition is actually our Ajax query.

If it is too much to understand, try to understand from the screenshot below.

Ajax Wait 5

Wait for Page Load using JavaScriptExecutor in Selenium

Generally Selenium WebDriver handles software app's page loading or wait for page to load by It self If you have used Implicit Wait In your software automation test. But many on development sites have a page loading Issues and It Is taking more or less time for page to load on every software test iteration. So some times your test will run without any Issue and some times It will be unable to found some elements due to the page loading Issue.

We can use bellow given java script syntax In our software automation test to check (loading) status of page.

document.readyState

It will return "complete" when page Is loaded completely.

public static void untilPageLoadComplete(WebDriver driver, Long timeoutInSeconds){
		until(driver, (d) ->
			{
				Boolean isPageLoaded = (Boolean)((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
				if (!isPageLoaded) System.out.println("Document is loading");
				return isPageLoaded;
			}, timeoutInSeconds);
	}

This also implemented in the same way. The only change is that this one use document.readyState.

Implement Wait Utility in the Framework

  1. Create a New Package and name it as selenium, by right click on the src/test/java and select New >> Package. As this some what related to Selenium WebDriverWait, I like to call it as selenium package.

  2. Create a New Class and name it as Wait by right click on the above created Package and select New >> Class.

  3. Put above created methods in that file now.

Wait.java

package selenium;

import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import managers.FileReaderManager;


public class Wait {
	
	public static void untilJqueryIsDone(WebDriver driver){
		untilJqueryIsDone(driver, FileReaderManager.getInstance().getConfigReader().getImplicitlyWait());
	}

	public static void untilJqueryIsDone(WebDriver driver, Long timeoutInSeconds){
		until(driver, (d) ->
			{
			Boolean isJqueryCallDone = (Boolean)((JavascriptExecutor) driver).executeScript("return jQuery.active==0");
			if (!isJqueryCallDone) System.out.println("JQuery call is in Progress");
			return isJqueryCallDone;
			}, timeoutInSeconds);
	}
	
	public static void untilPageLoadComplete(WebDriver driver) {
		untilPageLoadComplete(driver, FileReaderManager.getInstance().getConfigReader().getImplicitlyWait());
	}

	public static void untilPageLoadComplete(WebDriver driver, Long timeoutInSeconds){
		until(driver, (d) ->
			{
				Boolean isPageLoaded = (Boolean)((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
				if (!isPageLoaded) System.out.println("Document is loading");
				return isPageLoaded;
			}, timeoutInSeconds);
	}
	
	public static void until(WebDriver driver, Function<WebDriver, Boolean> waitCondition){
		until(driver, waitCondition, FileReaderManager.getInstance().getConfigReader().getImplicitlyWait());
	}

	
	private static void until(WebDriver driver, Function<WebDriver, Boolean> waitCondition, Long timeoutInSeconds){
		WebDriverWait webDriverWait = new WebDriverWait(driver, timeoutInSeconds);
		webDriverWait.withTimeout(timeoutInSeconds, TimeUnit.SECONDS);
		try{
			webDriverWait.until(waitCondition);
		}catch (Exception e){
			System.out.println(e.getMessage());
		}          
	}
	
	
}

Note: You will notice that every method name is used twice in the above class. In programming you can have same method names in a same class, if the parameters are different. Now, lets understand why we did that. There can be possibility that an element takes 20 seconds to load whereas other element takes 90 seconds to load. In this case it is good to open your method to accept the time from the method's user. But, if user is not bothered about the time, then there should not any compulsion to the user to provide the same. So in that case we are setting the timeout by default by our self, which is nothing but the same amount which is specified as Implicit Wait in our property configuration file.

Replace Thread.Sleep in page objects with Wait.untilJqueryIsDone()

We have used lot of Thread.sleep in the code so far, it is the time to replace all with Ajax Wait methods. After changing the code, checkout page object class will look like this:

CheckoutPage.java

package pageObjects;

import java.util.List;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindAll;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;

import selenium.Wait;
import testDataTypes.Customer;

public class CheckoutPage {
	WebDriver driver;
	
	public CheckoutPage(WebDriver driver) {
		this.driver = driver;
	    PageFactory.initElements(driver, this);
	}
	
	@FindBy(how = How.CSS, using = "#billing_first_name") 
	private WebElement txtbx_FirstName;
	
	@FindBy(how = How.CSS, using = "#billing_last_name") 
	private WebElement txtbx_LastName;
	
	@FindBy(how = How.CSS, using = "#billing_email") 
	private WebElement txtbx_Email;
	
	@FindBy(how = How.CSS, using = "#billing_phone") 
	private WebElement txtbx_Phone;
	
	@FindBy(how = How.CSS, using = "#billing_country_field .select2-arrow") 
	private WebElement drpdwn_CountryDropDownArrow;
	
	@FindBy(how = How.CSS, using = "#billing_state_field .select2-arrow") 
	private WebElement drpdwn_CountyDropDownArrow;
	
	@FindAll(@FindBy(how = How.CSS, using = "#select2-drop ul li"))
	private List<WebElement> country_List;	
	
	@FindBy(how = How.CSS, using = "#billing_city") 
	private WebElement txtbx_City;
	
	@FindBy(how = How.CSS, using = "#billing_address_1") 
	private WebElement txtbx_Address;
	
	@FindBy(how = How.CSS, using = "#billing_postcode") 
	private WebElement txtbx_PostCode;
	
	@FindBy(how = How.CSS, using = "#ship-to-different-address-checkbox") 
	private WebElement chkbx_ShipToDifferetAddress;
	
	@FindAll(@FindBy(how = How.CSS, using = "ul.wc_payment_methods li"))
	private List<WebElement> paymentMethod_List;	
	
	@FindBy(how = How.CSS, using = "#terms.input-checkbox") 
	private WebElement chkbx_AcceptTermsAndCondition;
	
	@FindBy(how = How.CSS, using = "#place_order") 
	private WebElement btn_PlaceOrder;
	
	
	public void enter_Name(String name) {
		txtbx_FirstName.sendKeys(name);
	}
	
	public void enter_LastName(String lastName) {
		txtbx_LastName.sendKeys(lastName);
	}

	public void enter_Email(String email) {
		txtbx_Email.sendKeys(email);
	}
	
	public void enter_Phone(String phone) {
		txtbx_Phone.sendKeys(phone);
	}
	
	public void enter_City(String city) {
		txtbx_City.sendKeys(city);
	}
	
	public void enter_Address(String address) {
		txtbx_Address.sendKeys(address);
	}
	
	public void enter_PostCode(String postCode) {
		txtbx_PostCode.sendKeys(postCode);
	}
	
	public void check_ShipToDifferentAddress(boolean value) {
		if(!value) chkbx_ShipToDifferetAddress.click();
		Wait.untilJqueryIsDone(driver);
	}
	
	public void select_Country(String countryName) {
		drpdwn_CountryDropDownArrow.click();
		Wait.untilJqueryIsDone(driver);

		for(WebElement country : country_List){
			if(country.getText().equals(countryName)) {
				country.click();	
				Wait.untilJqueryIsDone(driver);
				break;
			}
		}

	}
	
	public void select_County(String countyName) {
		drpdwn_CountyDropDownArrow.click();
		Wait.untilJqueryIsDone(driver);
		for(WebElement county : country_List){
			if(county.getText().equals(countyName)) {
				county.click();	
				//Wait.untilJqueryIsDone(driver);
				break;
			}
		}
	}
	
	public void select_PaymentMethod(String paymentMethod) {
		if(paymentMethod.equals("CheckPayment")) {
			paymentMethod_List.get(0).click();
		}else if(paymentMethod.equals("Cash")) {
			paymentMethod_List.get(1).click();
		}else {
			new Exception("Payment Method not recognised : " + paymentMethod);
		}
		Wait.untilJqueryIsDone(driver);
		
	}
	
	public void check_TermsAndCondition(boolean value) {
		if(value) chkbx_AcceptTermsAndCondition.click();
	}
	
	public void clickOn_PlaceOrder() {
		btn_PlaceOrder.submit();
		Wait.untilPageLoadComplete(driver);
	}
	
	
	public void fill_PersonalDetails(Customer customer) {
		enter_Name(customer.firstName);
		enter_LastName(customer.lastName);
		enter_Phone(customer.phoneNumber.mob);
		enter_Email(customer.emailAddress);
		enter_City(customer.address.city);
		enter_Address(customer.address.streetAddress);
		enter_PostCode(customer.address.postCode);
		select_Country(customer.address.country);
		select_County(customer.address.county);		
	}

}

Run the Cucumber Test

Run as JUnit

Now we are all set to run the Cucumber test. Right Click on TestRunner class and Click Run As  >> JUnit TestCucumber will run the script the same way it runs in Selenium WebDriver and the result will be shown in the left hand side project explorer window in JUnit tab.

You will notice that after executing all the steps, the execution will come in the hooks and it will execute quitDriver().

Project Explorer

Ajax Wait 5

Advance Webdriver Waits
Advance Webdriver Waits
Previous Article
How to handle multiple windows in Selenium?
How to handle multiple windows in Selenium?
Next Article
Lakshay Sharma
I’M LAKSHAY SHARMA AND I’M A FULL-STACK TEST AUTOMATION ENGINEER. Have passed 16 years playing with automation in mammoth projects like O2 (UK), Sprint (US), TD Bank (CA), Canadian Tire (CA), NHS (UK) & ASOS(UK). Currently, I am working with RABO Bank as a Chapter Lead QA. I am passionate about designing Automation Frameworks that follow OOPS concepts and Design patterns.
Reviewers
Virender Singh's Photo
Virender Singh

Similar Articles

Feedback