Run '$x("XPath")' in Selenium 'driver.execute_script' JavaScript, chromedriver=111.0.5563.64

Question:

On facebook, if I go to main page, and run in chrome dev tools this command:

$x('//span[contains(text(), "Marketplace")]')[0].click()

it works well.

If I try in Python/Selenium:

    driver.execute_script("""
    $x('//span[contains(text(), "Marketplace")]')[0].click()
    """)

I get:

selenium.common.exceptions.JavascriptException: Message: javascript error: $x is not defined
  (Session info: chrome=111.0.5563.64)

If I use:

marketplace_button = self.driver.find_element(By.XPATH, '//span[contains(text(), "Marketplace")]')
marketplace_button.click()

I get:

selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element <span class="x1lliihq x6ikm8r x10wlt62 x1n2onr6" style="-webkit-box-orient:vertical;-webkit-line-clamp:2;display:-webkit-box">...</span> is not clickable at point (204, 306). Other element would receive the click: <div class="x1uvtmcs x4k7w5x x1h91t0o x1beo9mf xaigb6o x12ejxvf x3igimt xarpa2k xedcshv x1lytzrv x1t2pt76 x7ja8zs x1n2onr6 x1qrby5j x1jfb8zj" tabindex="-1">...</div>

What I missed?

Maybe it’s because I have a ‘show me notification?’ popup that I try to bypass (not working) with:

options = webdriver.ChromeOptions()
options.add_experimental_option(
    "prefs",
    {
        "credentials_enable_service": False,
        "profile.password_manager_enabled": False,
        "profile.default_content_setting_values.notifications": 2
    },
)
options.add_argument('--disable-notifications')
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
options.add_argument("--password-store=basic")
options.add_argument("--disable-infobars")
options.add_argument("--disable-extensions")
options.add_argument("start-maximized")

fb

Answers:

Sometimes it takes few seconds for page to load completely and desired element to be in a clickable state, if that is the case, applying waits will help. Try the below code:

marketplace_button = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, '//span[contains(text(), "Marketplace")]')))
marketplace_button.click()

Update: If just applying waits also doesn’t help, then try to perform click() using java script, try the below code:

marketplace_button = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, '//span[contains(text(), "Marketplace")]')))
driver.execute_script("arguments[0].click();", marketplace_button)

Explanation to why JS click() works and the regular click() doesn’t:
marketplace_button.click() – this will imitate a human click on browser. As the error message is not clickable at point (204, 306) suggests, selenium couldn’t click on the button as some other element was intercepting it. On the other hand, JS(driver.execute_script("arguments[0].click();", marketplace_button)) will do the action of clicking directly via DOM, its like clicking the button from backend where obviously nothing will intercept. Hence, JS click() works and the canonical one doesn’t. Having said that, keep in mind, using JS to perform action is not the best of practice. This is because it will fail the purpose of automation testing which will emulate human interaction. Hope this helps.

Answered By: Shawn

$x() and the like are just dev console shortcuts implemented in common browsers. It’s not actually a JavaScript command.

The reason you are getting ElementClickInterceptedException is explained in the error message.

Message: element click intercepted:
   Element <span...>...</span> is not clickable at point (204, 306).
   Other element would receive the click: <div ...>...</div>

There is a DIV element (see your full error message for more info) that is covering/overlaying the SPAN you are trying to click. Without seeing the page, it’s hard for me to say. Some common instances are popup dialogs, transient popups/toasts, floating navigation areas, floating header/footer, etc.

How to fix the issue depends on what element(s) are blocking…

  • if it’s under a permanent popup, close it

    You’ll need to locate the close element (usually an ‘X’ or ‘Close’ button) of the popup and click it to close the popup.

  • if it’s under a transient popup, wait for the popup to become invisible

    Find an element that is the container for the popup and put the locator in the code below:

     new WebDriverWait(driver, 10).until(EC.invisibility_of_element_located(...))
    
  • if it’s under floating elements, you’ll need to scroll the desired element out from underneath it.

    This will depend on the position of the floating element vs the desired element. .scrollIntoView() will scroll the provided element to the top of the page.

     driver.execute_script("arguments[0].scrollIntoView();", element)
    

    While

     driver.execute_script("arguments[0].scrollIntoView(false);", element)
    

    will scroll the element to the bottom of the page. I would expect that at least one of those should work.

After you take care of the covering element, you should be able to proceed with your script.

Answered By: JeffC

$x is not javascript. If I were to do that in javascript it would look something like:

driver.execute_script("""
  [...document.querySelectorAll('span')].find(s => s.innerText.match('Marketplace'))?.click()
""")
Answered By: pguardiario