How to fix “Element is not clickable” in Selenium WebDriver tests?

Element is not clickable” is a common error that Selenium test automation engineers often encounter. This might be applicable to other test automation frameworks, with different error messages. There are possible two causes:

  1. The element is not clickable, such as disabled or not allowed to click by nature (e.g. a hidden field)
    this is easy to find out by inspecting (via right-click in Chrome), the solution is to change/refine the locator.
  2. The element is not viewable in the browser (by the definition of Selenium)

This article will explain the second type. Below is a test failure of trying to click the exclamation icon.

The test failed (the above: webpage, the below test failure output)

Tip: run the test and keep the browser open so that you can inspect the web page, test scripts and test output all-together. Check out: Keep the Browser Open after Executing an Individual Test.

Analyse

The test step:

driver.find_element(:class, "fa-warning").click

The error output:

Failure/Error: driver.find_element(:class, "fa-warning").click
Selenium::WebDriver::Error::ElementClickInterceptedError:
element click intercepted: Element is not clickable at point (1201, 611)
(Session info: chrome=102.0.5005.115)

The reason:

Selenium is unable to click the exclamation icon, which is inside the viewable of the browser window. However, it is just, not enough for Selenium even though we (human beings) can see it. This is a rare case (clickable element on the edge of the window), a more common case is where the element is off-screen.

Initial solutions:

  1. Make the browser window bigger (not recommended).
    Depending on the page content and browser size, it might work in some cases.
  2. Scroll the webpage down further to make the element fully visible.
    My recommendation, see below.

Solution

There are several approaches to scrolling in Selenium.

  1. Scroll based on the element’s X,Y coordinate
elem = driver.find_element(:class, "fa-warning")
elem_pos = elem.location.y
driver.execute_script("window.scroll(0, #{elem_pos + 100})")
sleep 0.5 # add delay to allow JS execution
elem.click

The above test script works. The 100 is, obviously, is one of many possible scroll-down pixels.

The explanation:

  • Find the element
  • Get the Y position of the element in the browser
  • Invoke JavaScript to scroll down a further 100 pixels
  • Add a small delay to allow JS scrolling to complete
  • Click the element (now fully visible)

As you can see, this approach is flexible, i.e., you can fine-tune the scrolling.

2. Invoke JavaScript scrollIntoView .

elem = driver.find_element(:class, "fa-warning")
driver.execute_script("arguments[0].scrollIntoView(true);", elem);
sleep 0.5
elem.click

Tip: when you debug/refine a single test step, try to find a way to attach the test execution (of modified test steps) against the current browser. Then, you can be focused and repeatedly trying for that step, a big time-saver in test automation. For more, check out the article “Attach Selenium Python test steps against an existing browser” (the article uses Python tests as example, the same works for Ruby and JS too in TestWise IDE).

However, I vaguely remember that this way did not work on a few occasions. So, personally, I preferred Approach #1. You may choose the style you preferred. Test Automation is practical, i.e., if it works reliably, that’s fine.

Two common scrolling JS functions:

// to bottom
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
// to top
driver.execute_script("window.scrollTo(0, 0);")

3. Scroll wheel actions (from Selenium v4.2)

Selenium v4.2 introduced Scroll wheel actions, which make scrolling easier, as a part of Advanced User Interactions. (please note that scrolling has always been possible, see the above).

elem = driver.find_element(:class, "fa-warning")
driver.action.scroll_by(100, 200).perform
elem.click

Astute readers might notice that sleep 0.5 is no longer there. Yes, because it is not done by JS this time. This method uses relative scrolling (i.e. the above snippet will go 100 pixels to the right and 200 pixels down from the current scroll position), not absolute like the previous two methods.

The new scrolling functions added in Selenium v4.2:

scroll_to(ELEM)
scroll_by(DELTA_X, DELTA_Y)
scroll_from(SCROLL_ORIGIN, DELTA_X, DELTA_Y)

For Selenium v4.2+, I recommend Approach #3.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store