Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- protected static <T> T waitUntil(By locator, Condition<T> condition, long timeoutMs)
- ...
- public static <V> V assertThat(By locator, Condition<V> condition) {
- return assertThat(locator, condition, Configuration.timeout);
- }
- ...
- public class Configuration {
- public static long timeout = 4;
- ...
- /*
- следи за размерностью таймаута )
- waitUntil - хочет миллисекунды
- assertThat - передает - 4 миллисекунды
- так что - все ждет))) 4 миллисекунды
- красивое решение - прийти к таймауту одной размерности - везде в проекте
- чтоб не думать - где пересчитывать, а где не пересчитывать
- ну и в самом тест-классе - не мешало бы увеличить таймаут по умолчанию
- вспомни - мы до 15 секунд, а то и до всех 20 увеличивали
- заодно - обеспечь одинаковое название для понятия - таймаут
- но и это еще не все)
- */
- NoSuchElementException
- /*
- с такой ошибкой тест начинает падать - буквально на попытке нажать compose
- и это исключение лови в waitUntil
- после этого тест задаботает
- */
- **************************************
- CustomConditions
- /*
- уже не нужен
- прибивай
- ходить подсматривать логику кондишенов - будешь в другой свой репозиторий)
- */
- ********************************
- public abstract class Condition <T> {
- /*
- переноси в пекедж conditions
- кстати - пекеджи называют маленькими буквами
- https://google.github.io/styleguide/javaguide.html#s5.2.1-package-names
- могут быть сложности с тем, чтоб зафиксировать это в репозитории
- когда ты меняешь лишь регистр буквы в названии -
- с точки зрения репозитория ничего не поменялось (case insensitive)
- вот полезные линки про эту проблему
- https://www.patrick-wied.at/blog/rename-files-and-folders-with-git
- http://stackoverflow.com/questions/8481488/is-git-not-case-sensitive
- http://stackoverflow.com/questions/17683458/how-do-i-commit-case-sensitive-only-filename-changes-in-git
- http://stackoverflow.com/questions/8904327/case-sensitivity-in-git
- http://stackoverflow.com/questions/3011625/git-mv-and-only-change-case-of-directory
- если это сложно, то можно поступить так
- если надо поменять лишь регистр буквы в названии (pageObject -> pageobject)
- и отразить эти изменения в репозитории
- 1)добавляем к названию еще какую-нибудь букву/цифру (pageObject -> pageObject1)
- 2)обновляем репозиторий
- 3)корректируем название на нужный нам вариант (pageObject1 -> pageobject)
- 4)обновляем репозиторий
- таким образом - изменения в регистре букв будут корректно отражены в репозитории
- т к каждый раз названия менялись не только за счет регистра букв
- */
- ********************************
- /*
- хорошая идея - реализовать умное ожидание в отдельном классе
- с точки зрения Single Responsibility - так будет лучше
- наглядно этот класс назвать WaitFor
- а статический метод-умный ожидатель выполнения кондишена - until
- и в коде мы будем писать waitFor(byCss(...)).until(visible())
- получится очень наглядная и понятная фраза
- в том же классе - расположи и метод sleep
- а его сделай - private
- т к sleep будет нужен только для реализации ждущей проверки
- чтобы так писать - waitFor(byCss(...)).until(visible())
- реализуй конструктор с параметром By locator
- реализуй статический метод waitFor с параметром By locator
- возвращающий - новый объект класса WaitFor
- реализуй метод until(...)
- получишь
- waitFor(byCss(...)). - создали объект типа WaitFor
- until(visible()) - вызвали у него метод until
- конечно, until-у передаай как кондишен, так и таймаут
- уже второй вариант until-а - без таймаута (также как и раньше - такой берет таймаут по умолчанию
- */
- ******************
- throw new TimeoutException("", lastError);
- /*
- про сообщение об ошибке в until
- failed while waiting ... seconds
- to assert __condition___
- __condition___ - это как раз toString кондишена
- */
- **********************
- catch (NoSuchElementException| StaleElementReferenceException | ElementNotVisibleException | IndexOutOfBoundsException e) {
- /*
- посмотри - какие предки есть у исключений
- все кроме IndexOutOfBoundsException
- приводятся к WebDriverException
- можно ловить именно его - WebDriverException (его потомков мы так тоже поймаем)
- и IndexOutOfBoundsException
- */
- ************************************
- /*
- Иерархия для кондишенов у тебя сейчас - достаточно простая
- интерфейс
- и классы-кондишены, имплементирующие его
- Минимально необходимая реализация есть
- Будем ее развивать
- Далее - реализуй абстрактный класс-предок AbstractCondition<V> ,
- который имплементирует интерфейс Condition<V>
- Статья про нейминг
- http://www.vertigrated.com/blog/2011/02/interface-and-class-naming-anti-patterns-java-naming-convention-tautologies/
- Теперь смотрим дальше
- Нам хочется, чтобы наш toString() для любого кондишена был хорошо структурирован
- Это значит, чтобы фразы были типа
- имя кондишена +
- for ____element/elements___ found by: ___locator___
- expected ___expected result desription_____
- actual ____actual result description
- Можно конечно в каждом из кондишенов просто строить такую фразу
- согласно правилу
- А можно - toString() реализовать в абстрактном классе, и внутри этого метода - вызывать абстрактные методы
- а их уже - реализуем в потомках. Таким образом - структура сообщения любого из кондишенов
- будет одинаковой
- Имя кондишена
- раз мы будем реализовывать кондишены как отдельные классы - потомки (пока - нашего абстрактного класса)
- то откуда взять имя кондишена - у нас есть
- у нас есть имя класса кондишена - чем не имя )
- Далее
- element/elements
- Это только верхушечка айсберга
- Да, схема проверки кондишенов - у нас одна и та же
- Хоть это кондишен для списка элементов
- Хоть для элемента
- И нам нужно, чтоб наш waitUntil был один и работал с любым кондишеном
- Но
- Нам важна разница - что это за кондишен - для элемента или коллекции
- В данный момент - чтобы сказать про то в фразе - for ____element/elements
- А далее (в следующих заданиях) - чтобы кондишены для element - мы просто НЕ МОГЛИ применить к elements
- Таким образом, приходим к тому, что у нашего общего предка AbstractCondition<V>
- Будут 2 абстрактных потомка
- CollectionCondition extends AbstractCondition<List<WebElement>>
- ElementCondition extends AbstractCondition<WebElement>
- От которых мы будем наследовать наши реальные кондишены
- И тогда, стоит держать 2 класса для реализации статических методов - вызовов кондишенов
- CollectionConditions и ElementConditions
- это будут классы-контейнеры статических методов
- типа
- public static Condition<WebElement> visible() {
- return new Visible();
- }
- чтобы уже в коде - не писать - new Visible()
- С иерархией разобрались немного )
- Возвращаемся к фразе в toString()
- Если этот метод реализовать в главном предке AbstractCondition,
- и этот метод будет использовать абстрактные методы, возвращающие строки
- для всех элементов этой фразы
- То структура сообщения о кондишене - будет всегда четкой
- А нам останется - реализовать эти абстрактные методы, возвращающие строки
- в потомках
- Тут будь внимательной
- Некоторые из методов надо будет реализовать уже в кондишенах-потомках
- Некоторые - в CollectionCondition и ElementCondition
- Руководствуйся такими рассуждениями
- Если во всех потомках я пишу одинаковый код
- То лучше этот код написать в предке
- Что касается типа параметра condition для
- until(Condition<V> condition)
- Ты можешь указать интерфейс Condition<V>
- И метод будет корректно работать для любого из кондишенов
- Т к этот интерфейс лежит в основе этой иерархии
- */
- ***************************************************
- /*
- еще один наворот внутри кондишенов)
- мы его впоследствии переделаем
- сейчас нам это нужно для лучшего понимания процесса
- в apply передают локатор
- описание которого мы возвращаем в одном из методов кондишена (для ToString)
- и это - справедливо для всех кондишенов
- потому в AbstractCondition заводим переменную locator
- в которую сохраняем переданный в apply локатор
- и уже в методе, возвращающем описание локатора,
- оперируем этой переменной
- сразу подумай, какой модификатор доступа использовать для такой переменной
- http://www.quizful.net/interview/java/access-modifiers
- но это опять была только верхушка айсберга)
- посмотри на реализованные кондишены
- первой строкой в методе проверок - у тебя идет
- List<WebElement> elements = getDriver().findElements(elementsLocator);
- или
- WebElement element = getDriver().findElement(elementsLocator);
- (таких, кстати, пока нету
- реализуй
- visible
- present
- text
- exactText
- )
- Так вот
- фактически - вот это
- List<WebElement> elements = getDriver().findElements(elementsLocator);
- или
- WebElement element = getDriver().findElement(elementsLocator);
- это сущность типа V с точки зрения класса AbstractCondition
- давай метод check изменим
- пусть принимает не локатор
- а уже V entity (т е внутри кондишена в реализации check
- нам ничего не придется искать по локатору - нам это уже на вход передадут)
- а вот в реализации apply в AbstractCondition
- для получения этого V entity
- мы объявим новый абстрактный метод getWrappedEntity()
- который будет нам возвращать значение типа V
- а реализуем его в классах CollectionCondition и ElementCondition
- думаю, ты догадаешься, как )
- а вот потом, когда у нас будут наши классы для элементов (следующее задание)
- мы будем в apply передавать не локатор
- а сам элемент нашего нового класса
- и сам элемент будет возвращать getWrappedEntity()
- и мы тут, в кондишенах, избавимся от getWrappedEntity() и его реализаций )
- пока это такой костыль
- нарушающий принцип Single Responsibility
- но позволяющий нам сейчас максимально реализовать код
- который впоследствии изменим минимально
- */
Advertisement
Add Comment
Please, Sign In to add comment