Site icon Vinsguru

Selenium WebDriver – How To Automate DatePicker

Overview:

We already have seen automating below complex controls.

In this article, we will see how we could automate Calendar / DatePicker.

Goal:

To model a wrapper element for the DatePicker / Calendar. So that user can identify the datepicker field as any other field by the locator and select any given date without injecting Javascript.

Injecting Javascript might be very easy. But that is not right way to automate as it could potentially miss some issues. It might not trigger any associated events.

My use case would be to select any given date in the DatePicker/Calendar field as shown below.

DatePicker.setDate("01 Jan 2018");
DatePicker.setDate("29 Feb 2012");

JQuery DatePicker:

All the below elements make the DatePicker element.

 

Lets come up with a wrapper with all the WebElements which looks like Calendar.

DatePicker / Calendar Element:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.LongStream;

public class DatePicker {

    private static final String DATE_FORMAT = "dd MMMM yyyy";
    private static final String DAY_FIRST = "01";
    private static final String SPACE = " ";
    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern(DATE_FORMAT);

    @FindBy(css = "a.ui-datepicker-prev")
    private WebElement prev;

    @FindBy(css = "a.ui-datepicker-next")
    private WebElement next;

    @FindBy(css = "div.ui-datepicker-title")
    private WebElement curDate;

    @FindBy(css = "a.ui-state-default")
    private List< WebElement > dates;

    public DatePicker(final WebDriver driver){
        PageFactory.initElements(driver, this);
    }

    public void setDate(String date) {

        long diff = this.getDateDifferenceInMonths(date);
        int day = this.getDay(date);

        WebElement arrow = (diff >= 0 ? next : prev);
        diff = Math.abs(diff);

        //click the arrows
        LongStream.range(0, diff)
                .forEach(i -> arrow.click());

        //select the date
        dates.stream()
                .filter(ele -> Integer.parseInt(ele.getText()) == day)
                .findFirst()
                .ifPresent(ele -> ele.click());
    }

    private int getDay(String date) {
        LocalDate dpToDate = LocalDate.parse(date, DTF);
        return dpToDate.getDayOfMonth();
    }

    private long getDateDifferenceInMonths(String date) {
        LocalDate dpCurDate = LocalDate.parse(DAY_FIRST + SPACE + this.getCurrentMonthFromDatePicker(), DTF);
        LocalDate dpToDate = LocalDate.parse(date, DTF);
        return YearMonth.from(dpCurDate).until(dpToDate, ChronoUnit.MONTHS);
    }

    private String getCurrentMonthFromDatePicker() {
        return this.curDate.getText();
    }

}

Page Object:

By using above DatePicker, I could find the date picker element – like locating a regular WebElement.

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class DatePickerPage {

    private final WebDriver driver;

    @FindBy(id = "datepicker")
    private WebElement dateField;

    @FindBy(id = "ui-datepicker-div")
    private DatePicker datePicker;

    public DatePickerPage(final WebDriver driver){
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }

    public void goTo() {
        driver.get("https://jqueryui.com/datepicker/");
        this.driver.switchTo().frame(0);
        this.datePicker = new DatePicker(driver);
    }

    public DatePicker getDatePicker() {
        dateField.click();
        return datePicker;
    }

    public String getSelectedDate() {
        return this.dateField.getAttribute("value");
    }
    
}

TestNG Test:

This is my TestNG test to demo the data picker.

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class DatePickerTest {

    private DatePickerPage datePickerPage;
    private WebDriver driver;

    @BeforeTest
    public void setupDriver() {
        this.driver = new ChromeDriver();
        this.datePickerPage = new DatePickerPage(driver);
    }

    @Test(dataProvider = "inputDates")
    public void dateTest(String ipDate, String opDate) {
        datePickerPage.goTo();
        datePickerPage.getDatePicker().setDate(ipDate);
        Assert.assertEquals(datePickerPage.getSelectedDate(), opDate);
    }

    @DataProvider(name = "inputDates")
    public static Object[][] getDates() {
        return new Object[][]
        {
            {
                    "25 May 2017",
                    "05/25/2017"
            },
            {
                    "01 December 2016",
                    "12/01/2016"
            },
            {
                    "29 February 2016",
                    "02/29/2016"
            },
            {
                    "20 November 2020",
                    "11/20/2020"
            }
        };
    }

}

 

Demo:

Summary:

By adding an abstraction layer, we control Calendar/DatePicker, a complex element, like a simple WebElement.

Happy Testing & Subscribe ?

 

Share This:

Exit mobile version