История:

Здесь, в StackOverflow, я видел, как пользователи сообщали, что они не могут щелкнуть элемент с помощью команды selenium WebDriver "click" и могут обойти это с помощью щелчка JavaScript, выполнив сценарий.

Пример на Python:

element = driver.find_element_by_id("myid")
driver.execute_script("arguments[0].click();", element)

Пример в WebDriverJS / Protractor:

var elm = $("#myid");
browser.executeScript("arguments[0].click();", elm.getWebElement());

The Question:

Why is clicking "via JavaScript" works when a regular WebDriver click does not? When exactly is this happening and what is the downside of this workaround (if any)?

I personally used this workaround without fully understanding why I have to do it and what problems it can lead to.

Ответы (5)

Contrarily to what the currently accepted answer suggests, there's nothing specific to PhantomJS when it comes to the difference between having WebDriver do a click and doing it in JavaScript.

The Difference

The essential difference between the two methods is common to all browsers and can be explained pretty simply:

  • WebDriver: When WebDriver does the click, it attempts as best as it can to simulate what happens when a real user uses the browser. Suppose you have an element A which is a button that says "Click me" and an element B which is a div element which is transparent but has its dimensions and zIndex set so that it completely covers A. Then you tell WebDriver to click A. WebDriver will simulate the click so that B receives the click first. Why? Because B covers A, and if a user were to try to click on A, then B would get the event first. Whether or not A would eventually get the click event depends on how B handles the event. At any rate, the behavior with WebDriver in this case is the same as when a real user tries to click on A.

  • JavaScript: Now, suppose you use JavaScript to do A.click(). This method of clicking does not reproduce what really happens when the user tries to click A. JavaScript sends the click event directly to A, and B will not get any event.

Why a JavaScript Click Works When a WebDriver Click Does Not?

As I mentioned above WebDriver will try to simulate as best it can what happens when a real user is using a browser. The fact of the matter is that the DOM can contain elements that a user cannot interact with, and WebDriver won't allow you to click on these element. Besides the overlapping case I mentioned, this also entails that invisible elements cannot be clicked. A common case I see in Stack Overflow questions is someone who is trying to interact with a GUI element that already exists in the DOM but becomes visible only when some other element has been manipulated. This sometimes happens with dropdown menus: you have to first click on the button the brings up the dropdown before a menu item can be selected. If someone tries to click the menu item before the menu is visible, WebDriver will balk and say that the element cannot be manipulated. If the person then tries to do it with JavaScript, it will work because the event is delivered directly to the element, irrespective of visibility.

When Should You Use JavaScript for Clicking?

If you are using Selenium for testing an application, my answer to this question is "almost never". By and large, your Selenium test should reproduce what a user would do with the browser. Taking the example of the drop down menu: a test should click on the button that brings up the drop down first, and then click on the menu item. If there is a problem with the GUI because the button is invisible, or the button fails to show the menu items, or something similar, then your test will fail and you'll have detected the bug. If you use JavaScript to click around, you won't be able to detect these bugs through automated testing.

I say "almost never" because there may be exceptions where it makes sense to use JavaScript. They should be very rare, though.

If you are using Selenium for scraping sites, then it is not as critical to attempt to reproduce user behavior. So using JavaScript to bypass the GUI is less of an issue.

NOTE: let's call 'click' is end-user click. 'js click' is click via JS

Why is clicking "via JavaScript" works when a regular WebDriver click does not?

There are 2 cases for this to happen:

I. If you are using PhamtomJS

Then this is the most common known behavior of PhantomJS . Some elements are sometimes not clickable, for example

. This is because PhantomJS was original made for simulating the engine of browsers (like initial HTML + CSS -> computing CSS -> rendering). But it does not mean to be interacted with as an end user's way (viewing, clicking, dragging). Therefore PhamtomJS is only partially supported with end-users interaction.

WHY DOES JS CLICK WORK? As for either click, they are all mean click. It is like a gun with 1 barrel and 2 triggers. One from the viewport, one from JS. Since PhamtomJS great in simulating browser's engine, a JS click should work perfectly.

II. The event handler of "click" got to bind in the bad period of time.

For example, we got a

  • -> We do some calculation

  • -> then we bind event of click to the

    .

  • -> Plus with some bad coding of angular (e.g. not handling scope's cycle properly)

We may end up with the same result. Click won't work, because WebdriverJS trying to click on the element when it has no click event handler.

WHY DOES JS CLICK WORK? Js click is like injecting js directly into the browser. Possible with 2 ways,

Fist is through devtools console (yes, WebdriverJS does communicate with devtools' console).

Second is inject a