pythonselenium-webdriverselenium-chromedriverwebdriverwebdriverwait

Click intercepted, other element would receive the click. Allow this other element to receive the click


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)


Solution

  • 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.