0

In my Java based Selenium project I have the following method to wait for element availability before clicking it

public void clickVisible(By element){
    wait.until(ExpectedConditions.elementToBeClickable(element));
    wait.until(ExpectedConditions.visibilityOfElementLocated(element));
    driver.findElement(element).click();
}

And generally, in 99.9% cases it works just fine. However sometimes, on some specific elements it still throws exception

org.openqa.selenium.ElementNotInteractableException: element not interactable

So that I have to add some more delay before clicking on that element even after it was detected by Selenium as clickable and visible or to wait for some other element visibility and only after that to validate this element visibility and then click on it.
This actually means that Selenium WebDriverWait ExpectedConditions.elementToBeClickable and ExpectedConditions.visibilityOfElementLocated are not 100% reliable.
All the answers to questions here dealing with ElementNotInteractableException like this or this are suggesting to use ExpectedConditions.visibilityOfElementLocated WebDriver waits but, again, it is still not 100% reliable.
So my question is: is there some more reliable way to ensure element clickability?

Prophet
  • 32,350
  • 22
  • 54
  • 79
  • Nothing is 100% reliable in computer science that's why we have QA and bugs . It depends on UI application also right ? I have experienced that most of the time it is application causes issue too with while it goes under automation – cruisepandey Jun 17 '21 at 15:45
  • Generally I agree with you. Seems like not all the visible and clickable elements are actually clickable... – Prophet Jun 17 '21 at 15:50
  • let's see what we will get in Selenium 4. May be more reliability. – cruisepandey Jun 17 '21 at 15:52

3 Answers3

1

I agree this is annoying. One "solution" I have used a few times is to use actions instead, in your code it would be something like this

public void clickVisible(By element){
    wait.until(ExpectedConditions.elementToBeClickable(element));
    wait.until(ExpectedConditions.visibilityOfElementLocated(element));
    final Actions actions = new Actions(driver);
    actions.moveToElement(driver.findElement(element)).click().perform();
}

It clicks the position of the element, not considering if its interact-able. Maybe it will help.

James Mudd
  • 1,816
  • 1
  • 20
  • 25
1

I regularly have the problem when testing with selenium that the built-in waits are not enough, have spent a lot of time looking in to why, and there are a few ways to try to address that and make the tests stable. But first, let me point out, waiting for an element to be clickable with Selenium is the strongest condition one can use, in other words it will induce the longest wait from any EC.

All the function even does, from the docs, is wait for the element to be visible and enabled. (If you look at the source code you can see, I think I recall correctly, that visible means the element does not have attribute value='hidden', and enabled means it does not have any attribute called disabled.) Anyway, all this to say that your line

    wait.until(ExpectedConditions.elementToBeClickable(element));

has already checked for visibility, so the line that follows it is redundant.

Now to your actual question. I approach the a problem like this usually one of the following ways. The main thought is to figure out what you actually need to wait for before proceeding with your test, and, obviously, wait appropriately.

  1. Since it is throwing ElementNotInteractableException, I think you must try and find out what is actually going on in the app when this happens. Try taking screenshots at this step, and/or logging all or part of the page source to figure out: what is different between runs where your code works, and where it fails? Is there an element covering up your target? If so, maybe you can execute some javascript to get rid of that element. Or, you could wait for that element to NOT be visible. Or, you may find some other condition in the page source that you can wait for to account for this apparent edge case in your tests.

  2. If above doesn't work, Look at the network traffic in your app, again looking for differences between when the test passes and fails. Maybe there is something you can wait for; some request to be made or completed with some status?

  3. If above doesn't work, I start to get to "throw in the towel" stage. See if there is any reasonably short hard-coded wait that, perhaps in combination with other techniques, makes your test pass reliably.

  4. If above doesn't work, implement retry logic, ostensibly for just this single test or failure, to reduce the chance of it impacting your whole run

  5. Finally, if I cannot get any of that to work, the test is intolerably flaky, and it NEEDS to be run, just run the test manually. Some workflows are nearly or actually impossible to automate with Selenium, and at a certain point the effort spent writing and maintaining the code exceeds that which would be required to run the test manually. You also have to accept that some flakiness is inherent with a large amount of Selenium tests running (for most apps anyway), but of course that shouldn't stop your apparently diligent efforts to write the most reliable tests possible.

C. Peck
  • 3,641
  • 3
  • 19
  • 36
  • Finally had a time to read your great answer. And it's really good! First, about your introduction. Let's say some element is currently overlapped by some other element. Will this element recognized by Selenium as clickable? As visible? – Prophet Jun 21 '21 at 17:44
  • As about your suggested solutions - I actually already did what you suggested in the first step (even before reading your answer) and again, I totally agree with all what you wrote, including the order of things. – Prophet Jun 21 '21 at 20:30
0

The ElementNotInteractableException means the Element is present on the HTML DOM, but it is not in a state that can be interacted with. The ElementNotInteractableException occurs due to one of numerous reasons:

Another WebElement may overlay our desired WebElement. The overlay of the web element can be temporary; if so then we can follow the following strategy with WebDriverWait

new WebDriverWait(driver, 10).until(ExpectedConditions
.invisibilityOfElementLocated(By.xpath("element_xpath")));
driver.findElement(By.xpath("element_xpath"))
.click();

new WebDriverWait(driver,10).until(ExpectedConditions
.elementToBeClicable("WebElement xpath")).click();

If the desired web element is permanently overlayed by the other web element then we have cast WebDriver instance with
JavaScriptExecutor to use it

((JavaScriptExecutor)driver).executeScript("argument[0]
.click();",element)
C. Peck
  • 3,641
  • 3
  • 19
  • 36
YaDav MaNish
  • 1,260
  • 2
  • 12
  • 20