WebDriver click() vs JavaScript click()

История:

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

Пример в Python:

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

Вопрос:

Почему нажатие "через JavaScript" работает, а обычное нажатие WebDriver - нет? Когда именно это происходит и каковы недостатки этого обходного пути (если есть)?

Я лично использовал этот обходной путь, не полностью понимая, почему я должен это делать и к каким проблемам это может привести.

Ответ 1

В противоположность тому, что отвечает принятый в настоящее время ответ, нет ничего конкретного для PhantomJS, когда дело касается разницы между тем, как WebDriver делает клик и делает это в JavaScript.

Разница

Существенное различие между этими двумя методами является общим для всех браузеров и может быть объяснено довольно просто:

  • WebDriver: Когда WebDriver делает клик, он пытается как можно лучше имитировать то, что происходит, когда реальный пользователь использует браузер. Предположим, что у вас есть элемент A, который является кнопкой который говорит "Click me" и элемент B, который является элементом div, который является прозрачным, но имеет свои размеры и zIndex установлен так, что он полностью покрывает A. Затем вы указываете WebDriver щелкнуть A. WebDriver будет имитировать щелчок так что B сначала получает клик. Зачем? Поскольку B охватывает A, и если пользователь должен был нажать на A, тогда B сначала получит событие. Независимо от того, будет ли A в конечном итоге получать событие клика, зависит от того, как B обрабатывает событие. Во всяком случае, поведение с WebDriver в этом случае такое же, как когда реальный пользователь пытается нажать A.

  • JavaScript: предположим, вы используете JavaScript для A.click(). Этот метод нажатия не воспроизводит то, что действительно происходит, когда пользователь пытается щелкнуть A. JavaScript отправляет событие click непосредственно в A, а B не получит никакого события.

Почему JavaScript нажимает "Работает", когда нет доступа к WebDriver?

Как я уже упоминал выше, WebDriver будет пытаться имитировать, насколько это возможно, что происходит, когда реальный пользователь использует браузер. Дело в том, что DOM может содержать элементы, с которыми пользователь не может взаимодействовать, и WebDriver не позволит вам щелкнуть по этому элементу. Помимо упомянутого мною перекрывающего случая, это также подразумевает, что невидимые элементы не могут быть нажаты. Обычный случай, который я вижу в вопросах, - это тот, кто пытается взаимодействовать с элементом GUI, который уже существует в DOM, но становится видимым только при манипулировании каким-либо другим элементом. Это иногда происходит с выпадающими меню: сначала нужно нажать кнопку, чтобы открыть раскрывающийся список, прежде чем выбрать пункт меню. Если кто-то пытается щелкнуть элемент меню до того, как меню станет видимым, WebDriver перестанет говорить, что элемент нельзя манипулировать. Если пользователь пытается сделать это с помощью JavaScript, он будет работать, потому что событие доставляется непосредственно элементу независимо от видимости.

Когда вы должны использовать JavaScript для кликов?

Если вы используете Selenium для тестирования приложения, мой ответ на этот вопрос "почти никогда". В общем, ваш тест Selenium должен воспроизводить то, что пользователь будет делать с браузером. Взяв пример выпадающего меню: тест должен щелкнуть по кнопке, которая сначала откроет раскрывающийся список, а затем щелкните элемент меню. Если есть проблема с графическим интерфейсом, потому что кнопка невидима или кнопка не отображает элементы меню или что-то подобное, тогда ваш тест завершится неудачно, и вы обнаружите ошибку. Если вы используете JavaScript для кликов, вы не сможете обнаружить эти ошибки с помощью автоматического тестирования.

Я говорю "почти никогда", потому что могут быть исключения, когда имеет смысл использовать JavaScript. Однако они должны быть очень редкими.

Если вы используете Selenium для соскабливания сайтов, то не так критично пытаться воспроизвести поведение пользователя. Поэтому использование JavaScript для обхода графического интерфейса является проблемой.

Ответ 2

Щелчок, выполняемый драйвером, пытается имитировать поведение реального пользователя как можно ближе, а JavaScript HTMLElement.click() выполняет действие по умолчанию для события click, даже если элемент не взаимодействует.

Различия заключаются в следующем:

  • Драйвер обеспечивает видимость элемента , прокручивая его в представление и проверяет, что элемент доступен для взаимодействия.

    Водитель вызовет ошибку:

    • когда элемент сверху в координатах клика не является целевым элементом или потомком
    • когда элемент не имеет положительного размера или полностью прозрачен
    • когда элемент является отключенным вводом или кнопкой (атрибут/свойство disabled есть true)
    • когда элемент отключен указателем мыши (CSS pointer-events is none)


    JavaScript HTMLElement.click() всегда будет выполнять действие по умолчанию или, в лучшем случае, будет терпеть неудачу, если элемент отключен.

  • Ожидается, что драйвер перенесет элемент в фокус, если он сконфигурирован.

    JavaScript 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

    Обратите внимание, что некоторые драйверы все еще генерируют ненадежные события. Это относится к PhantomJS с версии 2.1.

  • Событие, испускаемое JavaScript .click() , не имеет координат щелчка.

    Свойства clientX, clientY, screenX, screenY, layerX, layerY установлены на 0. Страница может опираться на них и может вести себя по-другому.


Возможно, будет хорошо использовать JavaScript .click() для удаления некоторых данных, но это не в контексте тестирования. Он побеждает цель теста, поскольку он не моделирует поведение пользователя. Таким образом, если щелчок от драйвера не удастся, тогда реальный пользователь, скорее всего, также не сможет выполнить один и тот же клик в тех же условиях.


Что заставляет драйвер не удалять элемент, если мы ожидаем его успеха?

  • Целевой элемент еще не видимый/взаимодействующий из-за задержки или эффекта перехода.

    Некоторые примеры:

    https://developer.mozilla.org/fr/docs/Web (раскрывающееся меню навигации) http://materializecss.com/side-nav.html (выпадающая панель)

    Workarrounds:

    Добавьте официанта, чтобы подождать видимость, минимальный размер или устойчивое положение:

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


  • Целевой элемент завершается закрытым плавающим элементом после прокрутки в представление:

    Драйвер автоматически прокручивает элемент в виде, чтобы сделать его видимым. Если страница содержит плавающий/липкий элемент (меню, объявления, нижний колонтитул, уведомление, политика файлов cookie..), элемент может оказаться закрытым и больше не будет видимым/интерактивным.

    Пример: 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);
    

Ответ 3

ПРИМЕЧАНИЕ. Позвольте call 'click' щелкнуть конечный пользователь. "js click" - щелчок через JS

Почему нажатие "через JavaScript" работает, когда обычный клик WebDriver не работает?

Для этого есть 2 случая:

I. Если вы используете PhamtomJS

Тогда это наиболее распространенное известное поведение PhantomJS. Некоторые элементы иногда не доступны для кликов, например <div>. Это связано с тем, что PhantomJS был оригинальным для моделирования движка браузеров (например, начальный HTML + CSS → вычисление CSS → рендеринга). Но это не означает, что нужно взаимодействовать с ним как с конечным пользователем (просмотр, щелчок, перетаскивание). Поэтому PhamtomJS является лишь частично поддержкой с использованием взаимодействия с конечным пользователем.

ПОЧЕМУ РАБОТАЕТ JS CLICK WORK? Что касается кликов, то все они являются средним нажатием. Это похоже на пушку с 1 баррель и 2 триггерами. Один из окна просмотра, один из JS. Поскольку PhamtomJS отлично подходит для моделирования браузера, JS-клик должен работать отлично.

II. Обработчик события "click" получил привязку в плохой период времени.

Например, мы получили <div>

  • - > Мы делаем некоторый расчет

  • - > Затем мы привязываем событие щелчка к <div>.

  • - > Плюс с плохой кодировкой angular (например, не обрабатывать цикл действия по-польски)

Мы можем закончиться тем же результатом. Щелчок не будет работать, потому что WebdriverJS пытается щелкнуть элемент, если у него нет обработчика события клика.

ПОЧЕМУ РАБОТАЕТ JS CLICK? Js-клик похож на ввод js непосредственно в браузер. Возможно с двумя способами,

Fist через консоль devtools (да, WebdriverJS взаимодействует с консолью devtools).

Второй вводит тег <script> непосредственно в html.

Для каждого браузера поведение будет разным. Но, несмотря на это, эти методы более сложны, чем нажатие на кнопку. Щелчок использует то, что уже существует (щелчок конечного пользователя), js-клик идет через бэкдор.

И для js click появится задача asyncronus. Это связано с любопытной сложной темой " задачи асинхронного браузера и планирования задач ЦП" (прочитайте ее еще раз, чтобы не найти статью снова). Короче говоря, это в основном приведет к тому, что js-клик должен будет ждать цикла планирования задач CPU, и после привязки события click он будет немного медленнее. (Вы могли бы знать этот случай, когда вы обнаружили, что элемент иногда можно щелкнуть, иногда нет. )

Когда именно это происходит и что является недостатком этого обходной путь (если есть)?

= > Как упоминалось выше, оба означают для одной цели, но об использовании того входа:

  • Нажмите: использует то, что предоставляет по умолчанию браузер.
  • JS click: идет через бэкдор.

= > Для производительности трудно сказать, потому что оно зависит от браузеров. Но в целом:

  • Щелчок: не означает ускорение, но только подписанное более высокое положение в списке расписаний задачи по вытеснению процессора.
  • JS-клик: не означает более медленный, но только он подписан в последнюю позицию списка расписаний задачи ЦП.

= > Недостатки:

  • Щелчок: похоже, что у вас нет недостатков, кроме использования PhamtomJS.
  • JS click: очень плохо для здоровья. Вы можете случайно щелкнуть что-то, что не видно на экране. Когда вы используете это, убедитесь, что элемент существует и доступен для просмотра и щелкните в качестве точки зрения конечного пользователя.

P.S. если вы ищете решение.

  • Использование PhantomJS? Вместо этого я предлагаю использовать Chrome без головы. Да, вы можете установить Chrome без гарнитуры на Ubuntu. Вещь работает точно так же, как Chrome, но у нее нет только представления и менее багги, как PhantomJS.
  • Не использовать PhamtomJS, но он все еще имеет проблемы? Я предлагаю использовать ExpectedCondition of Protractor с browser.wait() (для получения дополнительной информации)

(Я хочу сделать это коротким, но в итоге получилось плохо. Все, что связано с теорией, усложняет объяснение...)