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.

date-picker-001

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.

date-picker-002

 

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

DatePicker / Calendar Element:

public class DatePicker {

    private static final String dateFormat = "dd MMM yyyy";

    @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 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
        for (int i = 0; i < diff; 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) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(dateFormat);
        LocalDate dpToDate = LocalDate.parse(date, dtf);
        return dpToDate.getDayOfMonth();
    }

    private long getDateDifferenceInMonths(String date) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(dateFormat);
        LocalDate dpCurDate = LocalDate.parse("01 " + 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.

public class DatePickerPage {

    @Drone
    private WebDriver driver;

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

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

    public void goTo() {
        driver.get("https://jqueryui.com/datepicker/");
    }

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

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

}

TestNG Test:

@RunAsClient
public class DatePickerTest extends Arquillian {

    @Page
    private DatePickerPage datePickerPage;

    @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 Dec 2016",
                "12/01/2016"
            }, {
                "29 Feb 2016",
                "02/29/2016"
            }, {
                "20 Nov 2018",
                "11/20/2018"
            }
        };
    }

}

date-picker-003

Demo:

Summary:

By adding an abstraction layer, we control Calendar/DatePicker, a complex element, like a simple WebElement. Now, I could easily share / export this as a library and share it with others who has similar requirements. I could find any DatePicker/Calendar element by using its locator as I would normally find a WebElement.

@FindBy(id="datepicker")
private DatePicker calendar;

 

Happy Testing & Subscribe ?

 

Share This:

Categories: Arquillian, Articles, Extend WebDriver, Selenium

2 comments