WebDriver API достаточно обширно, но и оно имеет некоторые ограничения. Хочу поинтересоваться у сообщества. Подскажите исходя из вашего опыта, где возможностей WebDriver обычно не хватает и нужно использовать хуки на JavaScript, чтобы обойти ограничения? Или допустим, где вебдрайвер может глючить и хуки на JavaScript работают более эффективно?
Ранее я работал с PHP + Mink драйверами на Selenium2. Там практически все действия пользователя реализованы не через апи вебдрайвера, а через javascript и библиотеку Syn.js. Сейчас я перевожу всё на чистый вебдрайвер, и в связи с этим у меня и появился этот вопрос.
Ээээ не-не, не пойду по дороге негатива и феэлов ВебдРайвера, и начну с киллер фичи, которой нет и быть не может (пока что) в JavaScript
Это: nativeEvents
Эта фича работает немного медленнее, чем JavaScript аналог, но зато позволяет эмулировать реальный клики и наборы текста в браузере.
В некоторых веб-приложениях есть обычай блокировать пользовательский интерфейс в момент выполнения некоторого Ajax запроса. Это может быть сделано путем добавления div элемента по верх всей страницы. Так вот, используя nativeEvents, веб драйвер не сможет кликать или набирать текст в заблокированые таким образом поля и не сможет набирать текст, как это бы не мог сделать реальный пользователь. А кликать будет не по элементу найденному в DOM-дереве страницы, а по вычисленным координатам, и клик этот пройдет через весь веб браузер , что создает более реалистичную симуляцию работы пользователя, чем через JavaScript. Недостаток в том, что работает медленнее, но, в любой момент можно переключится на JavaScript-симуляцию. Я в основном работаю через JavaScript-симуляцию, (nativeEvents = false), но пару раз в неделю прогоняю тесты с nativeEvents = true
Скорость работы
Сам протокол REST, через который работает WebDriver, довольно тормознутый.
Ну, например, мы хотим вывести в лог все теги input и их value в лог.
В этом случае, первый запрос получит список внутренних ID найденных элементов.
Потом в цикле , для каждого элемента, запрос 1 получит тэг, запрос 2 – value.
В таком случае, может быть лучше запустить JavaScript для того чтобы собрать всю информацию за один раз. А JavaScript можно запустить посредством самого вебдрайвера.
AJAX
Вебдрайвере есть конечно WebDriverWait для ожидания появления некоторого элемента при Ajax запросе, но если используется jQuery – то лучше у нее и спросить, закончился запрос или нет:
public void WaitForAjax()
{
while (true) // Handle timeout somewhere
{
var ajaxIsComplete = (bool)(driver as IJavaScriptExecutor).ExecuteScript("return jQuery.active == 0");
if (ajaxIsComplete)
break;
Thread.Sleep(100);
}
}
Кривые руки программистов некоторых фреймворков
В приложении написаном на knockout + bootstrap (вот не знаю кого конкретно ругать) у текстового поля, которое я проверял на свойство disabled, как раз этого свойства и не было, хотя для пользователя оно было недоступно. Оказалось, что в недрах knockout’а (или bootstrap) у этого поля было нестандартное свойство isEnabled, которое никак не обновляло стандартное HTML’ное disabled.
Приходилось лезть в недра JavaScript’а и получать это свойство.
Фреймы недоступны в JavaScript
Через JavaScript и без помощи WebDriver – нельзя обращаться из одного фрейма в другой (который ведет на другой сайт). В Вебдрайвере – можно.
Вебдрайвер сам использует очень много JavaScript
Сам вебдрайвер инжектит очень много JavaScript. Везде есть баги, но я всегда более уверен в том, что в реализации Вебдрайвера их меньше, чем в моей реализации. Почему? Потому что этот код уже от тестирован тысячами пользователей на разных платформах.
Кроме того, очень удобным образом можно инжектить и пользовательский JavaScript, так что, в случае чего, всегда можно заменить стандартную реализацию на свою.
Итог
Своя реализация на JavaScript, с одной стороны, может быть более быстрой для некоторых задач. Но, при этом, уже реализованные методы в Вебдрайвере – более оттестированы другими людьми на разных платформах. Тут нужно учитывать фактор надежности кода против производительности.
Хотим ли мы получить более быстрый, но, менее надежный код в итоге?
конечно для некоторых случаев есть нативная поддержка через определенные методы
я тебе просто рассказываю частые случае, в которых люди пытаюсь выполнить что-то javascript, чтобы решить их задачу (просто я думал, ты об этом спрашивал)
[quote=“davert, post:1, topic:3310”]
Подскажите исходя из вашего опыта, где возможностей WebDriver обычно не хватает и нужно использовать хуки на JavaScript, чтобы обойти ограничения?
[/quote]Везде хватает.
[quote=“davert, post:1, topic:3310”]
Или допустим, где вебдрайвер может глючить и хуки на JavaScript работают более эффективно?
[/quote]Везде может глючить: тайпы, клики, isDisplayed и т.д. Но, имхо, нужно придерживаться следующей стратегии:
Пишем workaround на js
Помечаем его //TODO: remove when fixed
Выписываем/находим соответствующий баг в багтрекере селениума
Ждем фикса или просто проверяем с новым релизом WD
Удаляем workaround
Единственным случаем, когда при относительно (iedriverserver падал иногда) правильной работе WD, пришлось использовать js, было пару листбоксов/ддл с парой сотней айтемов. Вот тут WD нещадно тупил (счет не на секунды, а на минуты) на findElements.
[quote=“dzhariy, post:4, topic:3310”]
Я в основном работаю через JavaScript-симуляцию, (nativeEvents = false),
[/quote]Хочу добавить, что с этой опцией лучше отказаться от запуска скриптов в IE.
[quote=“dzhariy, post:4, topic:3310”]
но если используется jQuery – то лучше у нее и спросить, закончился запрос или нет:
[/quote]Код может и подкупает своей простотой и видимой надежностью, но на практике заставить его работать не получилось. jQuery.active == 0 не говорит о том, что все запросы выполнились.
Использовать или не использовать – тут все зависит от конкретного приложения. То, с которым я работаю – по сути синхронное, т.е. выполняет один запрос за другим и все это делается через только через jQuery. В таком случае jQuery.active == 0 всегда возвращает «истину». Но, опять же, вполне возможно, что когда-то это будет не так.
Ну, и иногда приходится комбинировать и запрос к jQuery и использовать свой аналог WebDriverWait для того чтобы дождаться элемента.
Я не имел ввиду параллельное/последовательное выполнение запросов. Между “действием” и инкрементом каунтера active может пройти достаточно времени, за которое WaitForAjax()
успешно пройдет, при том, что запрос не выполнился.
Либо WaitForAjax()
может попасть в промежуток, когда предыдущий запрос выполнился, а следующий еще не сформировался. В лучшем случае WaitForAjax() будет работать “вхолостую”, а ожидать окончания запросов/сетевого трафика будет драйвер (FF). В худшем (IE) тесты будут крайне нестабильны.