WebDriver click () vs JavaScript click ()


126

이야기:

StackOverflow에서 셀레늄 WebDriver "click"명령을 통해 요소를 클릭 할 수 없으며 스크립트를 실행하여 JavaScript 클릭으로 해결할 수 있다고보고하는 사용자를 보았습니다.

파이썬의 예 :

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());

질문:

정기적 인 WebDriver 클릭이되지 않을 때 왜 "JavaScript를 통한"클릭이 작동합니까? 정확히 언제 이런 일이 발생하며이 해결 방법의 단점은 무엇입니까?

나는 왜이 해결 방법을 사용해야하는지, 그리고 어떤 문제가 발생할 수 있는지 완전히 이해하지 않고이 해결 방법을 사용했습니다.

답변:


150

반대로 뭐라고에 현재 허용 대답은 그것이 WebDriver는 클릭을 가진 자바 스크립트에서 그 일의 차이에 관해서 제안, PhantomJS에 아무것도 특정있다.

차이점

두 방법의 근본적인 차이점은 모든 브라우저에 공통적이며 매우 간단하게 설명 할 수 있습니다.

  • WebDriver : WebDriver는 클릭을 수행 할 때 실제 사용자가 브라우저를 사용할 때 발생하는 상황을 시뮬레이션하기 위해 최선을 다합니다. "Click me"라는 단추 인 요소 A와 div투명하지만 크기가 있고 zIndexA를 완전히 덮도록 설정된 요소 인 요소 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를 사용하는 것은 문제가되지 않습니다.


1
훨씬 더 나은 대답은 이것이 받아 들여야합니다. 위의 답변은 PhantomJS에 특정한 엣지 케이스에 관한 것입니다. 이것은 훨씬 정확한 IMHO입니다.
Ardesco

확실히 @Ardesco. 허용 된 것으로 표시되었습니다. 완벽하고 자세한 답변.
alecxe

계획대로 Linh에게 현상금을 수여하지만, 또 다른 멋진 답변에 대해 감사하기 위해 새로운 것을 시작할 것입니다. 감사.
alecxe

1
아주 좋고 이해하기 쉬운 대답. WebDriver 방법과 같은 몇 가지 요소 : AngularJS와 페이지에 문제를 많이했다 WebDriver 내 경험에 clicksendKeys- 항상은 아니지만했다. 위치 문제 나 다른 예외는 없었으며 테스트 사례는 더 이상 진행되지 않았습니다. 로깅은 작업이 실행되었음을 나타냅니다. 때로는 Action도움이되었습니다. 테스트 케이스가 중지 된 후 요소를 수동으로 클릭하면 모든 것이 잘 작동했습니다. 그래서 우리는 그 때에 원시 JS로 전환했습니다. 지난 2 년간 AngularJS와 함께 일한 적이 없어서 지금은 더 나아질 수 있습니다.
Würgspaß

1
@Alex 편리한 링크가 없습니다. 내 답변은 특히 Selenium에 대한 경험과 일반적으로 사용자 이벤트 시뮬레이션과 관련이 있습니다. 5 년 전에 셀레늄을 사용하기 시작했습니다. Selenium을 사용하는 동안 몇 가지 문제를 해결하기 위해 Selenium의 코드를 읽어야했으며 이벤트 발송에 대한 꽤 많은 버그 보고서를 제출하고 Selenium 개발자와 버그에 대해 토론했습니다. "가능한 한 최선"이 목표입니다. 나는 그 목표에 도달하지 못하게하는 (현재 수정 된) 버그를 발견했습니다. 일부 버그가 남아있을 수 있습니다.
Louis

30

드라이버가 실행 한 클릭 은 요소가 상호 작용할 수없는 경우에도 JavaScript HTMLElement.click()click이벤트에 대한 기본 조치를 수행하는 동안 가능한 한 근접한 실제 사용자의 동작을 시뮬레이션하려고 시도합니다 .

차이점은 다음과 같습니다.

  • 드라이버는 요소를 보기로 스크롤 하여 요소 가 표시 되는지 확인하고 요소가 상호 작용할 수 있는지 확인합니다 .

    드라이버가 오류를 발생시킵니다 :

    • 클릭 좌표에서 맨 위에있는 요소가 타겟팅 된 요소 또는 하위 요소가 아닌 경우
    • 요소의 크기가 없거나 완전히 투명한 경우
    • 요소가 비활성화 된 입력 또는 버튼 인 경우 (속성 / 속성 disabledtrue)
    • 요소에 마우스 포인터가 비활성화 된 경우 (CSS pointer-eventsnone)


    JavaScript HTMLElement.click()는 항상 기본 조치를 수행하거나 요소가 사용 불가능한 경우 자동으로 실패합니다.

  • 운전자는 초점을 맞출 수있는 요소에 초점을 맞출 것으로 예상됩니다 .

    자바 스크립트 HTMLElement.click()는 그렇지 않습니다.

  • 드라이버는 실제 사용자처럼 모든 이벤트 (mousemove, mousedown, mouseup, click 등) 를 방출해야합니다 .

    JavaScript HTMLElement.click()click이벤트 만 생성합니다 . 페이지는 이러한 추가 이벤트에 의존 할 수 있으며 생성되지 않은 경우 다르게 작동 할 수 있습니다.

    다음은 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, ... }

    그리고 이것은 JavaScript 주입으로 생성 된 이벤트입니다.

    click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
  • JavaScript .click() 가 생성이벤트 는 신뢰할 수 없으며 기본 조치가 호출되지 않을 수 있습니다.

    https://developer.mozilla.org/en/docs/Web/API/Event/isTrusted
    https://googlechrome.github.io/samples/event-istrusted/index.html

    일부 드라이버는 여전히 신뢰할 수없는 이벤트를 생성합니다. 버전 2.1부터 PhantomJS의 경우입니다.

  • JavaScript에 의해 생성 된 이벤트 .click() 에는 click 좌표가 없습니다 .

    속성 clientX, clientY, screenX, screenY, layerX, layerY이로 설정되어 0있습니다. 페이지가 의존 할 수도 있고 다르게 동작 할 수도 있습니다.


JavaScript를 사용하여 .click()일부 데이터를 스크랩 해도 괜찮지 만 테스트 컨텍스트에는 없습니다. 사용자의 행동을 시뮬레이션하지 않기 때문에 테스트의 목적을 무효화합니다. 따라서 드라이버 클릭이 실패하면 실제 사용자도 동일한 조건에서 동일한 클릭을 수행하지 못할 가능성이 높습니다.


드라이버가 성공할 것으로 예상되는 요소를 클릭하지 못하는 이유는 무엇입니까?

  • 지연 또는 전환 효과로 인해 대상 요소가 아직 표시되거나 상호 작용할 수 없습니다.

    몇 가지 예 :

    https://developer.mozilla.org/fr/docs/Web (드롭 다운 탐색 메뉴) http://materializecss.com/side-nav.html (드롭 다운 사이드 바)

    해결 방법 :

    가시성, 최소 크기 또는 안정된 위치를 기다리는 웨이터를 추가하십시오.

    // 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);

    성공할 때까지 클릭을 다시 시도하십시오.

    browser.wait(function clickSuccessful() {
        return elem.click().then(() => true, (ex) => false);
    }, 5000);

    애니메이션 / 전환 기간과 일치하는 지연을 추가하십시오.

    browser.sleep(250);


  • 대상 요소 일단보기로 스크롤되면 부동 요소로 덮여 있습니다.

    드라이버는 요소를보기로 자동 스크롤하여 볼 수있게합니다. 페이지에 플로팅 / 스티커 요소 (메뉴, 광고, 바닥 글, 알림, 쿠키 정책 등)가 포함 된 경우 해당 요소는 결국 표시 될 수 있으며 더 이상 표시 / 상호 작용할 수 없습니다.

    예 : https://twitter.com/?lang=en

    해결 방법 :

    스크롤 또는 부동 요소를 피하려면 창의 크기를 더 크게 설정하십시오.

    음수 Y오프셋으로 요소 위로 마우스를 가져간 다음 클릭하십시오.

      browser.actions()
         .mouseMove(elem, {x: 0, y: -250})
         .click()
         .perform();

    클릭하기 전에 요소를 창의 중앙으로 스크롤하십시오.

    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();

    피할 수없는 경우 부동 요소를 숨기십시오.

    browser.executeScript(function scrollCenter(elem) {
      elem.style.display = 'none';
    }, element);

17

참고 : '클릭'이라고 부르 자 최종 사용자 클릭입니다. 'js 클릭'은 JS를 통한 클릭입니다.

정기적 인 WebDriver 클릭이되지 않을 때 왜 "JavaScript를 통한"클릭이 작동합니까?

이 경우 2 가지 경우가 있습니다.

I. PhamtomJS를 사용하는 경우

그러면 이것이 가장 일반적인 동작입니다 PhantomJS. 예를 들어 일부 요소를 클릭 할 수없는 경우가 <div>있습니다. 이는 PhantomJS브라우저의 엔진을 시뮬레이션하기 위해 원래 만들어 졌기 때문 입니다 (초기 HTML + CSS-> 컴퓨팅 CSS-> 렌더링). 그러나 최종 사용자의 방식 (보기, 클릭, 드래그)으로 상호 작용한다는 의미는 아닙니다. 따라서 PhamtomJS최종 사용자 상호 작용을 통해서만 부분적으로 지원됩니다.

왜 JS 클릭이 작동합니까? 두 클릭 모두 평균 클릭입니다. 그것은 1 개의 배럴2 개의 방아쇠를 가진 총과 같습니다 . 하나는 뷰포트에서, 다른 하나는 JS에서. 때문에 PhamtomJS브라우저의 엔진을 시뮬레이션에 큰하는 JS 클릭 완벽하게 작동합니다.

II. "click"의 이벤트 핸들러가 나쁜 시간에 바인드되었습니다.

예를 들어, 우리는 <div>

  • -> 우리는 약간의 계산을

  • -> 클릭 이벤트를에 바인딩합니다 <div>.

  • -> 각도 코딩 불량 (예 : 스코프 사이클을 제대로 처리하지 못함)

우리는 같은 결과로 끝날 수 있습니다. 클릭 이벤트 핸들러가없는 경우 WebdriverJS가 요소를 클릭하려고하므로 클릭이 작동하지 않습니다.

왜 JS 클릭이 작동합니까? JS 클릭은 js를 브라우저에 직접 주입하는 것과 같습니다. 두 가지 방법으로 가능

주먹 은 devtools 콘솔을 통해 이루어집니다 (예, WebdriverJS는 devtools의 콘솔과 통신합니다).

두 번째<script>태그를 HTML에 직접 삽입하는 것 입니다.

각 브라우저마다 동작이 다릅니다. 그러나 그럼에도 불구하고 이러한 방법은 버튼을 클릭하는 것보다 더 복잡합니다. 클릭은 이미 존재하는 것을 사용하고 (최종 사용자 클릭) js 클릭은 백도어를 통해 진행됩니다.

그리고 js의 경우 클릭은 비동기 작업으로 나타납니다. 이것은 ' 브라우저 비동기 작업 및 CPU 작업 예약 ' 이라는 다소 복잡한 주제와 관련이 있습니다 (이전 기사를 다시 찾을 수 없음). 간단히 말해 이것은 js 클릭이 CPU작업 스케줄링 주기를 기다려야 하고 클릭 이벤트 바인딩 후 약간 느리게 실행될 때 발생합니다. (때때로 클릭 할 수있는 요소를 찾았을 때이 경우를 알 수있었습니다.)

정확히 언제 이런 일이 발생하며이 해결 방법의 단점은 무엇입니까?

=> 위에서 언급했듯이 둘 다 한 가지 목적을 의미하지만 어떤 입구를 사용하는지에 대한 의미입니다.

  • 클릭 : 기본적으로 브라우저에서 제공하는 것을 사용하고 있습니다.
  • JS 클릭 : 백도어를 통해 진행 중입니다.

=> 성능을 위해서는 브라우저에 의존하기 때문에 말하기가 어렵습니다. 그러나 일반적으로

  • 클릭 : CPU 실행 작업의 일정 목록에서 더 빠르지는 않지만 더 높은 자리에만 서명한다는 의미입니다.
  • JS 클릭 : 느리다는 의미는 아니지만 CPU 작업의 일정 목록의 마지막 위치에만 로그인했습니다.

=> 단점 :

  • 클릭 : PhamtomJS를 사용하지 않는 한 단점이없는 것 같습니다.
  • JS 클릭 : 건강에 매우 나쁨. 보기에없는 것을 실수로 클릭 할 수 있습니다. 이것을 사용할 때 요소가 있고 최종 사용자의 관점에서보고 클릭 할 수 있는지 확인하십시오.

해결책을 찾고 있다면 PS.

  • PhantomJS를 사용하십니까? 대신 Chrome 헤드리스를 사용하는 것이 좋습니다. 예, Ubuntu에서 Chrome 헤드리스를 설정할 수 있습니다. Chrome과 마찬가지로 실행되지만 PhantomJS와 같은보기와 버그가 적습니다.
  • PhamtomJS를 사용하지 않지만 여전히 문제가 있습니까? Protractor의 ExpectedCondition을 사용하는 것이 좋습니다 browser.wait()( 자세한 내용은 이것을 확인하십시오 )

(짧게 만들고 싶지만 결과가 나빴습니다. 이론과 관련된 것은 설명하기가 복잡합니다 ...)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.