WebDriver click () vs JavaScript click ()
이야기:
StackOverflow에서 셀레늄 WebDriver "click"명령을 통해 요소를 클릭 할 수 없으며 스크립트를 실행하여 JavaScript 클릭으로 해결할 수 있다고보고하는 사용자를 보았습니다.
파이썬의 예 :
element = driver.find_element_by_id("myid")
driver.execute_script("arguments[0].click();", element)
WebDriverJS / 분도기의 예 :
var elm = $("#myid");
browser.executeScript("arguments[0].click();", elm.getWebElement());
질문:
정기적 인 WebDriver 클릭이되지 않을 때 왜 "JavaScript를 통한"클릭이 작동합니까? 정확히 언제 이런 일이 발생하며이 해결 방법의 단점은 무엇입니까?
나는 왜이 해결 방법을 사용해야하는지 그리고 어떤 문제가 발생할 수 있는지 완전히 이해하지 않고이 해결 방법을 사용했습니다.
반대로 뭐라고에 현재 허용 대답은 그것이 WebDriver는 클릭을 가진 자바 스크립트에서 그 일의 차이에 관해서 제안, PhantomJS에 아무것도 특정있다.
차이점
두 방법의 근본적인 차이점은 모든 브라우저에 공통적이며 매우 간단하게 설명 할 수 있습니다.
WebDriver : WebDriver는 클릭을 수행 할 때 실제 사용자가 브라우저를 사용할 때 발생하는 상황을 시뮬레이션하기 위해 최선을 다합니다. "Click me"라는 단추 인 요소 A와
div
투명하지만 크기가 있고zIndex
A를 완전히 덮도록 설정된 요소 인 요소 B가 있다고 가정합니다 . 그런 다음 WebDriver에 A를 클릭하도록 지시합니다. B가 클릭을 먼저 받도록 클릭을 시뮬레이션합니다 . 왜? B가 A를 다루고 사용자가 A를 클릭하려고하면 B가 먼저 이벤트를받습니다. A가 결국 클릭 이벤트를 받을지 여부는 B가 이벤트를 처리하는 방법에 따라 다릅니다. 어쨌든이 경우 WebDriver의 동작은 실제 사용자가 A를 클릭하려고 할 때와 동일합니다.JavaScript : 이제 JavaScript를 사용하여한다고 가정 해 봅시다
A.click()
. 이 클릭 방법은 사용자가 A를 클릭하려고 할 때 실제로 발생하는 상황을 재현하지 않습니다. JavaScript는click
이벤트를 A로 직접 보내고 B는 이벤트를받지 않습니다.
WebDriver 클릭이 작동하지 않을 때 JavaScript 클릭이 작동하는 이유는 무엇입니까?
위에서 언급했듯이 WebDriver는 실제 사용자가 브라우저를 사용할 때 발생할 수있는 최선의 시뮬레이션을 시도합니다. 문제의 사실은 DOM이 사용자가 상호 작용할 수없는 요소를 포함 할 수 있으며 WebDriver에서 이러한 요소를 클릭 할 수 없다는 것입니다. 위에서 언급 한 겹치는 경우 외에도 보이지 않는 요소를 클릭 할 수 없습니다. 스택 오버플로 질문에서 흔히 볼 수있는 사례는 DOM에 이미 존재하지만 다른 요소를 조작했을 때만 보이는 GUI 요소와 상호 작용하려고하는 사람입니다. 이것은 때때로 드롭 다운 메뉴에서 발생합니다 : 메뉴 항목을 선택하기 전에 드롭 다운을 표시하는 버튼을 먼저 클릭해야합니다. 메뉴가 표시되기 전에 누군가 메뉴 항목을 클릭하려고하면사용자가 JavaScript를 사용하여 시도하면 가시성에 관계없이 이벤트가 요소에 직접 전달되므로 작동합니다.
클릭시 언제 JavaScript를 사용해야합니까?
응용 프로그램 을 테스트하기 위해 Selenium을 사용 하는 경우이 질문에 대한 대답은 "거의"입니다. 전반적으로 Selenium 테스트는 사용자가 브라우저로 수행 한 작업을 재현해야합니다. 드롭 다운 메뉴의 예를 들어 : 테스트는 드롭 다운을 먼저 표시하는 버튼을 클릭 한 다음 메뉴 항목을 클릭해야합니다. 버튼이 보이지 않거나 버튼에 메뉴 항목 또는 이와 유사한 항목이 표시되지 않아 GUI에 문제가있는 경우 테스트에 실패하고 버그를 감지 한 것입니다. JavaScript를 사용하여 클릭하면 자동화 된 테스트를 통해 이러한 버그를 감지 할 수 없습니다.
JavaScript를 사용하는 것이 합당한 경우 예외가있을 수 있으므로 "거의 절대"라고 말합니다. 그러나 매우 드 물어야합니다.
사이트 스크랩에 Selenium을 사용하는 경우 사용자 동작을 재현하는 것이 중요하지 않습니다. 따라서 GUI를 우회하기 위해 JavaScript를 사용하는 것은 문제가되지 않습니다.
드라이버가 실행하는 클릭 은 요소가 상호 작용할 수없는 경우에도 JavaScript HTMLElement.click()
가 click
이벤트에 대한 기본 조치를 수행하는 동안 가능한 한 근접한 실제 사용자의 동작을 시뮬레이션하려고 시도합니다 .
차이점은 다음과 같습니다.
드라이버는 요소를 보기로 스크롤 하여 요소 가 표시 되는지 확인하고 요소가 상호 작용할 수 있는지 확인합니다 .
드라이버가 오류를 발생시킵니다 :
- 클릭 좌표에서 맨 위에있는 요소가 타겟팅 된 요소 또는 하위 요소가 아닌 경우
- 요소의 크기가 없거나 완전히 투명한 경우
- 요소가 비활성화 된 입력 또는 버튼 인 경우 (속성 / 속성
disabled
은true
) - 요소에 마우스 포인터가 비활성화 된 경우 (CSS
pointer-events
는none
)
JavaScriptHTMLElement.click()
는 항상 기본 조치를 수행하거나 요소가 사용 불가능한 경우 자동으로 실패합니다.운전자는 초점을 맞출 수있는 요소에 초점을 맞출 것으로 예상됩니다 .
자바 스크립트
HTMLElement.click()
는 그렇지 않습니다.드라이버는 실제 사용자처럼 모든 이벤트 (mousemove, mousedown, mouseup, click 등)를 생성해야합니다.
JavaScript
HTMLElement.click()
는click
이벤트 만 방출합니다 . 페이지는 이러한 추가 이벤트에 의존 할 수 있으며 생성되지 않은 경우 다르게 작동 할 수 있습니다.These are the events emitted by the driver for a click with Chrome:
mouseover {target:#topic, clientX:222, clientY:343, isTrusted:true, ... } mousemove {target:#topic, clientX:222, clientY:343, isTrusted:true, ... } mousedown {target:#topic, clientX:222, clientY:343, isTrusted:true, ... } mouseup {target:#topic, clientX:222, clientY:343, isTrusted:true, ... } click {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
And this is the event emitted with a JavaScript injection:
click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
The event emitted by a JavaScript
.click()
is not trusted and the default action may not be invoked:https://developer.mozilla.org/en/docs/Web/API/Event/isTrusted
https://googlechrome.github.io/samples/event-istrusted/index.htmlNote that some of the drivers are still generating untrusted events. This is the case with PhantomJS as of version 2.1.
The event emitted by a JavaScript
.click()
doesn't have the coordinates of the click.The properties
clientX, clientY, screenX, screenY, layerX, layerY
are set to0
. The page might rely on them and might behave differently.
It may be ok to use a JavaScript .click()
to scrap some data, but it is not in a testing context. It defeats the purpose of the test since it doesn't simulate the behavior of a user. So, if the click from the driver fails, then a real user will most likely also fail to perform the same click in the same conditions.
What makes the driver fail to click an element when we expect it to succeed?
The targeted element is not yet visible/interactable due to a delay or a transition effect.
Some examples :
https://developer.mozilla.org/fr/docs/Web (dropdown navigation menu) http://materializecss.com/side-nav.html (dropdown side bar)
Workarrounds:
Add a waiter to wait for the visibility, a minimum size or a steady position :
// wait visible browser.wait(ExpectedConditions.visibilityOf(elem), 5000); // wait visible and not disabled browser.wait(ExpectedConditions.elementToBeClickable(elem), 5000); // wait for minimum width browser.wait(function minimumWidth() { return elem.getSize().then(size => size.width > 50); }, 5000);
Retry to click until it succeeds :
browser.wait(function clickSuccessful() { return elem.click().then(() => true, (ex) => false); }, 5000);
Add a delay matching the duration of the animation/transition :
browser.sleep(250);
The targeted element ends-up covered by a floating element once scrolled into the view:
The driver automatically scrolls the element into the view to make it visible. If the page contains a floating/sticky element (menu, ads, footer, notification, cookie policy..), the element may end-up covered and will no longer be visible/interactable.
Example: https://twitter.com/?lang=en
Workarounds:
Set the size of the window to a larger one to avoid the scrolling or the floating element.
Mover over the element with a negative
Y
offset and then click it:browser.actions() .mouseMove(elem, {x: 0, y: -250}) .click() .perform();
Scroll the element to the center of the window before the click:
browser.executeScript(function scrollCenter(elem) { var win = elem.ownerDocument.defaultView || window, box = elem.getBoundingClientRect(), dy = box.top - (win.innerHeight - box.height) / 2; win.scrollTo(win.pageXOffset, win.pageYOffset + dy); }, element); element.click();
Hide the floating element if it can't be avoided:
browser.executeScript(function scrollCenter(elem) { elem.style.display = 'none'; }, element);
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 <div>
. 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 <div>
-> We do some calculation
-> then we bind event of click to the
<div>
.-> 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 <script>
tag directly into HTML.
For each browser, the behavior will be different. But regardless, these methods are more complicating than clicking on the button. Click is using what already there (end-users click), js click is going through backdoor.
And for js click will appear to be an asynchronous task. This is related a with a kinda complex topic of 'browser asynchronous task and CPU task scheduling' (read it a while back can't find the article again). For short this will mostly result as js click will need to wait for a cycle of task scheduling of CPU and it will be ran a bit slower after the binding of the click event. (You could know this case when you found the element sometimes clickable, sometimes not. )
When exactly is this happening and what is the downside of this workaround (if any)?
=> As mention above, both mean for one purpose, but about using which entrance:
- Click: is using what providing by default of browser.
- JS click: is going through backdoor.
=> For performance, it is hard to say because it relies on browsers. But generally:
- Click: doesn't mean faster but only signed higher position in schedule list of CPU execution task.
- JS click: doesn't mean slower but only it signed into the last position of schedule list of CPU task.
=> Downsides:
- Click: doesn't seem to have any downside except you are using PhamtomJS.
- JS click: very bad for health. You may accidentally click on something that doesn't there on the view. When you use this, make sure the element is there and available to view and click as the point of view of end-user.
P.S. if you are looking for a solution.
- Using PhantomJS? I will suggest using Chrome headless instead. Yes, you can set up Chrome headless on Ubuntu. Thing runs just like Chrome but it only does not have a view and less buggy like PhantomJS.
- Not using PhamtomJS but still having problems? I will suggest using ExpectedCondition of Protractor with
browser.wait()
(check this for more information)
(I want to make it short, but ended up badly. Anything related with theory is complicated to explain...)
참고URL : https://stackoverflow.com/questions/34562061/webdriver-click-vs-javascript-click
'Programing' 카테고리의 다른 글
많은 수의 파일에 대한 빠른 Linux 파일 수 (0) | 2020.07.21 |
---|---|
UNIX / LINUX에서 명령이 걸리는 시간을 추적 하시겠습니까? (0) | 2020.07.20 |
SQL에서 한 줄로 변수를 선언하고 할당하는 방법 (0) | 2020.07.20 |
XML에서 한 줄을 주석으로 처리하는 방법은 무엇입니까? (0) | 2020.07.20 |
HG 버전간에 변경된 파일 목록 생성 (0) | 2020.07.20 |