Нахождение вебэлемента перед каждым его использованием

Здравствуйте! 

В процессе автоматизации на Selenium WD + C# столкнулся с такой вот интересной проблемой - часто и довольно радномно тесты падают по причине того,  что страница слегка меняется и драйвер "теряет" обьвленный и залокейченый элемент. Как результат - Element not found in cache exception.

Наиболее часто данная проблема проявляется при длинных циклах проходящих по вебэлементам. 

 Для борьбы с такой проблемой я нашел такой выход:

1. Написал свои кастомные методы Файнд Элемент и Файнд Элементс, в которых задаю таймаут для нахождения элемента. (С помощью Explicit Wait).

2. При любой манипуляции над элементом я вызываю свой кастомный метод, нахожу элемент, а лишь потом выполняю требуемую операцию. 

Например: 

Клик на элементе - FindPageElement(driver, By.Id(""), 5).Click();

В таком случае проблем с потерей вебэлементов нет - фактически я не обьвляю веб элемент (как IWebElement element = driver.FindElement(By);), а нахожу его перед каждым использованием:

FindPageElement().Click();

FindPageElement().SendKeys();

e.t.c.

Но возникает вопрос - корректно ли так делать - не обьявлять веб элемент напрямую, а использовать кастомный метод. . 

И еще вопрос - можно ли каким-то другим образом перед каждым действием над элементом знать, что элемент активен или заново его локейтить? 

Заранее благодарен всем Вам  за ответ\совет. 

 

 

Посмотри в сторону PageFactory, @FindBy

http://code.google.com/p/selenium/wiki/PageFactory

И после можешь почитать советы Баранцева, я по ним сам реализовал то, что тебе надо

http://smartresponder.ru/web_version.php?Action=ShowArchiveMessage&q=000DtG000H4A004GNt1643ca1c

http://smartresponder.ru/web_version.php?Action=ShowArchiveMessage&q=000DtG000H4A004Hpq7b8ef1da

тут даже пожалуй более чем тебе надо. Можно даже заставить ожидать (в течение некоторого таймаута), пока твой WebElement станет видимы

Но возникает вопрос - корректно ли так делать - не обьявлять веб элемент напрямую, а использовать кастомный метод. .

 

у меня в проекте реализованно как раз так.

имхо: вполне нормальное решение, если не использовать PageFactory

примерно как то так http://pastebin.com/ebuXJ0sY

 

Сам подход вполне нормальный. Единственное, к чему я могу придраться – это к коду :)
Возможно, действительно лучше посмотреть в сторону PageObject/Page Factory, как советовал @dev_il?  Это, конечно же, по началу более сложное решение, но к нему вы быстро привыкните, и оно делает код более поддерживаемым. 
 
Если же вы не планируете использовать PageObject в проекте, то я бы посоветовал глянуть на фреймворк Coypu, который позволяет писать вот такой код: 
// Drop downs
browser.Select("toyota").From("make");

// Text inputs
browser.FillIn(“keywords”).With(“hybrid”);

// File inputs
browser.FillIn(“Avatar”).With(@“c:\users\adiel\photos\avatar.jpg”);

// Radio button lists
browser.Choose(“Trade”);
browser.Choose(“Private”);

// Checkboxes
browser.Check(“Additional ads”)
browser.Uncheck(“Additional ads”)

 
Вызов каждого метода будет находить нужный элемент "по-новой". 
 

Огромное спасибо за советы.

Проблема в использовании Пейдж Обджекта у меня на проекте

Процесс автоматизации у меня на проекте заключается в

1. Написание сценариев в стиле BDD (с помощью Specflow)

2. Имплементация шагов для каждого сценария.

3. Имплементация новых или использование уже реализованных методов для взаимодействия с обьектами на странице.

Пример двух разных шагов в сценарии:

When I log in to site as user ' '  - в этом случае использую метод LogIn который реализован с помощью пейдж обджекта - очень приятно и хорошо.

When I check ' ' checkbox - общий шаг - реализован без пейджобджекта, применим для любой страницы.

Сосбтвенно проблема состоит в том, что я использую в автоматизации шаги и первого и второго типов.

Вопрос: можно ли так делать - т.е. для комплексных шагов использовать Пейдж Обджект, а для элементарных - общие методы. Не противоречит ли это принятым стандартам написания автотестов?

 

 

В этом вопросе "правильно" – это как вам удобней.  
А принятых стандартов написания тестов – просто нет. 
 
Просто, если вы используете два подхода – то может появится дублирующий код. Т.е. одни и те же локаторы будут разбросаны по разным файлам. 
Если локаторы не меняются – проблем может и не быть. 
 
У меня другая ситуация. UI приложения очень хрупкий, постоянно какие-то изменения. Бывает так что появляются несколько элементов с одинаковым id на странице, команда распределенная, так что пока вопрос решится – может целая куча времени пройти. 
Для меня нет другого выхода, чем не дублировать локаторы и выделять более обобщенные функции в классах страниц чтобы можно было легче локализировать завал.
 

А зачем ты так делаеш? 

((webElement.Displayed) && (webElement.Enabled))

в каких случаях тебе недостаточно просто (webElement.Displayed)  ??

ps: может кто подскажет когда
driver.isEnabled() вообще используется?  

у нас используется ext-js на проекте, и встречаются такие ситуации, вполне номральные - но если с элементом надо что то сделать (кликнуть, ввести текст и т.д.) то он обязан быть enabled

Возможно это специфика фреймворка (код элемента ниже - кнопка реально disabled, т.е. не доступна для нажатия , у enabled элементов нет свойства "disabled")

 

<button id="tab-1408-btnEl" class="x-tab-center" autocomplete="off" role="button" hidefocus="true" type="button" aria-disabled="true" disabled="">
...
</button>

 

p.s. если не хочется использоваться Element.Enabled - не используйте, я лишь привел пример...

на сколько я понимаю метод isEnabled() работает по принципу WebElement.GetAttribute("disabled"));

если будет время, завтра посмотрю исходники вебдрайвера.

 

по enabled/disabled - что бы было более понятно, я имею ввиду это:

Увы - данное решение не панацея, так как все равно остается вероятность поймать StaleElement. И эта неприятная штука, как обычно, вылазит "внезапно" и совсем не к месту.

Дело в том, что апдейт DOM'а можно словить даже в такой строчке

driver.findElement(By.xpath("//xpathloc")).click()

т.е. драйвер найдет элемент, затратив на это какое-то время, а в этот момет элемент станет Stale, и click() уже не пройдет.

Единственным 100% решением является намеренное ожидания стейла - все остальное - полумеры. Хотя бывают такие ситуации, что кроме sleep ничего в голову не приходит.