Selenium - Ожидание сетевого трафика

Мы используем Selenium с API Java и некоторыми расширениями Javascript. Мы используем много вызовов AJAX в нашем приложении. Многие наши тесты прерываются случайным образом, потому что иногда вызовы AJAX заканчиваются медленнее, чем другие, поэтому страница не загружена полностью. Мы исправим это, ожидая определенных элементов или Thread.sleep. Я пытался найти способ вместо этого просто ждать окончания сетевого трафика. Чтобы мы могли это сделать:

selenium.click("some JS button");
selenium.waitForNetwork();
assertTrue(something);

Таким образом, мы можем избавиться от спящего потока, и тесты проходят быстрее, когда сервер реагирует быстрее, и не так много тестов терпят неудачу из-за проблем с синхронизацией.

Мне не удалось найти способ поиска этого Google. Есть ли у кого-нибудь идеи, как мы можем это сделать? (Предпочтительно либо через Javascript, либо Java API, но все предложения приветствуются).

Примечание: другие варианты "waitFor" не то, что я ищу. Мы уже используем клики и другие вещи. Я ищу то, что ждет NETWORK TRAFFIC. Спасибо за все отзывы, я попробую пару предложений, но я по-прежнему открыт для других идей.

Спасибо.

Ответы

Ответ 1

Обновление: я использую тот же метод (wrapRequest) таким же образом с Selenium2, и он все еще работает. Единственное различие заключается в том, что я не использую расширение пользователя. Я просто запускаю javascript для запроса кода, загружаемого JSP.

Вот что мы в итоге сделали. (Обратите внимание: есть ли более простые способы получения, если выполняется вызов Ajax, если вы всегда используете только одну структуру, такую ​​как JQuery. Нам пришлось сделать это еще немного, потому что у нас есть несколько страниц, которые используют JQuery и группу, которая используйте GWT)

Я создал файл Javascript, который загружает каждая страница, только если вы тестируете. (Я сделал это, включив фрагмент в наш шаблон JSP: если параметр querystring тестирования передан как истинный, установите cookie. Если этот файл cookie установлен, включите файл javascript) Этот файл javascript по существу обертывает объект XMLHttpRequest для учета всех запросов отправки:

function wrapRequest(xmlRequest) {
    var oldSend = xmlRequest.prototype.send;
    xmlRequest.prototype.send = function() {
        var oldOnReady = this.onreadystatechange;
        oldOnReady = function() {
            oldOnReady.apply(this, arguments);
            // if call is complete, decrement counter.
        }
        // increment counter
        if(oldSend.apply)
            oldSend.apply(this, arguments);
        else if (oldOnReady.handleEvent) { //Firefox sometimes will need this
            oldOnReady.handleEvent.apply(this, arguments);
        }
    }
}

Там немного больше, чем if ifync == false, но это должно быть достаточно легко понять.

Затем я добавил функцию в user-extensions.js selenium, которая выглядит примерно так:

Selenium.prototype.getIsNetworkReady = function() {
    if(this.browserbot.topWindow.isNetworkReady) { //sometimes this method is called before the page has loaded the isNetworkReady function
        return this.browserbot.topWindow.isNetworkReady();
    }
    return false;
}

Также обратите внимание на check on topWindow: это потому, что вы получаете проблемы при выборе iframe.

Кроме того, вам нужно будет вызвать метод wrapRequest для объекта XMLHttpRequest для каждого загружаемого iFrame. Я делаю это прямо сейчас, используя: document.addEventListener("DOMNodeInserted", onElementAdded, true);, а затем в onElementAdded. Я просто захватываю iframe, когда он загружается и проходит объект XMLHttpRequest. но это не работает в IE, поэтому я ищу альтернативу. Если кто-то знает, как лучше это сделать, так что он работает как в IE, так и в FF, я бы хотел его услышать.

В любом случае, суть реализации. Надеюсь, это поможет любому в будущем.

Ответ 2

Существует несколько типов waitFor, доступных в Selenium. В тестовом примере, если вы знаете, что конкретный текст появится на странице загрузки, вы можете использовать waitForText. Если есть разные элементы DOM, которые заполняются (через Ajax/pageload), вы можете последовательно добавлять waitForText.

Ответ 3

После тестирования всех вариантов, описанных на этой странице, мы получили эту стратегию:

Внесите специальный javascript, который в основном отменяет все ваши соответствующие методы инфраструктуры и хранит счетчик количества незавершенных запросов, который увеличивается при запуске и уменьшается на завершение. Из-за асинхронного характера javascript недостаточно поддерживать логическую переменную, вы, скорее всего, окажетесь в условиях гонки в своей собственной логике.

Если вы используете визуальные эффекты, вы, вероятно, захотите сделать это и для визуальных эффектов; морфинг/затухание и другие визуальные эффекты будут иметь одинаковую проблему.

Итак, мы в основном делаем обычный "click", а затем всегда ждем, когда этот счетчик снова достигнет 0, используя javascript, как и другие, предлагаемые здесь. После того, как мы получили это место, мы уменьшили временные проблемы до уровня.

Помните, что селен не возвращается с "click" до тех пор, пока все синхронные события onclick не будут обработаны, поэтому вы должны убедиться, что эти счетчики увеличиваются как прямые последствия onclick.

Для получения инструкций о том, как переопределить методы инфраструктуры, вам необходимо проконсультироваться с вашей каркасной документацией; мы используем addMethods в прототипе. Можно сохранить это переопределение в специальном javascript, который добавляется только на страницу при выполнении тестов.

Ответ 4

У нас уже есть код на стороне клиента, чтобы изменить курсор мыши во время AJAX-запроса (используя a4j:status с атрибутами onstart и onstop). Поэтому мы можем просто ждатьДля значения выражения JavaScript

window.document.body.style.cursor

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

Что касается сокращения ненужной задержки, вы можете выполнить опрос себя и опросить чаще, чем селен.

Ответ 5

Это может быть неприемлемо для вас, но из-за подобных проблем мы перешли в Selenium 2 (он же WebDriver). Мы используем PageFactory с AjaxElementLocatorFactory

Чтобы облегчить миграцию, существует Selenium Emulation, и план состоит в том, чтобы полностью объединить Selenium 1 и WebDriver, что является главной целью Selenium 2.

Ответ 6

Да, сделайте что-нибудь вроде этого (Pseudocode):

int i = 0;
while (element is not yet present) {
  i++;
  if (i>TRESHOLD) {
    throw an exception
  }
  Thread.sleep(200);
}
//go on

Вы можете использовать его в функции.