Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- http://joxi.ru/a2X3dZMsy6l59m
- /*
- предка тест-классов - перенеси на уровень выше - раз используется для gmail & google searsh
- */
- ************************************************
- getWebDriver().findElement(By.name("q")).clear();
- getWebDriver().findElement(By.name("q")).sendKeys(queryText + Keys.ENTER);
- vs
- $(By.name("q")).clear();
- $(By.name("q")).sendKeys(queryText + Keys.ENTER);
- /*
- не забывай - есть способ писать код попроще)
- */
- *******************************************************
- catch (StaleElementReferenceException | ElementNotVisibleException | IndexOutOfBoundsException e){
- }
- ...
- throw new ElementNotFoundException(String.format("Condition %s not achieved while waiting with timeout of %s, Ms", condition.toString(), timeoutMs), "", "");
- /*
- вместо ElementNotFoundException - грамотнее использовать selenium.TimeoutException
- (будь внимательна при импорте, с таким именем - есть несколько вариантов)
- именно такое исключение кидает сам селениум - в его new WebDriverWait(...).until(...)
- да и по смыслу - это ближе - не хватило таймаута дождаться того-то
- чуть проще для восприятия будет вот такая фраза
- "failed while waiting ... seconds to assert ...."
- catch-секция
- Тут можно написать код покороче
- зажав ctrl кликай на именах классов кондишенов
- ты увидишь
- что StaleElementReferenceException и ElementNotVisibleException - потомки WebDriverException
- потому - можно ловить WebDriverException и IndexOutOfBoundsException
- также - в catch-секции сохраняй ошибку в переменной lastError
- чтобы при вызове исключения - включить информацию об ошибке, в результате которой кондишен не прошел
- получим
- throw new TimeoutException("....", lasterror);
- помнишь ошибки в Selenide
- ...some error...
- caused by ..... another error ....
- вот такое мы получим, если
- передадим вызываемому исключению не только текст-описание,
- но и второй параметр - cause = что было причиной того, что проверка не прошла
- подробности по lastError
- для этого - объяви вначале метода переменную lastError типа Throwable
- про Throwable - http://www.quizful.net/post/java-exceptions
- и инициализируй ее значением null
- мы тут без этого не обойдемся
- http://stackoverflow.com/questions/16699593/uninitialized-object-vs-object-initialized-to-null
- цитата - Note that the above rule excludes local variables: they must be initialized explicitly,
- otherwise the program will not compile.
- кстати, убери
- throws WebDriverException - в заголовке метода until
- */
- ************************************
- private void sleep(int milliseconds)
- /*
- молодец, что расположила такой метод в классе WaitFor
- и реализовала его как private
- все верно, лучше в руки такое не отдавать))
- только внутри ждущей проверки нам это и надо
- */
- ***********************************
- http://joxi.ru/brRlV57uQ9LpQ2
- /*
- структура пекеджа core
- уже тяжело)
- чуть ее разовьем))
- в корне core - оставим 1-4
- для кондишенов - создай в рамках core пекедж conditions
- туда перемести 5-8
- 9 - в итоге вообще уйдет, давай такие вещи тоже отдельно собирать
- например в пекедже core \ deprecated
- */
- ******************************************
- /*
- ты писала в слеке, и сейчас это все еще есть -
- проверки кондишенов Condition<Boolean> - не падают
- см на код родного селениумского until
- */
- public <V> V until(Function<? super T, V> isTrue) {
- ...
- V value = isTrue.apply(input);
- if (value != null && Boolean.class.equals(value.getClass())) {
- if (Boolean.TRUE.equals(value)) {
- return value;
- }
- } else if (value != null) {
- return value;
- }
- ...
- /*
- видишь - тут танцы вокруг булеана танцуют
- не самые красивые и не самые простые
- я советую так не делать
- лучше - если все кондишены будут возвращать нулл - если проверка не прошла
- тем более - что
- у нас так устроен WaitFor - что мі ждущую проверку делаем всегда
- либо для элемента, либо для списка элементов (передаем конечно - локатор, но в итоге - элемент или список)
- потому - для нас будет разумно - если все кондишены - будут
- или Condition<List<WebElement>>, или Condition<WebElement>
- удобно после прошедшей проверки - получить актуальное проверенное - или элемент, или сущность
- потому
- в реализованных кондишенах - перейди на вриант Condition<List<WebElement>>, или Condition<WebElement>
- реализуй кондишен Condition<WebElement> Visible - проверку видимости элемента
- а раз так - мы в кондишенах всегда будем кидать null - если условие не будет выполнено
- и так - мы уйдем от проблемы, что сейчас есть
- */
- /*
- Перейди в ConciseAPI на использование кондишена нашего вместо visibilityOfElementLocated
- погоняй google search в полной реализации -
- и так, чтобы проверки по кондишенам падали
- и так, чтоб не падали )
- это же надо будет сделать и по финишу)
- можешь эту версию - отдельно закоммитить - для истории))
- дальше развиваем)
- */
- ********************************************************************
- дореализуй еще варианты метода until
- public <V> V until(Condition<V>... conditions)
- /*
- суть - по очереди для каждого из кондишенов вызываем наш until(Condition<V> condition)
- до тех пор, пока проверки проходят - двигаемся по набору переданных кондишенов
- как только ждущая проверка для кондишена не прошла - дальше не проверяем
- */
- ***********************
- public abstract class Condition<V> {
- public abstract V apply(By locator);
- }
- /*
- Иерархия для кондишенов у тебя сейчас - достаточно простая
- абстрактный класс
- от которого наследуются и реализуются классы-кондишены
- Минимально необходимая реализация есть
- Будем ее развивать
- Во-первых, сначала у нас будет интерфейс Condition<V>
- Который будет декларировать/гарантировать
- что во всех классах, имплементирующих этот интерфейс
- будут такие-то методы
- полезные линки по интерфейсам
- http://kostin.ws/java/java-abstract-and-interfaces.html
- http://developer.alexanderklimov.ru/android/java/interface.php
- https://docs.oracle.com/javase/tutorial/java/concepts/interface.html
- теперь про методы)
- С самым главным - с apply его сигнатурой - все верно)
- В общем-то, это все, чем можно ограничиться в интерфейсе )
- Далее - абстрактный класс-предок, который мы имплементируем от интерфейса
- у тебя он уже есть, надо добавить имплементацию и подправить имя - AbstractCondition<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
- Можно конечно в каждом из кондишенов просто строить такую фразу
- согласно правилу
- А можно - задачу разбить на подзадачи, которые к тому же будут контролироваться
- благодаря реализации этих подзадач
- Имя кондишена
- Будем реализовывать кондишены как отдельные классы - потомки (пока - нашего абстрактного класса)
- Откуда взять имя кондишена - у нас есть имя класса кондишена - чем не имя )
- Далее
- 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>
- И метод будет корректно работать для любого из кондишенов
- Т к этот интерфейс лежит в основе этой иерархии
- */
- *****
- public abstract V apply(By locator);
- /*
- Выше я писала про то, что можно было бы внутрь apply
- включить обработку исключений
- Если реализовать apply в AbstractCondition
- как метод с try-catch
- внутри которого вызывается абстрактный метод check (с такой же сигнатурой, как и у apply)
- то - более нигде не нужно будет ловить исключения вокруг apply
- а в кондишенах - мы будем реализовыввать не apply, а check
- */
- ******
- /*
- еще один наворот внутри кондишенов)
- мы его впоследствии переделаем
- сейчас нам это нужно для лучшего понимания процесса
- в 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