4

So, I have an element which is hidden under an alert. Alert stays for 10 secs and the user can click the element after that. Here is my code to deal with this situation:

WebElement create = driver.findElement(By.cssSelector("div.action_menu_trigger"));
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(create));
create.click();

but I get this exception as soon as WebDriver reaches here, seems like Selenium doesn't care about wait method:

org.openqa.selenium.ElementClickInterceptedException:
Element <div class="action_menu_trigger"> is not clickable at point (1710.224952697754,140) because another element <div class="noty_body"> obscures it
Build info: version: '3.13.0', revision: '2f0d292', time: '2018-06-25T15:24:21.231Z'

I have tried by using Thread.sleep(10000) and it works fine but I don't want to use sleep.

Ratmir Asanov
  • 6,237
  • 5
  • 26
  • 40
theGuy
  • 683
  • 5
  • 15
  • hi, Yes, your observation is correct, elementToBeClickable wouldn't do it's Job because of this reason https://stackoverflow.com/questions/51615508/how-to-check-if-100-covered-webelement-is-clickable-with-selenium/51616760#51616760 I have detailed here. – Rajagopalan Aug 02 '18 at 13:49
  • You state there's an alert... do you mean a Javascript alert or an HTML alert? I'm assuming an HTML alert given the error message you receive. A link to the page would help a lot here. – JeffC Aug 02 '18 at 14:26
  • Hi, Here is an another answer which explains what I have been saying https://stackoverflow.com/questions/38327049/check-if-element-is-clickable-in-selenium-java/46315984#46315984 – Rajagopalan Aug 02 '18 at 17:05

4 Answers4

8

The problem here is that the element under the alert IS clickable as far as Selenium knows. It is visible and enabled so it should be clickable. Your code waits for the element to be clickable (assuming it will wait for the alert to disappear) but Selenium already thinks the element is clickable so it attempts a click immediately resulting in the error message because the alert is still up and blocks the click.

The way around this is to wait for the alert to appear then disappear, wait for the element to be clickable, and click it. I don't know that I have all the locators but the code below should get you pointed in the right direction.

// define locators for use later
// this also makes maintenance easier because locators are in one place, see Page Object Model
By alertLocator = By.cssSelector("div.noty_body");
By createLocator = By.cssSelector("div.action_menu_trigger");

// do something that triggers the alert

// wait for the alert to appear and then disappear
WebDriverWait shortWait = new WebDriverWait(driver, 3);
WebDriverWait longWait = new WebDriverWait(driver, 30);
shortWait.until(ExpectedConditions.visibilityOfElementLocated(alertLocator));
longWait.until(ExpectedConditions.invisibilityOfElementLocated(alertLocator));

// now we wait for the desired element to be clickable and click it
shortWait.until(ExpectedConditions.elementToBeClickable(createLocator)).click();
JeffC
  • 22,180
  • 5
  • 32
  • 55
  • 1
    Yes, that's the solution! Exactly! This is the way to solve the problem! ElementToBeClickable doesn't do it's job because they are waiting for element to be enabled! – Rajagopalan Aug 02 '18 at 14:44
  • @Rajagopalan `elementToBeClickable` is working as designed, you just have to take care of the alert first. I've used this before on projects and it works great. – JeffC Aug 02 '18 at 14:45
  • No, it is clearly not! I have detailed here, https://stackoverflow.com/questions/51615508/how-to-check-if-100-covered-webelement-is-clickable-with-selenium/51616760#51616760 If it works as expected, then his problem wouldn't even come into notification, they are checking for element to be enabled, but the problem is, element is enabled even when it's overlayed by other element, so it goes to click but it fails to perform it's operation because elementToBeClickable is not doing it's Job. – Rajagopalan Aug 02 '18 at 14:47
  • @JeffC, thanks. This is a great answer. I have other solutions to my problem (one includes manual dismissing of alert but I am bit hesitant to do that for some reasons) but I am just curious about why my wait method failed in code above. So, what I got from here is that my element is clickable but it is blocked by the alert and that is the reason for this error. – theGuy Aug 02 '18 at 14:51
  • @Rajagopalan If you look at the docs, enabled only really applies to INPUT elements, not regular elements. An element under an alert *IS* enabled... just use JS to click it and you'll see it can be clicked. Enabled/disabled is different than blocked by another element. See [this](https://github.com/seleniumhq/selenium/issues/1348) for some discussion. – JeffC Aug 02 '18 at 14:59
  • @theGuy Correct... the element is actually clickable, it just happens to be under another element that receives the click... thus the error. The way to handle this is to dismiss the alert or wait for it to disappear... then you are free to click the desired element. – JeffC Aug 02 '18 at 15:01
  • @JeffC I know JS would perform the click but webdriver doesn't do because there is a clear checking is inside. I know element is visible and enabled when the particular element is overlay-ed by other element, that's what my main point is. I am trying to tell you, elementToBeClickable is not doing it's job because it's checking whether element is enabled or not, element is clearly enabled even when other element overlays it,so it goes on to perform the action but it fails because webdriver has that checking. Selenium wrongly assume that webdriver can do the click but it's not. – Rajagopalan Aug 02 '18 at 15:04
  • @JeffC : Well , you can create only one instance of webDriverwait and use only `longWait.until(ExpectedConditions.invisibilityOfElementLocated(alertLocator));` , cause it's quite obvious that we are waiting for invisibility . I have tried using only `invisibilityOfElementLocated` in one scenario like this but it did not work , but worked when I used `visibility` followed by `invisibilityOfElementLocated` – cruisepandey Aug 02 '18 at 15:06
  • @Rajagopalan JS clicks on the element directly, going around (under) the alert that covers it. Selenium clicks on top of the element so that it hits the alert because it's designed to interact with the page as a user would. A user can't click the element underneath, so Selenium can't either (technically doesn't, not can't). Everything here is working as designed. You may not like the design but that's a different issue. Feel free to submit an issue on the Selenium github. They will tell you the same thing. :) – JeffC Aug 02 '18 at 15:07
  • @JeffC If it's designed correctly, then it has to wait for elementtobeclickable but OP finds that it's not working because selenium wrongly assume element is ready to be clicked since element is enabled but the selenium is not aware of the truth that there is an another element is overlaying this element, so it commands the webdriver to click the element but webdriver internal checking immediately throws the error, so it's very clear that it's not doing it's job. – Rajagopalan Aug 02 '18 at 15:10
  • 1
    @cruisepandey You can create a single instance of a wait but then all three waits would be for 30s, and that's not necessary and will prolong your test if/when it fails so I created two. What if the alert doesn't come immediately one time? The invisibility check will pass before the alert comes up and a click attempt will happen which might fail because it's blocked by the alert. That's why I wait for visible and then invisible. I'm confused as to what you are stating... my code above has a wait for visible and then invisible... are you saying that's right or wrong? – JeffC Aug 02 '18 at 15:10
  • @Rajagopalan Again... you not liking the design doesn't mean it's not doing it's job. There's no way that Selenium in all cases can determine if there are no elements covering the element you want to click. Because of that, it doesn't try and just does a click. There are other tools in the Selenium toolbox to handle situations like this because there is no one size fits all solution... that's why it's implemented this way. Feel free to log an issue on Selenium so they can explain in more detail although there's probably already an issue for this but I haven't looked. – JeffC Aug 02 '18 at 15:14
  • @JeffC : I am not making any conclusion. All I am saying is when I had this type of scenario , I wrote the code like you have written here , and it worked , But in the same scenario when you remove the visibility , then I have observed some time code works well , some time doesn't. – cruisepandey Aug 02 '18 at 15:14
  • 1
    @cruisepandey Ah... yes, I agree with you. I think having both the visible and invisible wait is necessary to handle all situations. – JeffC Aug 02 '18 at 15:15
  • @JeffC But it's clearly in webdriver, but selenium is unaware of the truth that element is still not ready to be clicked, so elementToBeClicked is clearly not doing it's Job. If not, what's for elementToBeClicked method is implemented? it should have actually been elementToBeEnabled. – Rajagopalan Aug 02 '18 at 15:17
  • 1
    @Rajagopalan The element is ready to be clicked (it's clickable)... it's just under another element. You are oversimplifying the situations that Selenium has to deal with to determine if an element is truly clickable and from that concluding that it's wrong. Elements other than INPUTs are not "enabled" so that check is meaningless most of the time... everything that is visible is clickable using JS. – JeffC Aug 02 '18 at 15:25
  • Whether element is ready to be clicked or not is determined by whether webdriver is able to click or not. If webdriver is not able to click it then it's not ready, whether it's clickable by JS is out of question because that doesn't stimulate the real user, So at some point If webdriver can't stimulate the click then it's not clickable, so selenium has to pave the way for the webdriver like the way it can pave the way for element to become visible, enabled. But it's clearly not. so element is clickable or not is clearly depends on whether webdriver is able to click on it or not. – Rajagopalan Aug 02 '18 at 15:31
  • Another best example would be, when there is an alert you can't click any of the element in the page, so that's why webdriver is not allowing you to click but JS would allow you click, Webdriver is exactly stimulating the real user while JS would not. – Rajagopalan Aug 02 '18 at 15:51
1

Instead of giving web element in elementToBeClickable , just give the locator with css selector.

You are trying to find the element before wait.

So the code would be like this :

create = wait.until(ExpectedConditions.visibilityOfElement(By.cssSelector(“your css selector”)));  
create.click();
cruisepandey
  • 28,520
  • 6
  • 20
  • 38
  • How will that make a difference? – theGuy Aug 02 '18 at 13:26
  • Because he is trying to find the element before using the wait. – cruisepandey Aug 02 '18 at 13:28
  • @Rajagopalan : Well, once he will define the webDriverWait, then selenium will try to fetch the element in every 500ms from the DOM. And after 10 second it will find the element and click it. For a safer side he should give 20, or 30 sec in web driver wait. – cruisepandey Aug 02 '18 at 13:48
  • I agree with @cruisepandey, I made a dumb mistake in the code above. The thing is I use page factory and with that I am giving the locator inside the wait. I just posted above code for my question here in hurry. My original code is as below and it still gives me an error: 'WebDriverWait wait = new WebDriverWait(driver, 20); wait.until(ExpectedConditions.elementToBeClickable(lib.create)); lib.create.click();' where create is @FindBy(css="div.action_menu_trigger") public WebElement create; – theGuy Aug 02 '18 at 13:59
  • @Rajagopalan do you have any reference documentation or Webdriver bug to prove this? – theGuy Aug 02 '18 at 14:02
  • @theGuy Can you please read here The problem is at elementToBeClickable method, it doesn't wait for you as you are expecting, Please read my post here https://stackoverflow.com/questions/51615508/how-to-check-if-100-covered-webelement-is-clickable-with-selenium/51616760#51616760 I have detailed here clearly. – Rajagopalan Aug 02 '18 at 14:03
  • @theGuy why we need a document? They are waiting for the element to be enabled and it's very clear to us that element is enabled even when some other element overlay it. Yes? it's pretty clear. If you don't believe me, just check whether element is enabled or not and also go inside the elementToBeClickabled method to check they are waiting for what(They are waiting for element to be enabled), By doing these two checking you can know for certain. – Rajagopalan Aug 02 '18 at 14:31
  • @theGuy : try with the same code and this time do not use page factory , just put locator like `create = wait.until(ExpectedConditions.visibilityOfElement(By.cssSelector(“div.action_menu_trigger”)));` and check whether it works or not. – cruisepandey Aug 02 '18 at 14:40
  • @Rajagopalan : As we had long discussion on other day , we are looking for visibilityOfElement here and inside of visibilityOfElement we are checking whether element is visible or not by using `return element.isDisplayed() ? element : null;` , So it's an assumption that if it is visible and displayed , then you should be able to click it. If you are digging deeper then note that DIV and SPAN should not meant to be clickable . But still lot of time we click on it , agree ? – cruisepandey Aug 02 '18 at 14:46
  • @cruisepandey You still haven't gotten the idea(not to cause any offenses), Element is visible and enabled even when the required element is overlayed by other element. Are you aware of that? – Rajagopalan Aug 02 '18 at 14:49
  • @Rajagopalan : That's why we have scroll down and up , left , right and actions class to make that particular element visible in UI. As a ideal script writer you should use it and get away with overlying . – cruisepandey Aug 02 '18 at 14:52
  • @cruisepandey Okay, so how would you check? You would scroll the element and then you check whether the element is visible or not, eh? – Rajagopalan Aug 02 '18 at 14:55
  • @Rajagopalan : The way you are doing it manually to avoid overlying. Can be anything – cruisepandey Aug 02 '18 at 14:58
  • @cruisepandey manually you can't do anything, you can click it if there is an alert ,but what would you do if there is a css style which covers it? Actually when we do manually, we would be extremely slow, so problem would not come but program is faster so it would surely throw the error, but you did not answer my question, what would do to check whether the element is clickable or not? You would be checking whether element is visible? – Rajagopalan Aug 02 '18 at 15:00
  • @Rajagopalan : I have been using elementToBeClickable for quite a long period of time. and it works exceptionally well. – cruisepandey Aug 02 '18 at 15:07
  • @cruisepandey Then it's not working in this case, read OP's question once again carefully, he says it's not waiting until element is ready to be clicked. Selenium assumes that element is ready to be clicked so it's asking the webdriver to perform the click but it's not aware of the truth that it's overlayed by another element and that's caught on webdriver internal checking, so it's the failure from selenium side not from the webdriver side. – Rajagopalan Aug 02 '18 at 15:12
  • @cruisepandey Here is an another answer which explains what I have been saying https://stackoverflow.com/questions/38327049/check-if-element-is-clickable-in-selenium-java/46315984#46315984 – Rajagopalan Aug 02 '18 at 17:05
1

You are using WebDriverWait not correctly. This:

WebElement create = driver.findElement(By.cssSelector("div.action_menu_trigger"));
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(create));
create.click();

should be like this:

WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("div.action_menu_trigger"))).click();

As @cruisepandey already mentioned,

WebElement create = driver.findElement(By.cssSelector("div.action_menu_trigger"));

locates the element and after that WebDriverWait has no effect.

EDIT: you can try to use this:

int i = 0;
while (true){
    i++;
    WebElement create = driver.findElement(By.cssSelector("div.action_menu_trigger"));
    try {
        create.click();
        break;
    }catch (Exception e){
        if (i > 30){
            create.click(); // throws exception after 15 sec to prevent infinite loop
        }
        Thread.sleep(500); // pause 0.5 sec
        // try one more time
    }
}
Andrei Suvorkov
  • 5,559
  • 5
  • 22
  • 48
  • I have added information to the answer, please have a look – Andrei Suvorkov Aug 02 '18 at 13:59
  • first question is, Why are you still adding elementToBeClickable method? It wouldn't work as expected, please read here https://stackoverflow.com/questions/51654804/elementtobeclickable-issues-with-selenium-java/51654854?noredirect=1#comment90274657_51654854 I have detailed here, My second question, though your given solution may work, that's not the right way to write the code, because tomorrow If ID changes, then you would be falling into infinite loop, third even your newly written code says to me that you still haven't gotten the problem very correctly. – Rajagopalan Aug 02 '18 at 14:09
  • @Rajagopalan I have edited my code, now it won't fall in infinite loop – Andrei Suvorkov Aug 02 '18 at 14:15
  • Yes, that's the good workaround. But I wouldn't go with this idea. – Rajagopalan Aug 02 '18 at 14:51
1

The "not clickable at point" may be solved by using the Actions object:

WebElement create = driver.findElement(By.cssSelector("div.action_menu_trigger"));
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(create));
Actions actions = new Actions(driver);
actions.moveToElement(create).perform();
actions.click().perform();
AutomatedOwl
  • 1,039
  • 1
  • 8
  • 14
  • The problem is, the method elementToBeClickable doesn't work as you are expecting, the reason I have detailed here, https://stackoverflow.com/questions/51654804/elementtobeclickable-issues-with-selenium-java/51654854?noredirect=1#comment90274657_51654854 – Rajagopalan Aug 02 '18 at 14:11