[Заметка] [C#] WebDriverWait и PageObject

##Проблема
Казалось бы, реализация PageObjects и WebDriverWait находятся очень близко друг к другу, прямо в соседних пространствах имен, соответственно:

  • OpenQA.Selenium.Support.PageObjects
  • OpenQA.Selenium.Support.UI

И я думаю, многие задавались вопросом: а почему WebDriverWait не умеет работать с элементами PageObject «из коробки?»
Можно, конечно же, «подружить» их между собой… но, тут есть возникает несколько проблем:

  1. Во-первых, вам нужно будет самостоятельно отлавливать некоторые исключения, например, StaleElementReferenceException
  2. Для создания класса 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… и просто писать тесты, забыв о львиной доли рутинной работы.

Все эти, и другие хорошие практики работы с Вебдрайвером, несомненно войдут в фреймворк.

Сейчас там еще мало чего реализовано и работа кипит.

Код фреймворка можно найти тут: