Click With a JavaScript Fallback
Try a real click first, then fall back to a JavaScript click only for the specific interception and visibility errors, with a log line so fallbacks are visible.
Problem
click() throws ElementClickInterceptedException because a sticky header, toast or cookie banner overlaps the target, or ElementNotInteractableException for a visually hidden but functional control. A JavaScript click works but bypasses the checks a user’s click would face, so making it the default hides real bugs.
Solution
Scroll to centre, try the real click, and only on those two exceptions fall back to element.click() in JavaScript, logging the fallback.
public static void safeClick(WebDriver driver, WebElement el) { JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript("arguments[0].scrollIntoView({block: 'center'});", el); try { el.click(); } catch (ElementClickInterceptedException | ElementNotInteractableException e) { System.out.println("JS click fallback for " + el + ": " + e.getClass().getSimpleName()); js.executeScript("arguments[0].click();", el); }}from selenium.common.exceptions import ( ElementClickInterceptedException, ElementNotInteractableException)
def safe_click(driver, el): driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", el) try: el.click() except (ElementClickInterceptedException, ElementNotInteractableException) as e: print(f"JS click fallback for {el}: {type(e).__name__}") driver.execute_script("arguments[0].click();", el)async function safeClick(driver, el) {await driver.executeScript("arguments[0].scrollIntoView({block: 'center'});", el);try { await el.click();} catch (e) { if (!['ElementClickInterceptedError', 'ElementNotInteractableError'].includes(e.name)) throw e; console.warn('JS click fallback:', e.name); await driver.executeScript('arguments[0].click();', el);}}public static void SafeClick(IWebDriver driver, IWebElement el){ var js = (IJavaScriptExecutor)driver; js.ExecuteScript("arguments[0].scrollIntoView({block: 'center'});", el); try { el.Click(); } catch (Exception e) when (e is ElementClickInterceptedException || e is ElementNotInteractableException) { Console.WriteLine($"JS click fallback: {e.GetType().Name}"); js.ExecuteScript("arguments[0].click();", el); }}Why It Works
The real click exercises the same hit-testing a user’s click does, so it catches layout bugs. The fallback dispatches a click event directly on the element, which fires the handlers regardless of overlap. Catching only the two overlap-related exceptions keeps genuine failures (NoSuchElement, stale references) visible.
Gotchas
- A JavaScript click does not move the mouse, so hover-dependent handlers and
mousedown/mouseuplisteners do not fire. If the app needs those, dispatch them explicitly or fix the overlay instead. - Count the fallbacks in CI. A test that always needs the fallback has an overlay bug worth reporting or a wait that should have covered the overlay.
- Prefer waiting for the overlay to disappear (see the spinner recipe) over falling back; use this recipe for the residual cases.
Learn the theory
- Click and Type Learn the fundamental Selenium interactions: clicking elements and typing text into input fields.
- JavaScript Executor Execute JavaScript directly in the browser for advanced interactions and DOM manipulation.
- Common Errors Diagnose and fix the most common Selenium errors and exceptions.