julia_v_iluhina

Untitled

Oct 27th, 2016
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 20.44 KB | None | 0 0
  1. public static WebElement $(ExpectedCondition<WebElement> conditionToWaitParentElement, String innerElementCssSelector){
  2.         assertThat(conditionToWaitParentElement);
  3.         return $(byCss(innerElementCssSelector));
  4. }
  5. /*
  6.     у нас задача - внутри элемента (который мы подождем вот так - conditionToWaitParentElement)
  7.     найти другой элемент и его вернуть
  8.  
  9.     вот этот элемент (ParentElement) - мы получим как результат assertThat(conditionToWaitParentElement)
  10.     (вспомни - как реализован assertThat - он возвращает тот же тип, что и в типе кондишена указан в <...>
  11.  
  12.     у элемента получить его внутренний элемент можно так -
  13.     WebElement parentElement = ...;
  14.     WebElement innerElement = parentElement.findElement(byCss(innerElementCssSelector));
  15.  
  16.     те же проблемы и у
  17.     WebElement $(ExpectedCondition<WebElement> conditionToWaitParentElement, By innerElementLocator)
  18.     советую реализовать вот этот метод
  19.  
  20.     а в $(ExpectedCondition<WebElement> conditionToWaitParentElement, String innerElementCssSelector) -
  21.     уже его переиспользовать - код методов очень похож
  22. */
  23. ********************************************
  24. public static ExpectedCondition<List<WebElement>> $$(ExpectedCondition<List<WebElement>> conditionToWaitForListFilteredElements){
  25.  
  26.         return null;
  27. }
  28. /*
  29.     тут все просто - возвращай assertThat
  30.     на самом деле - нам не очень-то и нужен такой метод
  31.     но пусть будет)
  32. */
  33. ********************************************
  34.                 List<WebElement> visibleElements = new ArrayList<>();
  35.                 for (WebElement element : elements) {
  36.                     if (element.isDisplayed()){
  37.                         visibleElements.add(element);
  38.                     }
  39.                 }
  40. /*
  41.     этот код - используется в несколььких кондишенах
  42.     реализуй метод
  43.     List<WebElement> getVisibleElements(List<WebElement> elements)
  44.  
  45.     для такого плана универсальных методов - используй новый класс-контейнер Helpers
  46.  
  47.     а в кондишенах - просто используй
  48. */
  49. *******************************************
  50. ExpectedCondition<List<String>> textsOf
  51. /*
  52.     странный выбор для типа кондишена)
  53.     наиболее разумный тип в данном случае = это ExpectedCondition<List<WebElement>>
  54. */
  55. **********************************************
  56.                 List<String> actualTexts = new ArrayList<>();
  57.                 for (WebElement element : elementList) {
  58.                     actualTexts.add(element.getText());
  59.                 }
  60. /*
  61.     этот код тоже нужен не раз
  62.     и для него реализуй метод List<String> getTexts(List<WebElement> elements)
  63.     там же, в Helpers размести
  64. */
  65. ********************************************
  66. public static ExpectedCondition<List<String>> exactTextOfVisibleElements(final By elementsLocator, final String... expectedTexts){
  67. /*
  68.     уточни в имени кондишена exactText__s___
  69.     тут - тоже подкорректируй тип кондишена - разумнее List<WebElement>
  70. */
  71.         final List<String> actualTexts = new ArrayList<>();
  72.         /*
  73.             объяви переменную внутри созданного кондишена
  74.             ведь именно там она и нужна
  75.             и как final - не придется ее объявлять
  76.         */
  77.  
  78.         return elementExceptionsCatcher(new ExpectedCondition<List<String>>() {
  79.         /*
  80.             я имею в виду  - вот тут
  81.         */
  82.             public List<String> apply(WebDriver driver) {
  83.                 ...
  84.                 /*
  85.                     уже есть 2 полезных метода
  86.                     получи видимые элементы
  87.                     а для них - тексты
  88.                     в случае успеха - как раз список с видимыми элементами и вернешь
  89.                 */
  90.                 ...
  91.                     if (!actualTexts.get(i).contains(expectedTexts[i])) {
  92.                 /*
  93.                     реализуем exactTexts - значит проверяем не вхождение, а равенство
  94.                 */
  95.             ...
  96.             @Override
  97.             public String toString() {
  98.                 return String.format("texts in visible element list should be:\n" + Arrays.toString(expectedTexts) + "\nWhile actual is:\n" + Arrays.toString(actualTexts.toArray()));
  99.             }
  100.             /*
  101.                 не мешало бы и про локатор рассказать
  102.             */
  103. *******************************************
  104.     public static ExpectedCondition<WebElement> elementWithCssClass(final By elementsLocator, final String cssClass){
  105.         ...
  106.                     if (element.getAttribute("class").contains(cssClass)){
  107.                     /*
  108.                         увы, тут так просто не получится)
  109.                         например  - у нас getAttribute("class")
  110.                         вернул "active editing"
  111.                         а мы проверяем на edit
  112.                         эта проверка пройдет
  113.                         а не дожна
  114.                         нам полученную строку (от getAttribute("class"))
  115.                         надо разбить на слова - по пробелам
  116.                         и проверять - если есть слово - равное переданному классу
  117.                         вот тогда только нашли
  118.                      */
  119.  
  120.             @Override
  121.             public String toString() {
  122.                 return String.format("problem to get element with locator " + elementsLocator + " and cssClass " + cssClass);
  123.             }
  124. /*
  125.     не надо писать про problem
  126.     на самом деле - мы этого не знаем)
  127.     в общем случае метод класса toString - это просто описание объекта
  128.     да, toString кондишена вызывается как правило - в сообщении об ошибке
  129.     но - математически верно будет просто описать
  130.     что проверяли
  131.     на что проверяли
  132.     что ждали
  133.     что фактически получили
  134.  
  135.     т е - нам нужно безоценосное описание, но точное
  136.  
  137.     list found by locator ...
  138.     should contain element with cssClass ... and text ...
  139.     while actual classes are ...
  140.     and actual texts are ...
  141.  
  142.     так что - надо бы собрать как классы, так и тексты элементов в список
  143.  
  144. */
  145. **********************************************
  146. /*
  147.     мне показалось, что немного не достает понимания - как работать с дженерик-типами
  148.  
  149.     я в конце ревью вставлю пояснения Якова и полезные ссылки по этой теме
  150.    
  151.     возможно - что-то приводила по данной теме уже
  152.     не стала проверять
  153.    
  154.     сейчас цель - не досконально разобраться
  155.     а в общих чертах понять эту идею
  156.    
  157.     разберемся чуть позже гораздо детальнее
  158. */
  159.  
  160. *********************************************
  161. public class TodoMvcPage {
  162.  
  163.     static By tasks = byCss("#todo-list>li");
  164.     static By newTaskInput =  byCss("#new-todo");
  165. /*
  166.     это - пейдж-объект
  167.  
  168.     потому - тут не нужны объявления этих переменных как static
  169.     такая реализация нам булет нужна в случае пейджа-модуля
  170. */
  171. **************************************
  172. doubleClick(assertThat(elementWithText(tasks, oldTaskText)));
  173. /*
  174.     помнишь - мы когда работу по downgrade selenide to 2.17 делали -
  175.     мы уточнялись тут до label
  176.  
  177.     и тут тоже надо
  178.  
  179.     будет
  180.     как раз пригодится
  181.     $(ExpectedCondition<WebElement> conditionToWaitParentElement, String innerElementCssSelector)
  182. */
  183. *************************
  184.  $(elementWithCssClass(tasks, "editing"), byCss(".edit"))
  185.  //можно проще
  186.   $(elementWithCssClass(tasks, "editing"), ".edit")
  187. /*
  188.     т к реализован метод
  189.     $(ExpectedCondition<WebElement> conditionToWaitParentElement, String innerElementCssSelector)
  190.  
  191.     и в toggle, и в delete - тоже можно чуть сэкономить таким же образом
  192. */
  193. ***********************************
  194. public void delete(String taskText) {
  195. /*
  196.     насчет реализации delete
  197.     вспомни - как он раньше был реализован
  198.  
  199.     мы сначала делали hover -  на таске
  200.     и только потом - работали с кнопкой удаления
  201.     а до ховера - она не видима
  202.  
  203.     hover - у тебя даже реализован)
  204. */
  205. *******************************************
  206. public void assertItemsLeft(Integer activeTasksCount) {
  207.         textToBe(byCss("#todo-count>strong"), String.valueOf(activeTasksCount));
  208. //        assertThat(exactTextOfElement(byCss("#todo-count>strong"), String.valueOf(activeTasksCount)));
  209. }
  210. /*
  211.     этот код - не выполняет проверку
  212.     а лишь возвращает значение типа ExpectedCondition
  213.  
  214.     будет ок -
  215.     assertThat(textToBe(byCss("#todo-count>strong"), String.valueOf(activeTasksCount)))
  216. */
  217. *********************************************************
  218. /*
  219.     Кодишенов есть много и разных
  220.     и далеко не все они ExpectedCondition<Boolean>
  221.     вот в этих <...> - могут быть разные типы
  222.     если совсем грубо - то результат вот этого ... типа и вернет нам WebDriverWait(...).until(...) -
  223.  
  224.     например
  225.          есть такой кондишен ExpectedCondition<WebElement> visibilityOfElementLocated(By locator)
  226.          https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#visibilityOfElementLocated-org.openqa.selenium.By-
  227.  
  228.          это значит WebDriverWait(...).until(visibilityOfElementLocated(...)) - вернет вебэлемент, видимость которого мы ждали
  229.  
  230.          а для кондишенов ExpectedCondition<Boolean> - new WebDriverWait(...).until вернет результат типа Boolean
  231.  
  232.          это не отменяет главной схемы работы - если проверка new WebDriverWait(...).until( - не проходит за таймаут -
  233.          то вызывается исключение
  234.  
  235.          но - помимо этого - есть вот такая разница ...
  236.  
  237.     пока наш assertThat возвращает void  - нас это может не сильно тревожить )
  238.     достаточно - в описании параметров убрать уточнение типа - не ExpectedCondition<Boolean>, а ExpectedCondition
  239.     и assertThat - будет работать с любым из кондишенов
  240.     правда - ничего нам не вернет)
  241.  
  242.  
  243.     Давай разберемся. Сначала "идейно".
  244.  
  245.     Этот метод until возвращает такую интересную динамическую штуку-аватар...
  246.     "воплощение" которого зависит от того что именно ты передашь вейт антилу параметром
  247.     - точнее - какой именно кондишен ты ему передаешь...
  248.  
  249.     А кондишены бывают "разные"... "Разность" эта определеятся "параметром типа" который в джава записывается
  250.     ИмяТипа<ЗДЕСЬ>
  251.  
  252.     Ты уже ведь использовал списки, например...
  253.     В частности - List<WebElement>
  254.  
  255.     вот в такой записи типа - его параметром, выступает WebElement, указывая джаве,
  256.     что это не просто список, а "список ВебЕлементов"
  257.     а мог бы быть и списком стрингов например - List<String> или еще чего :)
  258.  
  259.     Такие "умные" типы которые получают параметр (или несколько параметров) - так и называются - параметризированными
  260.     (а фича языка, в которой они поддерживаются называется - параметрическим полиформизмом -
  261.     не путать с тем другим полиморфмизом... который называется - subtyping polymorphism,
  262.     а в джава все его знают как просто "полиморфизм")...
  263.     Еще они называются - шаблоны... или дженерики...
  264.     Именно так - Java Generics - их принято называть в Java
  265.  
  266.     Так вот... таким же дженериком является тип ExpectedCondition
  267.     который может быть параметризирован...
  268.  
  269.     Ты уже встречал запись типа:
  270.     ExpectedCondition<Boolean>
  271.  
  272.     что же значит этот булеан? что он параметризирует?
  273.     А он параметризирует внутреннюю реализацию этого кондишена...
  274.     Он определяет то, каким должен быть тип возвращаемого значения в методе apply
  275.  
  276.     То есть...
  277.     Если ты поставишь цель создать кондишен ExpectedCondition<Boolean> - ты должен будешь реализовать
  278.     его метод apply -  как возвращающий тип Boolean
  279.  
  280.     Но зачем вообще нам париться о типе возвращаемой сущности метода apply?
  281.  
  282.     А потому, что есть еще один "умный дженерик"...
  283.     Только который не "параметризированный класс", а "параметризированный метод"
  284.     (в джава бывают как Generic Types так и Generic Methods)
  285.  
  286.     и этот параметризированный метод - как раз и есть наш wait.until
  287.  
  288.     особенность реализации этого метода в том... что он вызывает внутри метод apply
  289.     нашего кондишена... и запоминает то значение, которое этот метод apply возвращает...
  290.  
  291.     И потом... в конце всей истории... этот метод until - либо бросит исключение
  292.     (в случае если "не дождется" кондишена)
  293.     либо вернет то, что вернул метод apply в "случае успеха"...
  294.  
  295.     Получается... Если ты передашь вейт антилу кондишен параметризированный типом Boolean
  296.     то в случае успеха антил - вернет тру...
  297.  
  298.     то есть ты можешь писать код вида:
  299.  
  300.     if (wait.until(enabled(composeButton))) {
  301.        doSomething();
  302.     }
  303.  
  304.     но на самом деле, такое нужно не часто...
  305.     то есть - такие кондишены - которые
  306.     параметризированы типом булеан...
  307.  
  308.     бошьше толку как раз от кондишенов параметризированных типом "того, характеристики чего ждет кондишен"...
  309.  
  310.     вот кондишен visibilityOf - как раз параметризирован типом WebElement
  311.         ExpectedCondition<WebElement>
  312.  
  313.     и его метод apply возвращает обьект типа WebElement,
  314.     а "идейно" - возвращает этот же элемент, визибилити которого мы дожидались...
  315.     (если бы мы не дождались - apply вернул бы null - что в этом случае играет роль "false")
  316.  
  317.     а until в конце концов вернет то, что вернет apply
  318.     и именно поэтому мы можем писать такой код:
  319.  
  320.         wait.until(visibilityOf(composeButton)).click()
  321.  
  322.     теперь твоим заданием будет - переделать assertThat что бы он возвращал то что возвращает wait.until
  323.  
  324.     ну и потом - переделать все свои кондишены, что бы они были параметризированы типом той сущности,
  325.     характеристики которой они должни дожидаться (кстати так выражатся немного некорректно - ведь кондишен не ждет,
  326.     он только выдает информацию - да/нет - а ждет уже вейт антил, ну то такое:) )
  327.  
  328.     для того, чтобы "правильно реализовать этот wait.until" -
  329.     тебе придется разобраться с этими дженериками...
  330.     И с дженерик типами и дженерик методами.
  331.  
  332.     И даже этого будет мало...
  333.     Прийдется покопаться в коде селениума, чтобы понять, что там за тип реально получает
  334.     вейт антил как кондишен...
  335.     Потому что он получает не ExpectedCondition а что то еще более странное...
  336.     Это работает - потому что это "странное" - есть родительским классом для ExpectedCondition
  337.  
  338. Что почитать про Generics
  339. про дженерики в общем(русский)
  340. http://www.quizful.net/post/java-generics-tutorial
  341.  
  342.  
  343. http://www.tutorialspoint.com/java/java_generics.htm
  344. http://developer.alexanderklimov.ru/android/java/generic.php
  345.  
  346. конвеншенcы      http://stackoverflow.com/questions/2900881/generic-type-parameter-naming-convention-for-java-with-multiple-chars
  347. https://docs.oracle.com/javase/tutorial/java/generics/types.html
  348.  
  349. уроки
  350. http://docs.oracle.com/javase/tutorial/extra/generics/index.html
  351.  
  352. очень приличный faq (есть pdf, и есть кое-что еще, помимо дженериков)
  353. http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
  354.  
  355.  
  356. ----------------------------------------------------------
  357. для понимания кетчера (Catcher)
  358. http://grepcode.com/file/repo1.maven.org/maven2/com.google.guava/guava/r06/com/google/common/base/Function.java
  359. http://www.programcreek.com/java-api-examples/com.google.common.base.Function
  360. https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html
  361. http://stackoverflow.com/questions/3847162/java-generics-super-keyword
  362. http://stackoverflow.com/questions/2800369/bounding-generics-with-super-keyword
  363. http://stackoverflow.com/questions/1910892/what-is-the-difference-between-super-and-extends-in-java-generics
  364. */
Advertisement
Add Comment
Please, Sign In to add comment