In Selenium, why does forcing a tax-return page's Submit button with executeScript("arguments[0].click()", el) hide a real defect?
answer
- Green pipeline, blocked taxpayer
- Who actually moves the pointer?
- The banner is still on top
- Dispatched at the node, not aimed at it
- arguments[0].click() versus WebElement.click()
basics
~20 sThe injected click fires straight at the node, so it works even when a banner covers the button or the button is invisible. The test goes green while a real user, whose pointer hits whatever sits on top, cannot submit.
solid answer
~40 s`((JavascriptExecutor) driver).executeScript("arguments[0].click();", el)` runs in the page and calls the DOM's own `click()` on that node, which dispatches a click event directly at it. Selenium's `WebElement.click()` instead asks the browser to press a real pointer at the element's in-view centre point, so it fails loudly with `ElementClickInterceptedException` when a consent banner or sticky bar covers the Submit button on a tax-return summary page. Swapping in the scripted click makes that failure disappear without fixing anything: the handler still runs, the return still posts, the assertion still passes, and a human still cannot file. Use the hatch deliberately - to read something WebDriver has no command for, or to arrange state the case is not asserting - and never as the fix for the exact step the case exists to prove.
go deeper
Recall that Selenium can click twice over: the driver's own click and a click you inject with script. Know that the injected one ignores anything covering the button.
Explain the mechanics: the driver's click presses a pointer at a hit-tested coordinate, while injected script dispatches an event on the node itself, so no overlay is consulted.
Show the judgment. Say out loud that the forced click converts a real user-facing defect into a green pipeline, and describe where you would still allow it and how you would keep it auditable.
Own the policy angle: whether forced interactions are allowed at all in your suites, how the team detects a green run that hides a broken page, and what signal replaces the red test you deleted.
## Two different things both called a click `WebElement.click()` is a **WebDriver command**. The client posts to the element-click endpoint and the driver drives the browser's own input machinery: it scrolls the element into view, computes an in-view centre point, and presses a pointer there. The browser hit-tests that coordinate, so whatever is painted on top of the point receives the event. When a consent banner or a sticky "Return ready to file" bar covers the **Submit return** button on a tax-return summary page, the driver refuses and raises `ElementClickInterceptedException`, naming the element that got in the way. `((JavascriptExecutor) driver).executeScript("arguments[0].click();", submit)` is not a click command at all. The script string is posted to `/session/{id}/execute/sync` and evaluated as the body of an anonymous function inside the page; the element you passed is deserialized from its `element-6066-11e4-a52e-4f735466cecf` reference and handed to the script as `arguments[0]`. Calling the DOM's own `click()` on that node **dispatches an event straight at the node**. No coordinate is computed, no hit test is performed, and nothing sitting on top of the button is ever consulted. ```java // Fails loudly while the banner covers the button. driver.findElement(By.id("submit-return")).click(); // Succeeds no matter what covers the button. ((JavascriptExecutor) driver) .executeScript("arguments[0].click();", driver.findElement(By.id("submit-return"))); ``` ## Why the suite goes green and the taxpayer does not - The button's handler is bound to the node, so it runs: the return posts and the confirmation page renders. - The overlay is never in the code path, so its existence is invisible to every assertion downstream. - The failure the case existed to catch - "a filer cannot submit their return" - is exactly the failure the workaround erases. - Somebody reading a green pipeline gets no signal at all that the page is broken for humans. ## Side by side | | `submit.click()` | `executeScript("arguments[0].click();", el)` | |---|---|---| | Endpoint | element click | `/session/{id}/execute/sync` | | Geometry | in-view centre point, hit-tested | none computed | | Covered target | `ElementClickInterceptedException` | dispatches anyway | | `pointer-events: none` | nothing reaches the button | handler still fires | | `visibility: hidden` | the driver refuses | handler still fires | | Events produced | the browser's own pointer sequence | a single `click` event | | A green result proves | a user can reach and press it | the handler runs when invoked | That last row is the whole argument. ## The event shape matters too The DOM's `click()` produces one `click` event. It does not produce the `pointerdown`, `mousedown`, `mouseup` and focus changes a real press produces. A widget that opens on `mousedown`, a custom **filing status** dropdown, or an amount field that only commits on `blur` may therefore do nothing at all under a forced click, or do half of what it should. So the escape hatch does not only hide defects: it can **invent** failures no user would ever see, which is a slower and more confusing way to lose an afternoon than a red test would have been. ## When it is a legitimate escape hatch 1. **Reading things WebDriver has no command for.** `return document.readyState`, `return window.getComputedStyle(arguments[0]).position` and `return arguments[0].scrollHeight` are only reachable through a script. 2. **Arranging state the case is not asserting.** If the case is about the refund figure, scrolling the summary table with `arguments[0].scrollIntoView({block: "center"})` is setup, not the subject. 3. **Diagnosing a failure.** `return document.elementFromPoint(x, y)` answers "what is actually on top of my button?" far faster than staring at a screenshot does. 4. **Reaching a control no person reaches** - a hook the application exposes for automation rather than for hands. The distinguishing test is short: **would a real filer's own hands have to perform this step?** If they would, injected script must not perform it. ## Keeping the hatch honest - Wrap it in one named helper, `forceClick(WebElement)`, so a reviewer can find every use with a single grep. - Force the setup, never the subject: no forced click may sit on the step the case exists to prove. - When you force something because the page really is broken, open the bug and link it from the call site so the workaround carries an expiry date. - Treat `ElementClickInterceptedException` as a **finding** rather than an obstacle - the driver has just told you a user is blocked. A senior engineer is expected to reach for `executeScript` without embarrassment, and to refuse it in exactly one place: the step under assertion.
- Your suite already has thirty forced clicks. How would you find out which ones are hiding defects?Wrap every one in a single named helper so they are greppable, then flip them back to a real `click()` behind a flag and run the suite. The ones that now fail with `ElementClickInterceptedException` or `ElementNotInteractableException` are pointing at genuine page problems; the ones that still pass were only ever setup and can keep the hatch.
- When is a scripted click the honest choice rather than a workaround?When the click is setup for something else - dismissing a survey prompt so the refund assertion can run - or when it targets a control the application exposes for automation rather than for people. The rule of thumb is whether a real filer's own hands would have to perform that step; if they would, force nothing.
- Why can a forced click also make a test fail that would have passed for a user?The DOM's `click()` emits only a `click` event. A widget that opens on `mousedown`, or a field that commits its value on `blur`, never sees the events it needs, so the page does less than a real press would have done. The hatch distorts behaviour in both directions.
It is like testing a door by reaching through the wall to work the latch. The latch opens every time, which tells you nothing about whether the doorway is blocked.
saying these in an interview costs you the question
- Claims the scripted click still checks that the element is visible
- Uses executeScript as the standard fix for an intercepted click
- Says Selenium dismisses overlays before running injected script
- Believes a passing forced click proves the button is reachable
- Thinks a DOM click() emits the same events as a real press