##Проблема
Казалось бы, реализация PageObjects и WebDriverWait находятся очень близко друг к другу, прямо в соседних пространствах имен, соответственно:
- OpenQA.Selenium.Support.PageObjects
- OpenQA.Selenium.Support.UI
И я думаю, многие задавались вопросом: а почему WebDriverWait не умеет работать с элементами PageObject «из коробки?»
Можно, конечно же, «подружить» их между собой… но, тут есть возникает несколько проблем:
- Во-первых, вам нужно будет самостоятельно отлавливать некоторые исключения, например, StaleElementReferenceException
- Для создания класса WebDriverWait, в конструктор необходимо отдельно передать экземпляр вебдрайвера или веб-элемента… Но, по сути, внутри элемента PageObject уже есть этот экземпляр…
Конечно же, магией внедрения зависимостей и реализовывая все интерфейсы на своем пути, можно добиться «правильного и благородного» решения этой проблемы… И, при этом, переопределить 95% кода.
Раз так, то почему бы не переписать все 100%, и сделать код проще?
Решение
В C# есть одна замечательная фича – это методы-расширения.
Если вы еще не знакомы с этой темой, то рекомендую послушать .NET-девочку:
А в нашем примере, специальный метод-расширение .WaitUntilVisible()
, будет «прилипать» ко всем элемента типа IWebElement
, и выглядеть это будет так:
var page = new YandexPage();
page.txtSearchBox.WaitUntilVisible().SendKeys("Google");
В данном примере WaitUntilVisible()
– будет вызван для txtSearchBox
.
Он подождет в течении секунды появления элемента, а дальше:
Либо, выбросит исключение, если элемент не найден
Либо, продолжит выполнение операции SendKeys.
Сам алгоритм ожидания реализован в классе Wait (Wait.cs).
Wait.UntilVisible(…)
– принимает элемент страницы, второй – граничное время ожидания.
Расширения реализованы в классе WebElementExtensions
Которые, просто передают нужные параметры в Wait.UntilVisible(element, timeOut)
;
https://gist.github.com/dzhariy/7013245
А сам тест и реализованный PageObject – ниже.
В этом примере элемент page.txtSearchBox, будет найден сразу же.
page.txtSearchBox.WaitUntilVisible().SendKeys("Google");
А вот появления элемента page.txtInvalidSearchBox – код подождет один день, и выбросит TimeOutException (если за это время, элемент не появится на странице)
page.txtInvalidSearchBox.WaitUntilVisible(TimeSpan.FromDays(1)).SendKeys("Google");
[TestFixture]
public class Class1
{
public class YandexPage : CorePage
{
[FindsBy(How = How.XPath, Using = @"id(""text"")")]
public IWebElement txtSearchBox { get; set; }
[FindsBy(How = How.XPath, Using = @"id(""Trololo-locator"")")]
public IWebElement txtInvalidSearchBox { get; set; }
}
[Test]
public void FirstTest()
{
SwdBrowser.Driver.Navigate().GoToUrl(@"http://yandex.ru");
var page = new YandexPage();
page.txtSearchBox.WaitUntilVisible().SendKeys("Google");
page.txtInvalidSearchBox.WaitUntilVisible(TimeSpan.FromDays(1)).SendKeys("Google");
}
}
Еще, значение можно передавать в миллисекундах, например, следующий код, будет ждать появления элемента ровно 5 сек:
page.txtInvalidSearchBox.WaitUntilVisible(5000).SendKeys("Google");
Минутка наглого пиара:
Сейчас, я работаю над фреймворком для автоматизированного тестирования на Selenium WebDriver. Задумка в том, что для начала автоматизации, вам нужно будет лишь скачать его с Github… и просто писать тесты, забыв о львиной доли рутинной работы.
Все эти, и другие хорошие практики работы с Вебдрайвером, несомненно войдут в фреймворк.
Сейчас там еще мало чего реализовано и работа кипит.
Код фреймворка можно найти тут: