Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public static String url() {
- String url = getDriver().getCurrentUrl();
- return url;
- }
- /*
- начнем с мелочей)
- тут в одну строку можно
- return getDriver().getCurrentUrl();
- */
- *******************************************
- public static By byCss(String cssSelector) {
- return cssSelector(cssSelector);
- }
- /*
- яркий пример - когда не стоило импорить метод статически
- и использовать вызов без указания класса метода
- сравни
- cssSelector(cssSelector)
- и
- By.cssSelector(cssSelector)
- все же - второй вариант - однозначнее
- тут всегда надо сопоставлять плюсы и минусы
- код должен быть точным и однозначно понимаемым
- тут - By.cssSelector - вариант получше
- вообще - по моему мнению для методов класса By - лучше указывать имя класса
- */
- ***********************************************
- public static WebElement $(String cssSelector) {
- return $(cssSelector(cssSelector));
- }
- /*
- Выше - реализован метод byCss
- стоит его уже тут применять
- пока мы делаем только вот эту часть
- http://joxi.ru/Dr860ybhkBb5B2
- не торопись все переделать
- мы пока не нуждаемся в функциональности
- $(ExpectedCondition<WebElement> conditionToWaitParentElement, String innerElementCssSelector)
- нам достаточно для отладки - наш тест google search
- остальное - можно пока закомментить
- ну и - пока это не нужно - не включать gmail или todoMVC тесты
- нам пока и без этого работы хватит
- постепенно с предыдущих заданий - перенесем и gmail и todoMVC тесты
- сейчас - не надо
- только лишней работы себе добавим
- */
- ******************************************************
- public interface ExpectedCondition<T> {
- T apply(WebDriver driver, By elementsLocator);
- }
- /*
- согласна, делаем интерфейс для своих кондишенов
- согласна - что apply возвращает значение типа T (какой у нас кондишен - ExpectedCondition<T>)
- согласна - уместно применила T
- насчет WebDriver driver
- можем избавиться от него
- мы же реализуем это решение для нашего фреймворка
- и тут - мы можем также - использовать вебдрайвер из ConciseAPI
- и не заводить такого параметра
- по By elementsLocator
- да, нам нужен парамент типа By
- но - будет ли это elementsLocator или elementLocator - зависит от обстоятельств
- потому - корректнее использовать более нейтральный термин - locator
- по имени интерфейса
- лучше не использовать классов с таким же именем, что и у стандартных классов
- предлагаю тут вариант Condition<T>
- */
- *******************************************
- protected static <V> V waitUntil(ExpectedCondition<V> condition, By elementsLocator, long timeOutInSeconds) {
- /*
- тут тоже - про имя elementsLocator
- корректнее - locator
- */
- final long startTime = System.currentTimeMillis();
- do {
- V v = condition.apply(getDriver(), elementsLocator);
- if (v != null) {
- if (v.getClass().isAssignableFrom(Boolean.class) && v == Boolean.TRUE ||
- !v.getClass().isAssignableFrom(Boolean.class)) {
- /*
- на самом деле, толку от реализации кондишенов как Condition<Boolean> - мало
- что нам даст возвращенный true?
- да ничего нового
- раз проверка не упала - значит и так понятно - что проверка прошла
- мы - сами себе хозяева
- и можем для себя решить - что не будем делать Condition<Boolean>
- нам будет достаточно
- Condition<WebElement>
- и
- Condition<List<WebElement>>
- а раз так - значит вот этого if (v.getClass().isAssignableFrom....
- не надо)
- */
- return v;
- }
- }
- sleep(collectionsPollingInterval);
- /*
- вот тут - лучше подробнее
- Configuration.pollingInterval
- и про collections - тут не надо писать)
- т к опять же - мы точно не знаем
- для коллекции элементов или для элемента мы будем делать проверку
- */
- }
- while (System.currentTimeMillis() - startTime < timeOutInSeconds * 1000);
- return condition.apply(getDriver(), elementsLocator);
- /*
- а вот тут нам надо - раз нам не хватило таймаута для проверки
- бросить исключение
- у Selenium - есть TimeoutException
- вот его и вызови тут
- new TimeoutException(...);
- */
- }
- /*
- в целом - молодец, переварила )
- чуть наворачиваем)
- */
- /*
- хорошая идея - реализовать умное ожидание в отдельном классе
- с точки зрения Single Responsibility - так будет лучше
- наглядно этот класс назвать WaitFor
- а статический метод-умный ожидатель выполнения кондишена - until
- и в коде мы будем писать WaitFor(byCss(...)).until(visible())
- получится очень наглядная и понятная фраза
- в том же классе - расположи и метод sleep
- а его сделай - private
- т к sleep будет нужен только для реализации ждущей проверки
- */
- *********************************************************
- public static ExpectedCondition<List<WebElement>> texts(final String... expectedTexts) {
- return elementExceptionsCatcher(new ExpectedCondition<List<WebElement>>() {
- ....
- });
- }
- /*
- Теперь - давай реализовывать кондишены не как анонимные классы, а как отдельные классы
- а в CustomConditions - будут статические лаконичные методы
- типа
- */
- public static Condition<List<WebElement>> texts(final String... texts) {
- return new Texts(texts);
- }
- /*
- в реализации самого кондишена - elementExceptionsCatcher использовать не будем
- это мы сделаем внутри цикла в ждущей проверке - будем ловить те же исключения
- такой способ реализации кондишенов - даст нам несколько бонусов приятных
- чуть позже разберем)
- чтоб не загромождать пекедж core
- создай в нем пекедж conditions
- и там расположи все, что касается кондишенов
- */
- ***************************************************
- public static ExpectedCondition<WebElement> visibilityOfElement() {
- /*
- смотри имя - мы проверяем видимость элемента (одного)
- */
- ...
- elements = driver.findElements(elementsLocator);
- /*
- потому и тут - можем просто получить элемент
- driver.findElement(...)
- */
- ****************************************************
- /*
- Иерархия для кондишенов у тебя сейчас - достаточно простая
- интерфейс
- и классы-кондишены, имплементирующие его
- Минимально необходимая реализация есть
- Будем ее развивать
- Далее - реализуй абстрактный класс-предок 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 класса для реализации статических методов - вызовов кондишенов
- не один, как сейчас у тебя - Conditions
- а 2 = CollectionConditions и ElementConditions
- чтобы каталоги проверок были разными для этих 2-ух типов проверок
- С иерархией разобрались немного )
- Возвращаемся к фразе в 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