selenium webdriver – Can’t Select random months dates using jquery calender

Datepickers are really slow and tedious to interact with. As Kate Paulk and lauda suggest, it may be worth trying to bypass this by just filling text into the field instead of using the interface if you’re not testing the datepicker itself.

If you really need to test the datepicker I would suggest a simple loop that figures out which direction it needs to move in based on the current month. Without seeing the actual datepicker you’re trying to automate, this is just a vague suggestion rather than something you can just copy and paste in. This will be incredibly slow and should only ever be used sparingly.

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

import java.time.LocalDate;
import java.time.Month;

public class DatePicker {
    private WebDriver driver;

    public DatePicker(WebDriver driver) {
        this.driver = driver;
    }

    public void selectDate(LocalDate date) throws InterruptedException {
        boolean monthFound = false;
        int maxAttempts = 100;
        int attempts = 0;
        int currentlySelectedMonth;
        int currentlySelectedYear;

        while (!monthFound && attempts++ < maxAttempts) {
            currentlySelectedMonth = getCurrentlySelectedMonth();
            currentlySelectedYear = getCurrentYear();

            // Make sure we move to the correct year first
            if(currentlySelectedYear != date.getYear()) {
                if(currentlySelectedYear > date.getYear()) {
                    clickPreviousMonth();
                } else {
                    clickNextMonth();
                }

                continue;
            }

            if (currentlySelectedMonth == date.getMonthValue()) {
                clickDay(date.getDayOfMonth());
                break;
            } else {

                // Which direction do we need to move?
                if (currentlySelectedMonth > date.getMonthValue()) {
                    clickPreviousMonth();
                } else {
                    clickNextMonth();
                    Thread.sleep(250); // Quick sleep to give the UI a chance to update, you probably want something smarter
                }
            }
        }
    }

    private void clickNextMonth() {
        driver.findElement(By.xpath("//a[@title="Next"]")).click();
    }

    private void clickPreviousMonth() {
        driver.findElement(By.xpath("//a[@title="Prev"]")).click();
    }

    private int getCurrentlySelectedMonth() {
        String monthName = driver.findElement(By.className("ui-datepicker-month")).getText();
        return Month.valueOf(monthName.toUpperCase()).getValue();
    }

    private int getCurrentYear() {
        return Integer.valueOf(
                driver.findElement(By.className("ui-datepicker-year")).getText()
        );
    }

    private void clickDay(int dayNumber) {
        driver.findElement(By.linkText(String.valueOf(dayNumber))).click();
    }

}

and a test case from a publicly available demo of jquery datepicker:

import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.LocalDate;

public class QuickTest {

    @Test
    public void datePickerTest() throws InterruptedException {
        System.setProperty("webdriver.chrome.driver", System.getProperty("user.home") + "/Downloads/chromedriver");
        WebDriver driver = new ChromeDriver();
        DatePicker datePicker = new DatePicker(driver);

        driver.get("https://jqueryui.com/datepicker/#default");
        WebElement frame = driver.findElement(By.className("demo-frame"));
        driver.switchTo().frame(frame);

        WebDriverWait wait = new WebDriverWait(driver, 30);

        wait.until(ExpectedConditions.presenceOfElementLocated(By.id("datepicker")));
        driver.findElement(By.id("datepicker")).click();

        datePicker.selectDate(LocalDate.now().plusMonths(24).minusDays(5));
    }

}

The testcase will sometimes stale reference on locating the field to click, but that’s something you can easily fix on a real implementation of this. Not worth fixing for this demo.

Turns out it’s not that slow, but still preferable to skip this if you’re just wanting a date to be filled out.

Leave a Comment