Selenium очень медленно читает DOM

Взаимодействие Selenium с DOM кажется чрезвычайно медленным при выполнении нескольких действий при каждом создании экземпляра страницы. На всем сайте у нас есть видимый счетчик, который указывает на любые ожидающие вызовы API, разрешенные или нет. Таким образом, у меня есть три метода, которые обеспечивают стабильность страницы перед выполнением каких-либо действий.

  1. Проверить состояние готовности DOM
  2. Проверьте наличие невыполненных вызовов JQuery.
  3. Проверить загрузку спиннеров

Все эти три выполняются как часть создания экземпляра объекта страницы с помощью следующих методов.

    public static void waitForLoadingAllSpinnersAnywhere(final WebDriver driver){
    final WebDriverWait wait = new WebDriverWait(driver, timeout);
    
    wait.until(waitForDomReadyState());
    wait.until(waitForjQueryToBeInactive());
    List<WebElement> elements = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(spinnersLoacator));
    
    for(WebElement element: elements){
        wait.until(invisibilityOfElementLocated(element));  
     }
    }

    private static ExpectedCondition<Boolean> waitForDomReadyState(){

        return new ExpectedCondition<Boolean>() {

            @Override
            public Boolean apply(WebDriver d){

                return ( ((JavascriptExecutor) d).executeScript("return document.readyState;").equals("complete"));
            }
        };
    }


    private static ExpectedCondition<Boolean> waitForjQueryToBeInactive(){

        return new ExpectedCondition<Boolean>() {

            @Override
            public Boolean apply(WebDriver d){

                return (Boolean) ( ((JavascriptExecutor) d).executeScript("return jQuery.active == 0;"));
            }
        };
    }

    public static ExpectedCondition<Boolean> invisibilityOfElementLocated(final WebElement element){

        return new ExpectedCondition<Boolean>() {

            @Override
            public Boolean apply(WebDriver driver){

                try{
                    return !element.isDisplayed();
                } catch (NoSuchElementException | StaleElementReferenceException e){
                    // Returns true because the element is not present in DOM.
                    // The
                    // try block checks if the element is present but is
                    // invisible or stale
                    return true;
                }
            }
        };
    }

Возьмем пример страницы (скажем, страницы пациента), которая имеет большое количество вызовов API и извлекает много данных. Для создания начального класса требуется около 17 секунд (журнал ниже). Мои знания Selenium говорят, что последующее создание экземпляра страницы не должно занимать столько же или больше времени, чтобы проверить состояние готовности DOM, или вызов JQuery или ожидание счетчика, поскольку вообще ничего не меняется. Однако каждый раз, когда создается экземпляр новой страницы, я вижу, что проверка всех этих трех занимает одинаковое количество времени. Что там происходит? Действительно ли Selenium пытается взаимодействовать с сервером каждый раз, когда я это делаю, или просто взаимодействие с клиентом по какой-то причине происходит медленно? Если да, то каким может быть возможный ответ?

Журнал консоли

==== [[Завершено ожидание 8 элементов счетчика, найденных в виджете [Пациент] после [17] с]]

==== [[Начать ожидание 8 элементов счетчика, найденных в виджете [Пациент] ]]

==== [[Завершено ожидание 8 элементов счетчика, найденных в виджете [Пациент] после [17] с]]

==== Браузер на [[[Patient]]]

==== [[Начать ожидание 8 элементов счетчика, найденных в виджете [Пациент] ]]

==== [[Завершено ожидание 8 элементов счетчика, найденных в виджете [Пациент] после [17] с]]

Окружающая среда:

  1. Селен 2.48
  2. Фаерфокс 38

Я также пробовал с Selenium 2.52 и Firefox 44 с тем же результатом.


person Saifur    schedule 17.02.2016    source источник
comment
Обычно, когда мой таймер всегда возвращает одни и те же результаты, я проверяю, что не так с таймером.   -  person Guy    schedule 17.02.2016
comment
@guy Не проблема с таймером, потому что он не обязательно возвращает одно и то же время все время, когда он находится в диапазоне 17-18.   -  person Saifur    schedule 17.02.2016
comment
Вы пробовали это в Chrome - та же проблема? Кроме того, вы изолировали проблему - это jquery, который сообщает об активности через 17 секунд, или счетчики, которые остаются видимыми в течение 17 секунд? Спасибо!   -  person alecxe    schedule 01.03.2016
comment
@alecxe Я не вижу такого же поведения в Chrome. Кроме того, я попытался отключить jquery, не относящийся к jquery.   -  person Saifur    schedule 04.03.2016
comment
@Saifur хорошо, это означает, что использование Chrome в этом случае является обходным решением, верно?   -  person alecxe    schedule 04.03.2016
comment
@alecxe ты прав. Но, к сожалению, бизнес хочет сначала использовать Firefox.   -  person Saifur    schedule 04.03.2016


Ответы (2)


Ваш тест, кажется, состоит из всех вызовов non-native, и поэтому Firefox должен работать для вас, но я удивлен, что собственный вызов Firefox для driver.navigate() даже работал для вас, чтобы перейти на начальную страницу, если вы использовали 44 и 48. Это хорошо известно, что 31.6.0 была последней поддерживаемой родной версией Firefox. Итак, я бы сказал, что вам следует использовать Chrome, пока вы не разберетесь с этим.

Но, чтобы ответить на ваш вопрос о медлительности. То, как вы написали свой код, сильно зависит от jQuery, и я полагаю, что у вас возникла проблема с задержкой ваших вызовов кода jQuery, которая распространяется на ваш тест Selenium, и на которую дополнительно влияет тот факт, что ваш цикл через несколько блесны. Одна вещь, которую я заметил раньше, заключается в том, что если страница занята выполнением вызовов ajax, то вашим вызовам Selenium с JavascriptExecutor, возможно, придется ждать в очереди, чтобы те отдали биты процессорного времени.

Что бы я сделал по-другому? Что ж, я бы написал, что мой счетчик ожидает работы с DOM вместо вызова JavascriptExecutors для jQuery. Возможно, в вашем случае это не вариант, но я думаю, что хорошо продуманный план может повысить эффективность вашего рабочего процесса подготовки страницы.

person djangofan    schedule 01.03.2016
comment
Я попытался отключить Jquery, и это не помогает. В итоге у меня был почти такой же результат. Во-вторых, как в этом случае будут различаться родные и неродные вызовы firefox? Не могли бы вы объяснить? Любой другой вариант я могу попробовать без каких-либо проблем. Идеи приветствуются - person Saifur; 04.03.2016

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

Таким образом, лучший способ повысить производительность в вашем случае — использовать один асинхронный вызов JavaScript:

public static void waitForLoadingAllSpinnersAnywhere(final WebDriver driver) {
  const String JS_WAIT_SPINNERS = 
      "var callback = arguments[0]; " +
      "(function fn(){ " +
      "  if (document.readyState == 'complete' && jQuery.active == 0) { " +
      "    var elts = $('.spinners'); " +
      "    if (elts.length == 8 && !elts.is(':visible')) " +
      "      return callback(); " +
      "  } " +
      "  setTimeout(fn, 60); " +
      "})();";

   ((JavascriptExecutor)driver).executeAsyncScript(JS_WAIT_SPINNERS);
}

Чтобы инициализировать тайм-аут:

driver.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);
person Florent B.    schedule 07.03.2016
comment
Мне кажется, очень позитивная техника. Но зачем использовать 60 в setTimeout()? - person Saifur; 08.03.2016
comment
Я думаю, что проверки состояния каждые 60 мс достаточно. Слишком частый опрос DOM был бы контрпродуктивным. Вы можете уменьшить значение, но я бы не стал меньше 10 мс. - person Florent B.; 08.03.2016
comment
Звучит отлично. Я награжу тебя наградой. Так как он обеспечивает самое близкое решение моей проблемы. Но я бы принял ответ Джангофана, поскольку его точка зрения также верна. - person Saifur; 08.03.2016