How to handle jQuery Calendar using Selenium | Automate the Calendar

Handle jQuery Calendar in Selenium

How to handle jQuery Calendar using Selenium | Automate the Calendar

 

How to handle jQuery Calendar using Selenium

Most of the websites contain a datepicker or Calendar field, which is used to select a date. In this tutorial, we will dive deep into how to handle the jquery calendar using selenium. We will create our own methods to manipulate dates and select the date value from jquery calendar, rather than just passing the date value into the datepicker field.

 

Steps to automate jquery calendar

Before writing the code, let’s assume we have the following requirements:

  • Datepicker field can accept a past date and future date.
  • We already have our target date stored in some variable. You can also have your date value stored in excel, database or properties file.
  • By default, our calendar shows the current date.
  • Our calendar can contain two entries for the same day. Refer the following figure to understand what I mean.
  • The format of our Date calendar is MM/DD/YYYY.

 

Handle jQuery Calendar in Selenium
Fig 01: Date 27 occur twice in above calendar
 

Suppose we have to choose 18/07/2019 (target date) and the current date is 19/02/2019, in this case, our target date is of future date and user have to click on Next button 5 times to navigate to July month from February. We will break this one big problem into below smaller modules:

  • Get current date, month and year: We will get this value programmatically.
  • Get the target date, month and year: This will be also extracted programmatically.
  • Get month difference between current and target dates: This value will determine how many times Next or Previous buttons should be pressed.
  • Counter flag: We will set this flag to false if the target date is in the past. The default value of the counter is true.

Firstly, we will manipulate and extract the current and target dates after removing ‘/‘. Basically, we want to get values 18 07 2019 and 19 02 2019 as an integer. We will start with pure java code to get these values.

 

package pkg;

import java.util.Calendar;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

public class SeleniumCalendar {
    
    // target day, month, year
    static int targetDay = 0;
    static int targetMonth = 0;
    static int targetYear = 0;

    // current day, month, year
    static int currentDay = 0;
    static int currentMonth = 0;
    static int currentYear = 0;

    // Difference in target and current month. Target could be a future date or past
    // date
    static int differenceInMonths = 0;

    // counter to track if the target date is future or past date
    static boolean counter = true;

    public static void main(String[] args) {
        
        String rawTargetDate = "31/08/2019";

        // get current date
        getCurrentDateMonthYear();
        System.out.println(currentDay + " " + currentMonth + " " + currentYear);

        // get target date 
        getTargetDateMonthYear(rawTargetDate);
        System.out.println(targetDay + " " + targetMonth + " " + targetYear);

        // get the month difference 
        calculateDifferenceInMonths();
        System.out.println(differenceInMonths);
        System.out.println(counter);    

    }

    public static void getCurrentDateMonthYear() {
        Calendar cal = Calendar.getInstance();
        currentDay = cal.get(Calendar.DAY_OF_MONTH);
        currentMonth = cal.get(Calendar.MONTH) + 1;
        currentYear = cal.get(Calendar.YEAR);
    }

    public static void getTargetDateMonthYear(String rawString) {
        // Breaking the date 18/02/2019 to get only values
        int firstIndex = rawString.indexOf("/");
        // get the positions where the two / are present
        int lastIndex = rawString.lastIndexOf("/");

        String day = rawString.substring(0, firstIndex);
        targetDay = Integer.parseInt(day);

        String month = rawString.substring(firstIndex + 1, lastIndex);
        targetMonth = Integer.parseInt(month);

        String year = rawString.substring(lastIndex + 1, rawString.length());
        targetYear = Integer.parseInt(year);
    }

    public static void calculateDifferenceInMonths() {
        if ((targetMonth - currentMonth) > 0) {
            differenceInMonths = targetMonth - currentMonth;
        } else {
            differenceInMonths = currentMonth - targetMonth;
            counter = false;
        }
    }

}

 

We started with the initialization of date, month and year for both current and target year. We also initialized the difference in months (the number of times next or previous buttons should be pressed) and counter (to track whether Next or Previous button should be clicked).

 

 

getCurrentDateMonthYear() will give the current day, month and year value. We have used Java’s inbuilt Gregorian Calendar class to get these values. This inbuilt method returns the MONTH value one less than actual, hence we have added 1 to it. 

 

In getTargetDateMonthYear(), we first identified the position of unwanted character ‘/’ and assigned these positions to variables firstIndex and lastIndexNext, we used substring methods to get the values before and after ‘/’. 

 

Once we have segregated the current and target date values, calculateDifferenceInMonths() will determine the number of clicks required to navigate to the target date. This method will also change the counter flag value to false if the target month is of past date. Further, we will see how this counter value will be used to either click on the Next or Previous button.

 

Once we are done with the above logic, the next step is to automate the calendar using Selenium.

 

//Start with Selenium scripting
        System.setProperty("webdriver.chrome.driver", "/home/dhawal/Downloads/chromedriver/chromedriver");
        WebDriver driver = new ChromeDriver();
    
        //driver.get("https://jqueryui.com/datepicker/");
        driver.get("http://jqueryui.com/resources/demos/datepicker/other-months.html");
        driver.manage().timeouts().implicitlyWait(10L, TimeUnit.SECONDS);
        driver.manage().window().maximize();
        driver.findElement(By.id("datepicker")).click();
            
        //click on either increment or decrement icon of calendar 'differenceInMonths' number of times
        for(int clickOnIcon = 0; clickOnIcon < differenceInMonths; clickOnIcon++) {
            //if the counter value is true, click on increment icon else click on decrement icon
            if (counter) {
                driver.findElement(By.xpath("//a[@title='Next']")).click();
            }else {
                driver.findElement(By.xpath("//a[@title='Prev']")).click();
            }
        }

 

You must already be aware of what the first few lines of code will do. After clicking on the datepicker field, use for-loop to click next or previous buttons differenceInMonths number of times. Inside this for-loop check for the counter flag value. If the value is true click on Next else click on Previous.

 

If you run the above code, it will navigate you to the target calendar. The final step is to click on the day. In Fig01, you have already seen that the day values could be duplicate, but not more than 2 and in such scenario, we have to select 2nd value as it represents the target day.

 

Handle jQuery Calendar in Selenium

 

Upon inspecting the calendar, we found that the day is in the form of link text. In almost all cases the jquery calendar consists of link text. Since the days could be duplicate but not more than 2 and it is a link text, we will use the findElements method of selenium and store it in a List. If the list has a size of 2, then we will click on 2nd element else we will click on the 1st element. Following code snippet take care of duplicate days scenario:

//This will handle the duplicity of Date value
        List<WebElement> days = driver.findElements(By.linkText(Integer.toString(targetDay)));
        if(days.size() == 2) {
            days.get(1).click();
        }else {
            days.get(0).click();
        }

 

Complete code to handle the jquery calendar using selenium is:

package pkg;

import java.util.Calendar;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

public class SeleniumCalendar {
    
    // target day, month, year
    static int targetDay = 0;
    static int targetMonth = 0;
    static int targetYear = 0;

    // current day, month, year
    static int currentDay = 0;
    static int currentMonth = 0;
    static int currentYear = 0;

    // Difference in target and current month. Target could be a future date or past
    // date
    static int differenceInMonths = 0;

    // counter to track if the target date is future or past date
    static boolean counter = true;

    public static void main(String[] args) {
        
        String rawTargetDate = "31/08/2019";

        // get current date
        getCurrentDateMonthYear();
        System.out.println(currentDay + " " + currentMonth + " " + currentYear);

        // get target date 
        getTargetDateMonthYear(rawTargetDate);
        System.out.println(targetDay + " " + targetMonth + " " + targetYear);

        // get the month difference 
        calculateDifferenceInMonths();
        System.out.println(differenceInMonths);
        System.out.println(counter);
        
        //Start with Selenium scripting
        System.setProperty("webdriver.chrome.driver", "/home/dhawal/Downloads/chromedriver/chromedriver");
        WebDriver driver = new ChromeDriver();
    
        //driver.get("https://jqueryui.com/datepicker/");
        driver.get("http://jqueryui.com/resources/demos/datepicker/other-months.html");
        driver.manage().timeouts().implicitlyWait(10L, TimeUnit.SECONDS);
        driver.manage().window().maximize();
        driver.findElement(By.id("datepicker")).click();
            
        //click on either increment or decrement icon of calendar 'differenceInMonths' number of times
        for(int clickOnIcon = 0; clickOnIcon < differenceInMonths; clickOnIcon++) {
            //if the counter value is true, click on increment icon else click on decrement icon
            if (counter) {
                //driver.findElement(By.xpath("//a[@title='Next']")).click();
                driver.findElement(By.xpath("//a[@title='Next']")).click();
            }else {
                //driver.findElement(By.xpath("//a[@title='Prev']")).click();
                driver.findElement(By.xpath("//a[@title='Prev']")).click();
            }
        }
        
        //This will handle the duplicity of Date value
        List<WebElement> days = driver.findElements(By.linkText(Integer.toString(targetDay)));
        if(days.size() == 2) {
            days.get(1).click();
        }else {
            days.get(0).click();
        }
        

    }

    public static void getCurrentDateMonthYear() {
        Calendar cal = Calendar.getInstance();
        currentDay = cal.get(Calendar.DAY_OF_MONTH);
        currentMonth = cal.get(Calendar.MONTH) + 1;
        currentYear = cal.get(Calendar.YEAR);
    }

    public static void getTargetDateMonthYear(String rawString) {
        // Breaking the date 18/02/2019 to get only values
        int firstIndex = rawString.indexOf("/");
        // get the positions where the two / are present
        int lastIndex = rawString.lastIndexOf("/");

        String day = rawString.substring(0, firstIndex);
        targetDay = Integer.parseInt(day);

        String month = rawString.substring(firstIndex + 1, lastIndex);
        targetMonth = Integer.parseInt(month);

        String year = rawString.substring(lastIndex + 1, rawString.length());
        targetYear = Integer.parseInt(year);
    }

    public static void calculateDifferenceInMonths() {
        if ((targetMonth - currentMonth) > 0) {
            differenceInMonths = targetMonth - currentMonth;
        } else {
            differenceInMonths = currentMonth - targetMonth;
            counter = false;
        }
    }

}

Above code will work just fine if the current date and target date fall in the same calendar year. Try to update the above code and make it compliant if the user has entered a target date which is not of the current calendar.

 

Author: Dhawal Joshi

A post-graduate in MCA, ISTQB & ITIL certified QA with more than 8 years of experience in QA working with a CMMI Level 5 organization as System Analyst. I started my automation journey with HP UFT(formerly known as QTP) and for the past few years, I am using Selenium for automation. I also have experience in Android Application Development, Java, HTML, and VBScript. When I am not working, I like to spend time with my family, cooking and learning new developments in IT.

Leave a Reply

Your email address will not be published. Required fields are marked *