julia_v_iluhina

Untitled

Sep 6th, 2016
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 21.34 KB | None | 0 0
  1.     public static void assertThat(WebDriver driver, ExpectedCondition condition) {
  2.         assertThat(driver, condition, timeout);
  3.     }
  4. /*
  5.     А вот тут как раз тот случай, когда нету смысла импортить статически core.Configuration.timeout;
  6.     лучше быть точнее и указывать в коде - Configuration.timeout
  7.     чтобы явно подчеркнуть - что за таймаут тут в данном случае
  8. */
  9. ******************************
  10. $(driver, By.id("Email")).sendKeys(email + Keys.ENTER);
  11.  
  12. /*
  13.     можно в ConciseAPI
  14.     дореадизовать метод
  15.      public static WebElement $(WebDriver driver, String cssSelector)
  16.     т к зачастую - он будет удобнее в работе
  17.  
  18.     тут, например,
  19.      вместо
  20.             $(driver, By.id("Email"))
  21.      получил бы
  22.             $(driver, "#Email")
  23.  
  24.     не забывай про DRY
  25.     и в  $(WebDriver driver, String cssSelector)
  26.     переиспользуй ранее реализованный метод $(...)
  27. */
  28. *****************************************
  29.  
  30.     public void createEmail() {
  31.         $(driver, By.cssSelector(".z0 .T-I")).click();
  32.     }
  33.  
  34. /*
  35.     В Selenide-версии было лучше  - нагляднее )
  36. */
  37.     public static void createEmail() {
  38.         $(byText("НАПИСАТЬ")).click();
  39.     }
  40. /*
  41.     реализуй в ConciseAPI метод byText
  42.     подсмотри - как это реализовано в Selenide
  43.     фактически - тебе через xPath выражение надо получить локатор
  44.     можно выражение и попроще, чем в  Selenide, использовать
  45.     там просто оно большее к-во вариантов покрывает
  46.  
  47.     про имя метода - писала еще в http://pastebin.com/XgnLDBuR, строки 20-27
  48.     не настаиваю, но я бы воспользовалась термином с UI = compose
  49.  
  50.     термины с UI - самые наглядные термины)
  51.  
  52.     не обязательно, но можно (не обязательно - т к ты в этом проекте вполне обойдешься без таких методов)
  53.         реализовать метод byTitle
  54.         применить его для переходов в Inbox & Sent
  55.         цель - реализовать полезный в будущем метод и отладить его тут
  56.         как реализовать - см идеи в Selenide
  57.  
  58.         еще - для уменьшения количества писанины - можно было бы реализовать
  59.         By byCss(String cssSelector)
  60.  
  61. */
  62. ************************************
  63.     public void goToSend() {
  64. /*
  65.     goToSen___t___
  66.     буковку поправь )
  67. */
  68. *******************************
  69.  
  70. public void send(String email, String subject) {
  71. ...
  72.         $(driver, By.id(":lo")).click();
  73. }
  74. /*
  75.     в селенидовской версии - было понагляднее)
  76. */
  77.  
  78. $(byText("Отправить")).click();
  79.  
  80. /*
  81.     т к уже и тут byText есть - смело применяй
  82. */
  83. **********************************************
  84.  
  85.     public static ExpectedCondition<Boolean> listNthElementHasText(final List<WebElement> elements, final int index, final String expectedText) {
  86.         return new ExpectedCondition<Boolean>() {
  87.             ...
  88.  
  89.             public Boolean apply(WebDriver driver) {
  90.                 try {
  91. ...
  92.                 } catch (StaleElementReferenceException var3) {
  93. ...
  94.                 }
  95.             }
  96. /*
  97.     лови в catch-секции и вот это исключение - IndexOutOfBoundsException
  98.     оно возникает - когда мы пытаемся получить элемент списка по индексу за пределами списка
  99.  
  100.     чтобы применять одну catch-секцию
  101.     http://stackoverflow.com/questions/3495926/can-i-catch-multiple-java-exceptions-in-the-same-catch-clause
  102. */
  103. *****************************************************
  104.  
  105.     public static ExpectedCondition<Boolean> texts(final List<WebElement> elements, final String ... expectedTexts) {
  106.         return new ExpectedCondition<Boolean>() {
  107.             private int listSize;
  108.             private int textsSize;
  109.             /*
  110.                 без этих переменных можно обойтись
  111.  
  112.                 т к есть expectedTexts.length
  113.                 и будет elementsTexts.size()
  114.             */
  115.             private int index;
  116.             /*
  117.                 это тоже лишнее
  118.                 в toString() достаточно вывести
  119.                 actual & expected тексты
  120.  
  121.                 этого будет более чем достаточно
  122.                 остальные варианты приведут только к усложнению логики
  123.             */
  124.             private List<String> elementsTexts = new ArrayList<String>();
  125.             /*
  126.                 ну, в принципе - можно и инициализировать тут
  127.  
  128.                 только вот вспомни - как работает until (WebDriverWait)
  129.                 метод кондишена apply - вызывается в цикле
  130.                 до тех пор пока - не закончится таймаут или условие не выполнится
  131.  
  132.                 потому - если далее в apply только вызывать elementsTexts.add
  133.                 то elementsTexts - будет пополняться и пополняться
  134.                 ерунда получится
  135.  
  136.                 внутри apply - надо инициализировать
  137.                 или
  138.                 тут - инициализировать + внутри apply перед циклом - очищать
  139.             */
  140.  
  141.             public Boolean apply(WebDriver driver) {
  142.                 try {
  143.                     ...
  144.  
  145.                     for (int index = 0; index < listSize; index++) {
  146.                     /*
  147.                         тут вполне подошел бы вариант цикла
  148.                         for(WebElement element:elements)
  149.                     */
  150.  
  151.                     if (listSize != textsSize) {
  152.                         return false;
  153.                     } else {
  154.                     /*
  155.                         сравнивать - можно размеры
  156.                         expectedTexts.length и elementsTexts.size()
  157.  
  158.                         не надо нам лишних сущностей)
  159.  
  160.                         else-блока можно не делать
  161.                         если размеры не равны - мы сразу выйдем
  162.                         дальнейший код - будет выполняться только если размеры равны
  163.  
  164.                         так  - чуть упростишь структуру кондишена
  165.                     */
  166.                         for(index = 0; index < listSize; index++) {
  167.                             if (elementsTexts.get(index).contains(expectedTexts[index])) {
  168.                                 continue;
  169.                             } else {
  170.                                 return false;
  171.                             }
  172.                             /*
  173.                                 тут и правда - удобнее цикл с целочисленным счетчиком
  174.  
  175.                                 для таких счетчиков - можно использовать однобуквенные переменные
  176.                                 for(int i = 0; i < elementsTexts.size(); i++)
  177.  
  178.                                 цитата из http://www.oracle.com/technetwork/java/codeconventions-135099.html
  179.                                 one-character variable names should be avoided except for temporary "throwaway" variables.
  180.                                 Common names for temporary variables are i, j, k, m, and n for integers;
  181.                                 c, d, and e for characters.
  182.  
  183.                                 нам не нужно для счетчика испольовать переменную, которая доступна еще где-то,
  184.                                 кроме этого цикла
  185.  
  186.                                 if - можно упростить
  187.                                 если не содержит - вернули false;
  188.                                 так уйдет else-блок
  189.  
  190.  .....
  191.  
  192.             public String toString() {
  193.                 return String.format("Lists size is %s, expectedTexts size is %s. " +
  194.                         "Text in element %s isn't contains expected text '%s'. " +
  195.                         "Expected text: '%s'", listSize, textsSize, index, expectedTexts[index], elementsTexts.get(index));
  196.             }
  197. /*
  198.     тут, при получении - expectedTexts[index] - ты уже можешь получить проблемы
  199.     да и не надо нам этих подробностей
  200.     проверяли то-то для элемента такого-то
  201.     expected ...
  202.     actual ...
  203.     т е - достаточно вывести полностью - ожидаемые тексты и фактические тексты
  204.     все есть, все получено
  205.     и этого достаточно
  206. */
  207. *************************************************************************************
  208. /*
  209.     это мы улучшали написанное, дальше - идем вперед)
  210. */
  211.  
  212. /*
  213.   Кодишенов есть много и разных
  214.     и далеко не все они ExpectedCondition<Boolean>
  215.     вот в этих <...> - могут быть разные типы
  216.     если совсем грубо - то результат вот этого ... типа и вернет нам WebDriverWait(...).until(...) -
  217.  
  218.     например
  219.          есть такой кондишен ExpectedCondition<WebElement> visibilityOfElementLocated(By locator)
  220.          https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#visibilityOfElementLocated-org.openqa.selenium.By-
  221.  
  222.          это значит WebDriverWait(...).until(visibilityOfElementLocated(...)) - вернет вебэлемент, видимость которого мы ждали
  223.  
  224.          а для кондишенов ExpectedCondition<Boolean> - new WebDriverWait(...).until вернет результат типа Boolean
  225.  
  226.          это не отменяет главной схемы работы - если проверка new WebDriverWait(...).until( - не проходит за таймаут -
  227.          то вызывается исключение
  228.  
  229.          но - помимо этого - есть вот такая разница ...
  230.  
  231.     пока наш assertThat возвращает void  - нас это может не сильно тревожить )
  232.     достаточно - в описании параметров убрать уточнение типа - не ExpectedCondition<Boolean>, а ExpectedCondition
  233.     и assertThat - будет работать с любым из кондишенов
  234.     правда - ничего нам не вернет)
  235.  
  236.     а вот если хочется получить результат new WebDriverWait(...).until( -
  237.     да еще и не городить кучу методов - придется подумать и немного теории почитать
  238. */
  239.  
  240.     public static WebElement $(WebDriver driver, By elementLocator) {
  241.         assertThat(driver, visibilityOfElementLocated(elementLocator));
  242.         return driver.findElement(elementLocator);
  243.     }
  244. /*
  245.     вот этот кондишен visibilityOfElementLocated - типа ExpectedCondition<WebElement>
  246.     значит - если бы assertThat возвращал то же, что и new WebDriverWait(...).until(...)
  247.  
  248.     то - assertThat вернул бы вебэлемент
  249.     и нам не пришлось бы его искать дополнительно
  250.     и метод выглядел бы вот так
  251. */
  252.     public static WebElement $(WebDriver driver, By elementLocator) {
  253.         return assertThat(driver, visibilityOfElementLocated(elementLocator));
  254.     }
  255. /*
  256.     Это не единственный вариант, когда нам это может пригодиться
  257.     но для самого простого и полезного примера - самое то)
  258.  
  259.     теперь - как этого добиться
  260. */
  261. /*
  262. Давай разберемся. Сначала "идейно".
  263.  
  264. Этот метод until возвращает такую интересную динамическую штуку-аватар...
  265. "воплощение" которого зависит от того что именно ты передашь вейт антилу параметром
  266. - точнее - какой именно кондишен ты ему передаешь...
  267.  
  268. А кондишены бывают "разные"... "Разность" эта определеятся "параметром типа" который в джава записывается
  269. ИмяТипа<ЗДЕСЬ>
  270.  
  271. Ты уже ведь использовал списки, например...
  272. В частности - List<WebElement>
  273.  
  274. вот в такой записи типа - его параметром, выступает WebElement, указывая джаве,
  275. что это не просто список, а "список ВебЕлементов"
  276. а мог бы быть и списком стрингов например - List<String> или еще чего :)
  277.  
  278. Такие "умные" типы которые получают параметр (или несколько параметров) - так и называются - параметризированными
  279. (а фича языка, в которой они поддерживаются называется - параметрическим полиформизмом -
  280. не путать с тем другим полиморфмизом... который называется - subtyping polymorphism,
  281. а в джава все его знают как просто "полиморфизм")...
  282. Еще они называются - шаблоны... или дженерики...
  283. Именно так - Java Generics - их принято называть в Java
  284.  
  285. Так вот... таким же дженериком является тип ExpectedCondition
  286. который может быть параметризирован...
  287.  
  288. Ты уже встречал запись типа:
  289. ExpectedCondition<Boolean>
  290.  
  291. что же значит этот булеан? что он параметризирует?
  292. А он параметризирует внутреннюю реализацию этого кондишена...
  293. Он определяет то, каким должен быть тип возвращаемого значения в методе apply
  294.  
  295. То есть...
  296. Если ты поставишь цель создать кондишен ExpectedCondition<Boolean> - ты должен будешь реализовать
  297. его метод apply -  как возвращающий тип Boolean
  298.  
  299. Но зачем вообще нам париться о типе возвращаемой сущности метода apply?
  300.  
  301. А потому, что есть еще один "умный дженерик"...
  302. Только который не "параметризированный класс", а "параметризированный метод"
  303. (в джава бывают как Generic Types так и Generic Methods)
  304.  
  305. и этот параметризированный метод - как раз и есть наш wait.until
  306.  
  307. особенность реализации этого метода в том... что он вызывает внутри метод apply
  308. нашего кондишена... и запоминает то значение, которое этот метод apply возвращает...
  309.  
  310. И потом... в конце всей истории... этот метод until - либо бросит исключение
  311. (в случае если "не дождется" кондишена)
  312. либо вернет то, что вернул метод apply в "случае успеха"...
  313.  
  314. Получается... Если ты передашь вейт антилу кондишен параметризированный типом Boolean
  315. то в случае успеха антил - вернет тру...
  316.  
  317. то есть ты можешь писать код вида:
  318.  
  319. if (wait.until(enabled(composeButton))) {
  320.    doSomething();
  321. }
  322.  
  323. но на самом деле, такое нужно не часто...
  324. то есть - такие кондишены - которые
  325. параметризированы типом булеан...
  326.  
  327. бошьше толку как раз от кондишенов параметризированных типом "того, характеристики чего ждет кондишен"...
  328.  
  329. вот кондишен visibilityOf - как раз параметризирован типом WebElement
  330.     ExpectedCondition<WebElement>
  331.  
  332. и его метод apply возвращает обьект типа WebElement,
  333. а "идейно" - возвращает этот же элемент, визибилити которого мы дожидались...
  334. (если бы мы не дождались - apply вернул бы null - что в этом случае играет роль "false")
  335.  
  336. а until в конце концов вернет то, что вернет apply
  337. и именно поэтому мы можем писать такой код:
  338.  
  339.     wait.until(visibilityOf(composeButton)).click()
  340.  
  341. теперь твоим заданием будет - переделать assertThat что бы он возвращал то что возвращает wait.until
  342.  
  343. ну и потом - переделать все свои кондишены, что бы они были параметризированы типом той сущности,
  344. характеристики которой они должни дожидаться (кстати так выражатся немного некорректно - ведь кондишен не ждет,
  345. он только выдает информацию - да/нет - а ждет уже вейт антил, ну то такое:) )
  346.  
  347. для того, чтобы "правильно реализовать этот wait.until" -
  348. тебе придется разобраться с этими дженериками...
  349. И с дженерик типами и дженерик методами.
  350.  
  351. И даже этого будет мало...
  352. Прийдется покопаться в коде селениума, чтобы понять, что там за тип реально получает
  353. вейт антил как кондишен...
  354. Потому что он получает не ExpectedCondition а что то еще более странное...
  355. Это работает - потому что это "странное" - есть родительским классом для ExpectedCondition
  356.  
  357. */
  358.  
  359. /*
  360.     Что почитать про Generics
  361.     про дженерики в общем(русский)
  362.     http://www.quizful.net/post/java-generics-tutorial
  363.    
  364.     http://www.tutorialspoint.com/java/java_generics.htm
  365.     http://developer.alexanderklimov.ru/android/java/generic.php
  366.    
  367.     конвеншенcы      http://stackoverflow.com/questions/2900881/generic-type-parameter-naming-convention-for-java-with-multiple-chars
  368.     https://docs.oracle.com/javase/tutorial/java/generics/types.html
  369.    
  370.     уроки
  371.     http://docs.oracle.com/javase/tutorial/extra/generics/index.html
  372.    
  373.     очень приличный faq (есть pdf, и есть кое-что еще, помимо дженериков)
  374.     http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
  375.    
  376.     ----------------------------------------------------------
  377.     для понимания кетчера (Catcher)
  378.     http://grepcode.com/file/repo1.maven.org/maven2/com.google.guava/guava/r06/com/google/common/base/Function.java
  379.     http://www.programcreek.com/java-api-examples/com.google.common.base.Function
  380.     https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html
  381.     http://stackoverflow.com/questions/3847162/java-generics-super-keyword
  382.     http://stackoverflow.com/questions/2800369/bounding-generics-with-super-keyword
  383.     http://stackoverflow.com/questions/1910892/what-is-the-difference-between-super-and-extends-in-java-generics
  384.    
  385.     если осилишь после этого и применение кетчера(то, что в прошлом ревью отложили) - можно уже сейчас
  386.     по-прежнему - кетчера можно отложить
  387. */
Advertisement
Add Comment
Please, Sign In to add comment