Всем,Привет)
Хотелось бы обратиться с вопросом.
Не могу добиться стабильности работы ожидания. Использую C# и webdriver.
Нарушается последовательность кликов.
По теме получения коллекции элементов:
Для списочных однотипных элементов (например, содержимое каталога) использую получение списка (FindElements вернёт ReadOnlyCollection<IWebElement>), сортировку или фильтрацию элементов с помощью Linq (OrderBy, Where). Например, в результате запроса было возвращено 1000 ссылок. Все они есть на странице, но 50 из них отображены, а остальные скрыты (просто уже подгрузились ajax-ом). Таким образом нам нужно получить только те элементы из результата запроса, что видимы. И, допустим, нет доверия к порядку выдачи элементов на страницу, поэтому самостоятельно сортируем список элементов по значению атрибута id.
Псевдокод (в целом, псевдокод не совсем корректный, так как после FindElements и Where нужно проверять, что в коллекции есть хоть один элемент, иначе будет исключение (работа с пустым списком)):
var collectionLinks = Browser.FindElements(By.CssSelector(".list_item")).Where(webElement => (webElement.Displayed == true)).OrderBy(webElement => webElement.GetAttribute("id"));
foreach(var link in collectionLinks)
{
link.Click();
//...обработчик реакции на щелчок по ссылке
btn1.Click();
//...обработчик реакции на щелчок по кнопке
}
На псевдокоде всё красиво. В реальности элементы вытесняются из dom-модели (при щелчке по элементам (ссылке и кнопке), dom-модель перестраивается, и в результате ссылки на IWebElement, что хранятся в коллекции collectionLinks со временем становятся неактуальными - WebDriver скажет, что элемента нет в кеше).
Даже получение статуса видимости и получение атрибута id может создать ажиотаж работы с dom-моделью (если список большой, то обращений получится много), в результате ажиотажа с большим количеством элементов, другая часть элементов (в силу их относительной неиспользуемости) устареет. Это гипотеза, почему на самом деле так происходит не знаю (возможно, причина в самом тестируемом сайте: на сайте, что тестирую, огромное количество обработчиков на каждое событие - любое действие, любой клик, вызывают реакцию разнородного javascript-кода, который, работая асинхронно и запускаясь по таймеру, сам может в любое время создавать и менять элементы страницы, понижая удобство тестирования).
И к моменту завершения операции фильтрации и сортировки:
var collectionLinks = Browser.FindElements(By.CssSelector(".list_item")) //Получение коллекции
.Where(webElement => (webElement.Displayed == true)) //Фильтрация
.OrderBy(webElement => webElement.GetAttribute("id")); //Сортировка
коллекция уже может содержать устаревшие ссылки (если элементов было очень много).
И поэтому приходится отказываться от работы с большими коллекциями элементов, работая с одиночными элементами или малыми коллекциями.
По теме ожидания:
Базовый Explicit Wait и Implicit Wait у меня не работают. Поэтому использовал дополнительный поисковый механизм. На основу был взят способ из фреймворка TestStack.Seleno, где все операции по поиску элементов сосредоточены в объекте Finder, который возвращается по вызову метода Find() (объект и метод - часть TestStack.Seleno, их нет в Selenium.WebDriver).
На псевдокоде, например, поиск одиночного элемента выглядит так:
var stopWaitTime = DateTime.Now.AddSeconds(paramMaxWaitTime);
IWebElement result = null;
do
{
result = ... тут поиск элемента по нужным критериям
}
wail((result == null) && (DateTime.Now <= stopWaitTime))
return result;
В TestStack.Seleno поиск выглядит так:
https://github.com/T...lementFinder.csа конкретно ожидание элемента использует базовый wait и сделано как метод расширения ElementWithWait (но у меня оно не работало):
https://github.com/T...erExtensions.csТакой функционал позволяет быть точно уверенным, что элемент будет искаться в течение указанного времени. А также позволяет писать подробные ошибки в лог, генерируя исключения с точным описанием, что поиск выполнялся в течение указанного времени, выполнялся по селектору ..., выполнялся относительно конкретного элемента ... или относительно страницы, и при этом, ещё сделать снимок экрана, сохранить в отладочный лог содержимое страницы, на которой нужный элемент так и не был найден. И всё это в одном месте - в дальнейшем не придётся дублировать код.