Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public static WebElement $(ExpectedCondition<WebElement> conditionToWaitParentElement, String innerElementCssSelector){
- assertThat(conditionToWaitParentElement);
- return $(byCss(innerElementCssSelector));
- }
- /*
- у нас задача - внутри элемента (который мы подождем вот так - conditionToWaitParentElement)
- найти другой элемент и его вернуть
- вот этот элемент (ParentElement) - мы получим как результат assertThat(conditionToWaitParentElement)
- (вспомни - как реализован assertThat - он возвращает тот же тип, что и в типе кондишена указан в <...>
- у элемента получить его внутренний элемент можно так -
- WebElement parentElement = ...;
- WebElement innerElement = parentElement.findElement(byCss(innerElementCssSelector));
- те же проблемы и у
- WebElement $(ExpectedCondition<WebElement> conditionToWaitParentElement, By innerElementLocator)
- советую реализовать вот этот метод
- а в $(ExpectedCondition<WebElement> conditionToWaitParentElement, String innerElementCssSelector) -
- уже его переиспользовать - код методов очень похож
- */
- ********************************************
- public static ExpectedCondition<List<WebElement>> $$(ExpectedCondition<List<WebElement>> conditionToWaitForListFilteredElements){
- return null;
- }
- /*
- тут все просто - возвращай assertThat
- на самом деле - нам не очень-то и нужен такой метод
- но пусть будет)
- */
- ********************************************
- List<WebElement> visibleElements = new ArrayList<>();
- for (WebElement element : elements) {
- if (element.isDisplayed()){
- visibleElements.add(element);
- }
- }
- /*
- этот код - используется в несколььких кондишенах
- реализуй метод
- List<WebElement> getVisibleElements(List<WebElement> elements)
- для такого плана универсальных методов - используй новый класс-контейнер Helpers
- а в кондишенах - просто используй
- */
- *******************************************
- ExpectedCondition<List<String>> textsOf
- /*
- странный выбор для типа кондишена)
- наиболее разумный тип в данном случае = это ExpectedCondition<List<WebElement>>
- */
- **********************************************
- List<String> actualTexts = new ArrayList<>();
- for (WebElement element : elementList) {
- actualTexts.add(element.getText());
- }
- /*
- этот код тоже нужен не раз
- и для него реализуй метод List<String> getTexts(List<WebElement> elements)
- там же, в Helpers размести
- */
- ********************************************
- public static ExpectedCondition<List<String>> exactTextOfVisibleElements(final By elementsLocator, final String... expectedTexts){
- /*
- уточни в имени кондишена exactText__s___
- тут - тоже подкорректируй тип кондишена - разумнее List<WebElement>
- */
- final List<String> actualTexts = new ArrayList<>();
- /*
- объяви переменную внутри созданного кондишена
- ведь именно там она и нужна
- и как final - не придется ее объявлять
- */
- return elementExceptionsCatcher(new ExpectedCondition<List<String>>() {
- /*
- я имею в виду - вот тут
- */
- public List<String> apply(WebDriver driver) {
- ...
- /*
- уже есть 2 полезных метода
- получи видимые элементы
- а для них - тексты
- в случае успеха - как раз список с видимыми элементами и вернешь
- */
- ...
- if (!actualTexts.get(i).contains(expectedTexts[i])) {
- /*
- реализуем exactTexts - значит проверяем не вхождение, а равенство
- */
- ...
- @Override
- public String toString() {
- return String.format("texts in visible element list should be:\n" + Arrays.toString(expectedTexts) + "\nWhile actual is:\n" + Arrays.toString(actualTexts.toArray()));
- }
- /*
- не мешало бы и про локатор рассказать
- */
- *******************************************
- public static ExpectedCondition<WebElement> elementWithCssClass(final By elementsLocator, final String cssClass){
- ...
- if (element.getAttribute("class").contains(cssClass)){
- /*
- увы, тут так просто не получится)
- например - у нас getAttribute("class")
- вернул "active editing"
- а мы проверяем на edit
- эта проверка пройдет
- а не дожна
- нам полученную строку (от getAttribute("class"))
- надо разбить на слова - по пробелам
- и проверять - если есть слово - равное переданному классу
- вот тогда только нашли
- */
- @Override
- public String toString() {
- return String.format("problem to get element with locator " + elementsLocator + " and cssClass " + cssClass);
- }
- /*
- не надо писать про problem
- на самом деле - мы этого не знаем)
- в общем случае метод класса toString - это просто описание объекта
- да, toString кондишена вызывается как правило - в сообщении об ошибке
- но - математически верно будет просто описать
- что проверяли
- на что проверяли
- что ждали
- что фактически получили
- т е - нам нужно безоценосное описание, но точное
- list found by locator ...
- should contain element with cssClass ... and text ...
- while actual classes are ...
- and actual texts are ...
- так что - надо бы собрать как классы, так и тексты элементов в список
- */
- **********************************************
- /*
- мне показалось, что немного не достает понимания - как работать с дженерик-типами
- я в конце ревью вставлю пояснения Якова и полезные ссылки по этой теме
- возможно - что-то приводила по данной теме уже
- не стала проверять
- сейчас цель - не досконально разобраться
- а в общих чертах понять эту идею
- разберемся чуть позже гораздо детальнее
- */
- *********************************************
- public class TodoMvcPage {
- static By tasks = byCss("#todo-list>li");
- static By newTaskInput = byCss("#new-todo");
- /*
- это - пейдж-объект
- потому - тут не нужны объявления этих переменных как static
- такая реализация нам булет нужна в случае пейджа-модуля
- */
- **************************************
- doubleClick(assertThat(elementWithText(tasks, oldTaskText)));
- /*
- помнишь - мы когда работу по downgrade selenide to 2.17 делали -
- мы уточнялись тут до label
- и тут тоже надо
- будет
- как раз пригодится
- $(ExpectedCondition<WebElement> conditionToWaitParentElement, String innerElementCssSelector)
- */
- *************************
- $(elementWithCssClass(tasks, "editing"), byCss(".edit"))
- //можно проще
- $(elementWithCssClass(tasks, "editing"), ".edit")
- /*
- т к реализован метод
- $(ExpectedCondition<WebElement> conditionToWaitParentElement, String innerElementCssSelector)
- и в toggle, и в delete - тоже можно чуть сэкономить таким же образом
- */
- ***********************************
- public void delete(String taskText) {
- /*
- насчет реализации delete
- вспомни - как он раньше был реализован
- мы сначала делали hover - на таске
- и только потом - работали с кнопкой удаления
- а до ховера - она не видима
- hover - у тебя даже реализован)
- */
- *******************************************
- public void assertItemsLeft(Integer activeTasksCount) {
- textToBe(byCss("#todo-count>strong"), String.valueOf(activeTasksCount));
- // assertThat(exactTextOfElement(byCss("#todo-count>strong"), String.valueOf(activeTasksCount)));
- }
- /*
- этот код - не выполняет проверку
- а лишь возвращает значение типа ExpectedCondition
- будет ок -
- assertThat(textToBe(byCss("#todo-count>strong"), String.valueOf(activeTasksCount)))
- */
- *********************************************************
- /*
- Кодишенов есть много и разных
- и далеко не все они ExpectedCondition<Boolean>
- вот в этих <...> - могут быть разные типы
- если совсем грубо - то результат вот этого ... типа и вернет нам WebDriverWait(...).until(...) -
- например
- есть такой кондишен ExpectedCondition<WebElement> visibilityOfElementLocated(By locator)
- https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#visibilityOfElementLocated-org.openqa.selenium.By-
- это значит WebDriverWait(...).until(visibilityOfElementLocated(...)) - вернет вебэлемент, видимость которого мы ждали
- а для кондишенов ExpectedCondition<Boolean> - new WebDriverWait(...).until вернет результат типа Boolean
- это не отменяет главной схемы работы - если проверка new WebDriverWait(...).until( - не проходит за таймаут -
- то вызывается исключение
- но - помимо этого - есть вот такая разница ...
- пока наш assertThat возвращает void - нас это может не сильно тревожить )
- достаточно - в описании параметров убрать уточнение типа - не ExpectedCondition<Boolean>, а ExpectedCondition
- и assertThat - будет работать с любым из кондишенов
- правда - ничего нам не вернет)
- Давай разберемся. Сначала "идейно".
- Этот метод until возвращает такую интересную динамическую штуку-аватар...
- "воплощение" которого зависит от того что именно ты передашь вейт антилу параметром
- - точнее - какой именно кондишен ты ему передаешь...
- А кондишены бывают "разные"... "Разность" эта определеятся "параметром типа" который в джава записывается
- ИмяТипа<ЗДЕСЬ>
- Ты уже ведь использовал списки, например...
- В частности - List<WebElement>
- вот в такой записи типа - его параметром, выступает WebElement, указывая джаве,
- что это не просто список, а "список ВебЕлементов"
- а мог бы быть и списком стрингов например - List<String> или еще чего :)
- Такие "умные" типы которые получают параметр (или несколько параметров) - так и называются - параметризированными
- (а фича языка, в которой они поддерживаются называется - параметрическим полиформизмом -
- не путать с тем другим полиморфмизом... который называется - subtyping polymorphism,
- а в джава все его знают как просто "полиморфизм")...
- Еще они называются - шаблоны... или дженерики...
- Именно так - Java Generics - их принято называть в Java
- Так вот... таким же дженериком является тип ExpectedCondition
- который может быть параметризирован...
- Ты уже встречал запись типа:
- ExpectedCondition<Boolean>
- что же значит этот булеан? что он параметризирует?
- А он параметризирует внутреннюю реализацию этого кондишена...
- Он определяет то, каким должен быть тип возвращаемого значения в методе apply
- То есть...
- Если ты поставишь цель создать кондишен ExpectedCondition<Boolean> - ты должен будешь реализовать
- его метод apply - как возвращающий тип Boolean
- Но зачем вообще нам париться о типе возвращаемой сущности метода apply?
- А потому, что есть еще один "умный дженерик"...
- Только который не "параметризированный класс", а "параметризированный метод"
- (в джава бывают как Generic Types так и Generic Methods)
- и этот параметризированный метод - как раз и есть наш wait.until
- особенность реализации этого метода в том... что он вызывает внутри метод apply
- нашего кондишена... и запоминает то значение, которое этот метод apply возвращает...
- И потом... в конце всей истории... этот метод until - либо бросит исключение
- (в случае если "не дождется" кондишена)
- либо вернет то, что вернул метод apply в "случае успеха"...
- Получается... Если ты передашь вейт антилу кондишен параметризированный типом Boolean
- то в случае успеха антил - вернет тру...
- то есть ты можешь писать код вида:
- if (wait.until(enabled(composeButton))) {
- doSomething();
- }
- но на самом деле, такое нужно не часто...
- то есть - такие кондишены - которые
- параметризированы типом булеан...
- бошьше толку как раз от кондишенов параметризированных типом "того, характеристики чего ждет кондишен"...
- вот кондишен visibilityOf - как раз параметризирован типом WebElement
- ExpectedCondition<WebElement>
- и его метод apply возвращает обьект типа WebElement,
- а "идейно" - возвращает этот же элемент, визибилити которого мы дожидались...
- (если бы мы не дождались - apply вернул бы null - что в этом случае играет роль "false")
- а until в конце концов вернет то, что вернет apply
- и именно поэтому мы можем писать такой код:
- wait.until(visibilityOf(composeButton)).click()
- теперь твоим заданием будет - переделать assertThat что бы он возвращал то что возвращает wait.until
- ну и потом - переделать все свои кондишены, что бы они были параметризированы типом той сущности,
- характеристики которой они должни дожидаться (кстати так выражатся немного некорректно - ведь кондишен не ждет,
- он только выдает информацию - да/нет - а ждет уже вейт антил, ну то такое:) )
- для того, чтобы "правильно реализовать этот wait.until" -
- тебе придется разобраться с этими дженериками...
- И с дженерик типами и дженерик методами.
- И даже этого будет мало...
- Прийдется покопаться в коде селениума, чтобы понять, что там за тип реально получает
- вейт антил как кондишен...
- Потому что он получает не ExpectedCondition а что то еще более странное...
- Это работает - потому что это "странное" - есть родительским классом для ExpectedCondition
- Что почитать про Generics
- про дженерики в общем(русский)
- http://www.quizful.net/post/java-generics-tutorial
- http://www.tutorialspoint.com/java/java_generics.htm
- http://developer.alexanderklimov.ru/android/java/generic.php
- конвеншенcы http://stackoverflow.com/questions/2900881/generic-type-parameter-naming-convention-for-java-with-multiple-chars
- https://docs.oracle.com/javase/tutorial/java/generics/types.html
- уроки
- http://docs.oracle.com/javase/tutorial/extra/generics/index.html
- очень приличный faq (есть pdf, и есть кое-что еще, помимо дженериков)
- http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
- ----------------------------------------------------------
- для понимания кетчера (Catcher)
- http://grepcode.com/file/repo1.maven.org/maven2/com.google.guava/guava/r06/com/google/common/base/Function.java
- http://www.programcreek.com/java-api-examples/com.google.common.base.Function
- https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html
- http://stackoverflow.com/questions/3847162/java-generics-super-keyword
- http://stackoverflow.com/questions/2800369/bounding-generics-with-super-keyword
- http://stackoverflow.com/questions/1910892/what-is-the-difference-between-super-and-extends-in-java-generics
- */
Advertisement
Add Comment
Please, Sign In to add comment