1

Goal:

I want to click the body by below code ;

WebDriverWait(driver,1).until(EC.element_to_be_clickable((By.XPATH, '//body'))).click()

Problem :

My solution needs to be flexible and in case that there is an overlay the click gets intercepted and it throws an error ;

Message: element click intercepted: Element <body>...</body> is not clickable at point (502, 337). 
Other element would receive the click: <div class="_4xvap4u"></div>

Question :

I searched for ages how to achieve to "allow the click" and in this case click the other element which the error displays.

So instead of my orginal click (body) i want to continue in case it's intercepted and click the element thats overlays the body (div / iframe which the error displays). I need this to be flexible so whatever is overlaying and would receive the click (div / iframe /modal / etc)

r-d-r-b-3
  • 325
  • 2
  • 11

1 Answers1

1

In this scenario, a regular selenium click is going to throw that exception if there's an overlay, but you can execute JS from selenium to get around that issue. How to simulate a click with JavaScript?

css_selector = "body"
script = (
    """var simulateClick = function (elem) {
           var evt = new MouseEvent('click', {
               bubbles: true,
               cancelable: true,
               view: window
           });
           var canceled = !elem.dispatchEvent(evt);
       };
       var someLink = document.querySelector('%s');
       simulateClick(someLink);"""
    % css_selector
)
driver.execute_script(script)

(If your css_selector contains quotes, you may need to escape them first, such as with re.escape(CSS_SELECTOR), before running that.)

And if you're looking for an easier way to do a JS click within selenium, there's a Python Selenium framework, https://github.com/seleniumbase/SeleniumBase, which already has a method for that: self.js_click("SELECTOR").


If it's always the same element overlay, you can click it first with an if statement if visible.

def is_element_visible(selector, by="css selector"):
    try:
        element = driver.find_element(by, selector)
        if element.is_displayed():
            return True
    except Exception:
        pass
    return False

if is_element_visible("div._4xvap4u"):
    driver.find_element("css selector", "div._4xvap4u").click()

WebDriverWait(driver,1).until(EC.element_to_be_clickable((By.XPATH, '//body'))).click()

If that selector is not guaranteed to be unique from the exception message Other element would receive the click: <div class="_4xvap4u"></div>, then it makes for a good feature request to https://github.com/SeleniumHQ/selenium. But if it is guaranteed to be a unique selector, you could parse it out and then click it.

Michael Mintz
  • 9,007
  • 6
  • 31
  • 48
  • Thanks for your answer I do know how to execute the click on the body by javascript and that this would be a workaround to click on the exact element i want no matter if there is an overlay or not. BUT this is not what i want, in case there is an exception and an other element would receive the click i want to continue and allow this "redirected click" to the overlaying element which the error mentions that would receive the click. – r-d-r-b-3 Sep 29 '22 at 20:57
  • So in case body has an overlay / modal / iframe / whatever and an error would raise which says another element would receive the click in this case the overlay / modal / iframe / etc. I want it to allow and click on that overlaying element. – r-d-r-b-3 Sep 29 '22 at 21:00
  • Is the overlay a unique element, or is it different each time? If it's the same, you could add an ``if`` statement to click that first if it's visible, and then click on the main element. – Michael Mintz Sep 29 '22 at 21:01
  • It needs to be flexible the error always displays the element that overlays and therefor would receive the click. I just want to continue and click that element. – r-d-r-b-3 Sep 29 '22 at 21:02
  • From my code : Other element would receive the click:
    All i want is to continue and allow this "other element from error receive the click" in this case
    – r-d-r-b-3 Sep 29 '22 at 21:03
  • I can think of a solution but there must be something more clean and simpler to that. I can always catch the error, filter the error string to get the element that would receive the click. And after that click it. – r-d-r-b-3 Sep 29 '22 at 21:05
  • I added to the solution. Use the ``if`` to click the overlay first if it's there. – Michael Mintz Sep 29 '22 at 21:11
  • Thank you so much for your help but I already know all of this. My problem is that the overlay which needs to receive the click is always different. Sometimes div like your example, sometimes modal, sometimes iframe. Thats why I wrote in my question it needs to be flexible. – r-d-r-b-3 Sep 29 '22 at 22:13
  • I can try to catch the exception of click body and if there is one I now know there is an overlay. But how can i program / get the output the error gives me which other element would receive the click ? After I have that I element can .click() it. – r-d-r-b-3 Sep 29 '22 at 22:16
  • That sounds like a good feature request for https://github.com/SeleniumHQ/selenium - A method that would return the overlay element if it exists, or None if there's no overlay. – Michael Mintz Sep 29 '22 at 22:22
  • Does that mean it's impossible what Im trying to achieve ? – r-d-r-b-3 Sep 29 '22 at 22:23
  • That depends. Do you know if ``Other element would receive the click:
    `` provides a unique selector for what needs to be clicked? If yes, then it's possible to extract it and click it. If it's not guaranteed to be unique, then it makes a good feature request.
    – Michael Mintz Sep 29 '22 at 22:28
  • 1
    It's always different and has no unique xpath, css selector etc. I think the answer to my question is that it's impossible which I find very strange when they output such nice details in the error. Anyway I cant thank you enough for your efforts, hero of the day :-) – r-d-r-b-3 Sep 29 '22 at 22:32
  • 1
    Can you add this to your answer so i can accept it so your effort was not for nothing =) – r-d-r-b-3 Sep 29 '22 at 22:43
  • I updated the solution with that. – Michael Mintz Sep 29 '22 at 22:51