Селен очень медленно читает DOM
Взаимодействие Selenium с DOM кажется чрезвычайно медленным, хотя в каждой странице создается пара вещей. По всему сайту у нас есть видимый счетчик, который указывает, разрешены или нет любые ожидающие вызовы API. Таким образом, у меня есть три метода, которые обеспечивают стабильность страницы перед выполнением каких-либо действий.
- Проверьте состояние готовности DOM
- Проверьте все ожидающие вызовы JQuery
- Проверить загрузку блесны
Все эти три выполняются как часть создания объекта страницы с помощью следующих методов.
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] с]]
Среда:
- Селен 2,48
- Firefox 38
Я также пытался с Selenium 2.52 и Firefox 44 с тем же результатом
2 ответа
Ваш тест, кажется, все non-native
звонки и поэтому Firefox должен работать для вас, но я удивлен, что собственный вызов Firefox для driver.navigate() даже работал для вас, чтобы перейти на начальную страницу, если вы использовали 44 и 48. Хорошо известно, что 31.6.0 был последняя поддерживаемая версия Firefox. Итак, я бы сказал, что вы должны использовать Chrome, пока вы не поймете это.
Но, чтобы ответить на вашу вещь о медлительности. То, как вы написали свой код, вы сильно зависите от jQuery, и я думаю, что у вас возникла проблема с задержкой вызовов вашего кода jQuery, которая распространяется на ваш тест Selenium, и на нее еще больше влияет тот факт, что ваш цикл повторяется через несколько блесны. Одна вещь, которую я заметил ранее, состоит в том, что если страница занята выполнением вызовов ajax, то ваши вызовы Selenium с JavascriptExecutor, возможно, придется ждать в очереди, чтобы те отдавали биты процессорного времени.
Что бы я сделал по-другому? Ну, я бы написал, что мой счетчик ждет, чтобы работать на DOM, а не вызывать JavascriptExecutors для jQuery. Возможно, в вашем случае это не вариант, но я думаю, что хорошо продуманный план может повысить эффективность рабочего процесса, готового к вашей странице.
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);