Tag Archives: webelement

waiter2: Clicking on page elements

Clicking on a page element is easy to do, however sometimes this action might fail. This can be either because the element we want to click is not yet present on the page, or is not visible, or does not yet allow interactions. To help make sure the click succeeds, here are my dedicated wait based click methods.

Clicking a page element: click

There are 4 methods for clicking on a page element in the ‘waiter2’ library: 2 of them take the timeout parameter, 2 don’t. Additionally, 2 of them take a WebElement (defined with @FindBy) as parameter, 2 take a By variable:

public void click(WebElement elementToClick)
public void click(WebElement elementToClick, int specificTimeout)
public void click(By selectorForElementToClick)
public void click(By selectorForElementToClick, int specificTimeout) 

It is worth mentioning that there will never be a ‘waitForElementToBeDisplayed’ method in the library, simply because it is not needed. For example, when trying to click on a page element, there is no need to wait for it to be displayed before clicking. The logic inside the ‘click’ method from ‘waiter2’ retries clicking the element any time an Exception is encountered. If the element would not be present, the NoSuchElementException would be thrown for each click, until it either is displayed, or the timeout value has elapsed. Similarly, if the page element were present but not visible, or not clickable, the click action is tried until it succeeds or the timeout elapses. Any Exception that can be encountered while clicking is treated the same, because the generic ‘Exception’ is checked for and treated.

So basically, calling the click method while the element to be clicked is not yet ready, but in the process of being ready, will reliably click on it (given it loads within the specified timeout).

In case the element is not clickable for any reason within the specified timeout, a RunTimeException is thrown, with the message:

"waiter2.FAILURE: Could not successfully click on '" + elementToClick + "' within "
        + specificTimeout + " seconds."

The provided selector will be displayed, so that the tester knows what selector was looked for. This helps debug the failure.

Since version: 1.0

The code

The ‘click’ method variants that take a WebElement as parameter are:

public void click(WebElement elementToClick) {
    click(elementToClick, TIMEOUT);
}
public void click(WebElement elementToClick, int specificTimeout) {
    WebDriverWait wait = new WebDriverWait(driver,
            Duration.ofSeconds(specificTimeout));
    try {
        ExpectedCondition<Boolean> condition = arg -> {
            try {
                elementToClick.click();
                return true;
            } catch (Exception e) {
                return false;
            }
        };
        wait.until(condition);
    }
    catch (TimeoutException e) {
        throw new RuntimeException("waiter2.FAILURE: Could not successfully click on '" + elementToClick + "' within "
                + specificTimeout + " seconds.");
    }
}

The ‘click’ method variants that take a By as parameter are:

public void click(By selectorForElementToClick) {
    click(selectorForElementToClick, TIMEOUT);
}
public void click(By selectorForElementToClick, int specificTimeout) {
    WebDriverWait wait = new WebDriverWait(driver,
            Duration.ofSeconds(specificTimeout));
    try {
        ExpectedCondition<Boolean> condition = arg -> {
            try {
                driver.findElement(selectorForElementToClick).click();
                return true;
            } catch (Exception e) {
                return false;
            }
        };
        wait.until(condition);
    }
    catch (TimeoutException e) {
        throw new RuntimeException("waiter2.FAILURE: Could not successfully click on '" + selectorForElementToClick + "' within "
                + specificTimeout + " seconds.");
    }
}

Usage examples

The best usage for the ‘click’ method would be: providing a WebElement defined in a page object class with an @FindBy annotation. For example, for a page on which there is a button to click, whose id is “buttonToClick”, the corresponding WebElement is:

@FindBy(id = "buttonToClick") public WebElement buttonToClick;

Don’t forget that as per the setup, you need to do a PageFactory.initElements before using the WebElement. In the test, in order to click on this page element, you would just need to pass the WebElement as parameter to the ‘click’ method (shown here with the default timeout value):

waiter.click(page.buttonToClick);

In case you cannot create the WebElement through the @FindBy annotation, because it gets generated dynamically in the test, you can pass a By variable to the ‘click’ method. There are 2 ways you can do that: either by creating a By variable somewhere in the test and passing it to the method once it has the correct value. Or by creating a String variable somewhere in the test that represents the selector, then passing it to a By.yourSelectorType once it gets assigned the correct value. Below are some examples for the same button as above.

If you want to create a By variable, it would look like the following one (here obviously it represents an id):

By byForButtonToClick = By.id("buttonToClick");

You can now use it in the ‘click’ method:

waiter.click(byForButtonToClick);

If instead you want to create a variable only for the String representing a selector:

String selectorForButtonToClick = "buttonToClick";

Then, to click the corresponding element:

waiter.click(By.id(selectorForButtonToClick));

Note1: If the selector value is static (it is always the same), use the @FindBy approach. Only use the By approach if you cannot use the @FindBy one, due to not knowing at the beginning of the test what the selector will be (as it gets generated along the way).

Note 2: If you are using the By or the corresponding String only to click that item once, and not anywhere else in the test, DO NOT create a separate variable to store these. Just pass them inline, directly into the ‘click’ method, like, for example:

waiter.click(By.id("buttonToClick"));

In case the element specified with @FindBy cannot be clicked due to any reason within the specified timeout, the following RunTimeException is thrown:

java.lang.RuntimeException: waiter2.FAILURE: Could not successfully click on 'Proxy element for: DefaultElementLocator 'By.cssSelector: nonExistentElement'' within 30 seconds.

In case the element specified with By cannot be clicked on due to any reason within the specified timeout, the following RunTimeException is thrown:

java.lang.RuntimeException: waiter2.FAILURE: Could not successfully click on 'By.cssSelector: nonExistentElement' within 30 seconds.

Incorrect usage!

Never do the following:

WebElement buttonToClick = driver.findElement(By.id("buttonToClick"));
waiter.click(buttonToClick);

Why? Because if the button to click is not displayed when the ‘findElement’ method runs, the test fails at that step, and the ‘click’ method never executes.

So that’s it for clicking on page elements, which of course, include more than just a button. The test code can be found here. Next up i will discuss some further useful methods, so stay tuned!

The weird true story of Selenium, the StaleElementReferenceException, the iframe, the List and the WebElement

I write a lot of automated tests. Most of the times, it all goes nice and smooth, like a good song. But once in a while i run into an automation situation that leaves me completely baffled. Debugging does not reveal how to fix it, and it is not very obvious to me what is going on. When do i realize what the issue was, i’m like ‘WOW i did not expect that’. These kind of stories are good to share, so that you know what to expect, should you encounter the same behavior. So, here is the peculiar, true story of Selenium, the StaleElementReferenceException, the iframe, the List and the WebElement. Continue reading The weird true story of Selenium, the StaleElementReferenceException, the iframe, the List and the WebElement

Selenium: How to wait for an element to be displayed / not displayed

In my previous post i talked about how to check whether an element is displayed or not. There are times when tests where such an action is performed fail randomly (sometimes they will pass, other times they won’t). The assumption here is that the element was not displayed within a decent amount of time when there were test failures, but would have appeared later on. Therefore if the test would have waited a little bit before performing the presence check, it would have passed. Continue reading Selenium: How to wait for an element to be displayed / not displayed