muzhik_65082235_big_

Для выполнения JS на странице у вебдрайвера есть два основных метода: executeScript и executeAsyncScript. Доступ можно получить, приведя объект WebDriver к интерфейсу  JavascriptExecutor. Пример будет ниже по тексту.

Давайте разберемся, в чем сакральный смысл и основное отличие этих методов.

executeScript

Согласно документации:

  • Переданный в данный метод джава скрипт будет выполнен в контексте выбранного фрейма или окна.
  • Будет выполнен как тело анонимной функции.
  • В данном скрипте можно использовать объект document как ссылку на текущий документ. Это значит, что вы можете выполнять джава скрипт, содержащий, к примеру, вот такую строку: getElementById(«id»).
  • Локальные переменные после выполнения скрипта не будут доступны, хотя глобальные сохранятся. Данный пункт позволяет изменять глобальные переменные на странице.
  • Если сценарий имеет возвращаемые значения, то преобразование в объекты Java происходит следующим образом:
  1. Html-элемент трансформируется в WebElement
  2. Decimal — в Double
  3. Non-decimal number — в Long
  4. Логическое значение — в Boolean
  5. Для остальных случаев будет возвращён String
  6. Массив будет преобразован в лист объектов, которые трансформируются согласно правилам, перечисленным выше. ВАЖНО! Списки могут быть вложенными! Т.е., если из JS будет передан двумерный массив, то он превратится в список списков.

             Обратите внимание!!! ExecuteScript возвращает не примитивы, а объекты! Это необходимо учитывать при последующей работе.

  • Если ваш скрипт ничего не возвращает, то метод вернёт null.
  • Передаваемые в скрипт значения могут быть числом, логическим значением, строкой, WebElement’ом или списком. Использовать их в самом JS можно как элементы массива arguments. Т.е., если в метод executeScript передать, скажем, WebElement, то кликнуть по нему можно будет следующим JS кодом: arguments[0].click();

  1. ((JavascriptExecutor) driver).executeScript("return document.readyState");

Данный код вернёт String со значением «complite», если документ был полностью загружен.

  1. ((JavascriptExecutor) driver).executeScript("arguments[0].click()", webElement);

А этот код выполнит нажатие силами JS на елемент webElement.

executeAsyncScript

А вот краткое описание отличий данного метода:

  • Основное отличие данного метода от предыдущего в том, что ваш скрипт должен через хитрую функцию обратного вызова callback() явно сообщить о завершении скрипта. Если данная функция не будет вызвана за определённое время, то WebDriver выкинет исключение TimeoutException. Выставить это время можно вот так:

driver .manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS) – данная строчка кода выставит таймаут в 5 секунд.

  • Функция callback() будет передана в вашу функцию как последний аргумент в arguments. Это значит, что следующая строчка кода позволит вызывать функцию в любой части кода: var callback = arguments[arguments.length — 1];
  • Для того, чтобы вернуть какое-то значение обратно в родную джаву, надо передать это значение в callback. Вот так: callback(variable);  Преобразовано оно будет по правилам для экзекутСкрипт метода.

  1. Object response = ((JavascriptExecutor) driver).executeAsyncScript(
  2. "var callback = arguments[arguments.length - 1];" +
  3. "var xhr = new XMLHttpRequest();" +
  4. "xhr.open('GET', '/resource/data.json', true);" +
  5. "xhr.onreadystatechange = function() {" +
  6. " if (xhr.readyState == 4) {" +
  7. " callback(xhr.responseText);" +
  8. " }" +
  9. "};" +
  10. "xhr.send();");
  11. JsonObject json = new JsonParser().parse((String) response);
  12. assertEquals("cheese", json.get("food").getAsString());

В данном примере, взятом вот отсюда,  выполняется AJAX Запрос, а затем ожидается, когда будет получен результат. После чего вызывается callback(), куда передаётся результат запроса.

Из всего вышесказанного становится ясно: метод executeScript нужен для выполнения просто JS на странице, а вот метод executeAsyncScript нужен для вызова на странице асинхронных запросов и контроля выполнения! А не для того, чтобы выполнять JS асинхронно, без ожидания полного выполнения, как любят писать в интернете некоторые говноеды!

Единственный из известных мне методов выполнить в браузере что-то асинхронно из автотестов — оборачивание вашего JS кода в setTimeout(function(){<сюда вставить то, что нужно выполнить асинхронно>}, 0);

Опубликовать в Google Plus
Опубликовать в LiveJournal
Опубликовать в Мой Мир
Опубликовать в Одноклассники
Опубликовать в Яндекс