Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public abstract interface Condition<V>
- /*
- И этот интерфейс - расположи в пекедже conditions
- */
- ***********************************
- public V apply(By locator){
- this.locator = locator;
- V essence = getEssence();
- return essence;
- }
- /*
- про термин essense
- мне кажется более уместным - entity
- https://wikidiff.com/essence/entity
- нам нужно не только получить сущность
- но еще и проверить ее
- и по результтам проверки -
- либо сущность вернуть
- либо нулл
- а для проверки - нужен еще один метод
- check - собственно проверка
- этот метод - на уровне абстрактного класса объяви обстрактным
- и используй в реализации apply (на уровне абстрактного класса
- а уже как дело дойдет до реализации конкретных кондишенов - там и реализуешь check
- а apply - уже не будешь - ведь тут все будет реализовано
- что метод check должен делать - отвечать на вопрос - прошла проверка для нашей сущности или не прошла
- т е - возвращать от на должен - boolean
- а принимать в качестве параметра - сущность
- */
- **************************************
- public abstract class CollectionCondition extends AbstractCondition<List<WebElement>> {
- public List<WebElement> getEssence(){
- /*
- с реализацией этого метода - согласна
- */
- public String identity() {
- /*
- а вот тут - все значительно проще
- нам нужна просто строка
- for element
- или
- for elements
- для всех кондишенов-наследников CollectionCondition - это for elements
- а то и for collection - чтоб сразу бросилось в глаза - что речь не про один элемент
- похожая ситуация - с классом ElementCondition
- у нас же какая конечная цель = получить фразу
- __имя кондишена__ +
- for ____element/elements___ found by: ___locator___
- expected ___expected result description_____
- actual ____actual result description_____
- ты уже что-то похожее на уровне AbstractCondition - в toString - собираешь
- надо бы проверить это (это по финишу обязательно сделай, о уже по финишу)
- а для этого - нужно выполнить ждущую проверку
- которая заведомо должна упасть
- и в тексте описания ошибки - мы как раз эту фразу и должны увидеть
- и она должна будет помочь разобраться - что не так сработало
- вот тут уже - глядя на фразу - как раз и доравняешь это сообщение
- также обязательно - проверить работу ждущей проверки - на ситуации
- которая должна заведомо пройти проверку
- и это тоже должно подтвердиться экспериментом
- это - обязательные шаги в разработке кондишенов и своих механизмов ждущей проверки
- т к - если на этом уровне создать неверно работающую систему - то остальные старания - будут в общем-то бесполезны
- */
- ********************************************
- public class NthElementHasText extends ElementConditions{
- public WebElement apply(By locator) {
- public String toString() {
- /*
- мы специально реализовывали эти методы в абстрактном предке
- чтоб тут - уже не использовать их
- чтоб тут - логика кондишенов была проще
- тут - будем реализовывать те методы
- которые на уровне абстрактного класса - объявлены как абстрактные
- структура и логика методов - apply и toString - для всех кондишенов одна
- именно потому мы и смогли вынести это все на уровень абстрактного класса
- и тут, в реализации конкретного кондишена - мы лишь уточняем - реализуем методы,
- объявленные абстрактными в предке
- а сам скелет в apply и toString - един для всех кондишенов
- потому это достаточно реализовать единожды, на уровне предка
- */
- }
- ****************************************************
- public class NthElementHasText extends ElementConditions{
- ....
- public By locatorForString;
- /*
- на уровне предка - у нас уже хранится локатор
- да нам он и не нужен тут
- если тут мы будем реализовывать метод check
- параметром которого уже будет - вебэлемент/или спиок вебэлементов (в зависимости от типа кондишшена)
- то тут уже нам точно не понадобится работать с локатором
- */
- ...
- String expectedtext;
- /*
- не забывай про правила CamelCase
- https://google.github.io/styleguide/javaguide.html#s5.3-camel-case
- */
- ***************************
- if (actualText.contains(expectedtext)) {
- return element;
- }
- return null;
- /*
- вот такие вещи - удобно реализовать используя ternary operator (гугли)
- return (condition) ? resultIfTrue : resultIfFalse
- */
- **********************************************
- for(String text:expectedTexts) {
- this.expectedTexts.add(text);
- }
- /*
- можно применить Arrays.asList
- https://www.tutorialspoint.com/java/util/arrays_aslist.htm
- http://ru.stackoverflow.com/questions/488383/%D0%97%D0%B0%D1%87%D0%B5%D0%BC-%D0%BD%D1%83%D0%B6%D0%B5%D0%BD-%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-arrays-aslist
- */
- **************************************************
- http://joxi.ru/52akqzoU4GDQdr
- /*
- чтоб было легче разобраться - внутри пекеджа conditions
- создай 2 пекеджа -
- element
- collection
- и разложи классы
- в корне у conditions - останутся только общие вещи
- */
- *******************************************
- public static Texts texts(String... text)
- /*
- имя параметра - не текст - а текстЫ
- */
- **********************************************
- public class ElementConditions {
- public static VisibilityOfElement visible() {
- public static NthElementHasText nthElementHasText(int index, String text) {
- /*
- все такие методы - будут возвращать значениетипа интерфейс (приводила в прошлом ревью линки на тему интерыейсов-абстрактных классов - потомков)
- да, внутри метода - создаем объект такого-то класса
- но т к этот класс - имплементирует интерфейс Condition<...что-то конкретное уже...>
- то в качестве типа результата - используй Condition<...что-то конкретное уже...>
- правда, кондишен nthElementHasText придется реализовать не как ElementCondition
- а как CollectionCondition
- позже мы от него избавимся
- а пока - пусть apply возвращает список, а не элемент
- нам безразлично - что apply вернет - мы ведь не используем его результат
- а вот работаем мы - со списокм вебэлемента
- потому объявляй и реализуй как CollectionCondition
- ну и метод тогда будет - в CollectionConditions
- для кондишена про видимость элемента - visible() - хорошее имя
- тога и класс VisibilityOfElement - аналогично назови
- */
- *******************************************************************
- public class CustomConditions {
- /*
- а этот класс зачем нужен?
- ведь у нас уже есть CollectionConditions и ElementConditions
- */
- **********************************************
- assertThat(elementLocator, visibilityOfElement());
- /*
- вот тут как раз и видно будет - почему имя visible() - лучше
- сравни
- assertThat(elementLocator, visibilityOfElement());
- и
- assertThat(elementLocator, visible());
- согласись - второй вариант легче читать, фраза короче и проще понимается
- */
- ***************************************************
- public static <V> V waitUntil(By locator, Condition<V> condition, long timeout) {
- ...
- Throwable error = null;
- while(endTime > System.currentTimeMillis()) {
- try {
- ....
- } catch(StaleElementReferenceException | ElementNotVisibleException | IndexOutOfBoundsException e) {
- error = e;
- }
- sleep(waitTimeout);
- }
- throw new TimeoutException(String.format("Failed while waiting ['%s'] seconds to assert ['%s']", timeout / 1000, condition.toString()));
- /*
- ты в переменной error сохранил ошибку
- это ок
- и теперь - передай ее как второй параметр в конструктор исключения TimeoutException
- (посмотри сигнатуру такого конструктора - как называются параметры - зажми ctrl + наведи курсор мыши)
- передавать ошибку вторым парамтром нужно - чтоб сообщение об ошибке выглядело так
- имя возникшего кондишена + его сообщение
- а далее - caused by - описание
- */
- }
- /*
- хорошая идея - реализовать умное ожидание в отдельном классе
- с точки зрения 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-а - без таймаута (также как и раньше - такой берет таймаут по умолчанию
- */
Add Comment
Please, Sign In to add comment