Advertisement
julia_v_iluhina

Untitled

Oct 20th, 2016
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 18.01 KB | None | 0 0
  1. public class ByText extends By {
  2.     private final String text;
  3.  
  4.     public ByText(String text) {
  5.         this.text = text;
  6.     }
  7.  
  8.     @Override
  9.     public List<WebElement> findElements(SearchContext context) {
  10.         return ((FindsByXPath)context).findElementsByXPath(".//*[@text()= \'" + this.text + "\']");
  11.     }
  12. }
  13. /*
  14.     ну, я предлагаю обойтись без класса ByText)
  15.     просто в методе byText
  16.     воспользуемся By.xPath(...)
  17.     а само xPath - выражение - у тебя уже есть)
  18.  
  19.     советую посмотреть на аналогичное выражение в Selenide (посмотри на реализацию byText там)
  20. */
  21. ********************************************************
  22. public abstract class SupportingApi {
  23.  
  24.     protected static WebDriver driver;
  25. ...
  26.  
  27. public class BaseTest extends SupportingApi {
  28. ...
  29.  
  30. public class Gmail extends BaseTest {
  31. ...
  32.  
  33. /*
  34.     наворочено слишком с наследованием
  35.     наследовать пейджа от предка тест-класса - не очень решение
  36.  
  37.     следующая версия как раз будет про то, как можно исхитриться использовать наследование в наших целях
  38.     и слеующая версия - нарушает принцип Composition over inheritance
  39.     но она будет все равно стройнее
  40.  
  41.     давай пока сделаем проще - это и полезнее будет
  42.  
  43.     класс SupportingApi
  44.     давай переименуем в ConciseAPI
  45.  
  46.     во все методы этого класса ConciseAPI
  47.     которым нужен вебдрайвер - добавь первый параметр - WebDriver driver
  48.     да, вызовы этих методов получатся не очень лаконичные
  49.     но - зато будет легче все это реализовать
  50.  
  51.     BaseTest - ни от чего не наследуем
  52.     там объявляем поле WebDriver driver
  53.     и инициализируем его - как ты и делала
  54.  
  55.     Пейджи - не наследуй ни от BaseTest, ни от ConciseAPI
  56.     В пейджи - будем передавать драйвер при вызове конструктора
  57.     а это значит - что будем использовать
  58.     не пейдж-модули
  59.     а пейдж-объекты
  60.     и в конструктор пейджа - в качестве параметра - будешь передавать вебдрайвер
  61.     посмотришь - если поймешь как и зачем - реализуешь общего предка для пейджей
  62.     а нет - пока обойдись без предка
  63. */
  64.  
  65. public class BaseTest extends SupportingApi {
  66.  
  67.  
  68.     @BeforeClass
  69.     public static void setup() {
  70.         ...
  71.         Configuration.timeout = 4;
  72.     }
  73. /*
  74.     вспомни селенидовское решение этой задачи
  75.     где ты устанавливала Configuration.timeout?
  76.     сколько секунд требовалось для gmail?
  77.  
  78.     тут аналогично сделай
  79. */
  80. ************************************************
  81.  
  82.     protected static WebDriverWait wait;
  83.     /*
  84.         не нужна нам такая переменная теперь
  85.     */
  86.  
  87.     public static WebElement $(String cssSelector) {
  88.         wait = new WebDriverWait(driver, 10);
  89.         /*
  90.             инициализировать такую переменную внутри метода $(String cssSelector) - вредно
  91.             это источник многих ошибок
  92.  
  93.             получается - если мы такой метод не вызвали первым - то все)
  94.             обращение к wait будет приводить к Null Pointer Exception
  95.  
  96.             нам и для реализации проверок - нужен
  97.              new WebDriverWait(...).until(....)
  98.             вот и давай - для начала - переселим сюда методы
  99.             assertThat
  100.             которые ты зачем-то аж в пейже реализовала)
  101.  
  102.             и в assertThat-ы - передадим вебдрайвер и кондишен
  103.             и там - в этом методе - и вызывай
  104.             new WebDriverWait(...).until(....)
  105.  
  106.             а в других методах, где требуется new WebDriverWait(...).until(....)
  107.             уже вызывай этот assertThat
  108.  
  109.             в частности, и тут в $(String cssSelector)
  110.             вызывай assertThat для visibilityOfElementLocated
  111.         */
  112.  
  113.         wait.until(visibilityOfElementLocated(By.cssSelector(cssSelector)));
  114.         return getWebDriver().findElement(By.cssSelector(cssSelector));
  115.     }
  116.  
  117.     public static WebElement $(By name) {
  118.     /*
  119.         name - не удачное имя для параметра
  120.         это locator, elementLocator, by
  121.     */
  122.  ***************************
  123.      public static void open(String url) {
  124.          driver.get(url);
  125.      }
  126.  /*
  127.     это - универсальный метод открытия страницы
  128.     и ему место не в пейдже, а в ConciseAPI
  129.  
  130.     вспомни - какой метод мы в пейдже реализовывали для открытия gmail)
  131.     мы в нем использовали open
  132.  */
  133. ***********************************
  134.  public class Mails extends BaseTest {
  135.  
  136.  ....
  137.  
  138.      public static  <T> T assertThat(ExpectedCondition<T> condition, int timeout) {
  139.      public static  <T> T assertThat(ExpectedCondition<T> condition) {
  140.  
  141. /*
  142.     ага, а вот и assertThat)
  143.  
  144.     почему в пейдже? )
  145.  
  146.     ведь это - универсальные вещи)
  147.  
  148.     и вот ты и Configuration.timeout используешь
  149.     да и с использованием дженерик-типов реализовала
  150.     )
  151.  
  152.     про дженерик-типы - вставлю кусочек пояснений, вдруг нужны
  153.     это уже внизу ревью
  154. */
  155. ***********************************************
  156.     public static ExpectedCondition<Boolean> NthElementHasText(final By elementsLocator, final int index, final String text) {
  157.         return new ExpectedCondition<Boolean>() {
  158.             @Override
  159.             public Boolean apply(WebDriver driver) {
  160.                 return driver.findElements(elementsLocator).get(index).getText().equals(text);
  161.             }
  162.         };
  163.     }
  164. /*
  165.     располагать кондишены в пейдже - тоже как-то странно)
  166.  
  167.     кондишены - вещь универсальная
  168.     реализуй для ник отдельный класс CustomConditions
  169.  
  170.     еще такой момент
  171.     toString кондишена - должен возвращать строку
  172.     описsывающую - что проверяли, для чего проверяли, чего ожидали, и что получили
  173.     иначе - не понятно будет  - почему тест упал)
  174.  
  175.     тебе нужен кондишен, который текст index-ого элемента проверяет
  176.     не на equals
  177.     а на contains
  178.  
  179.     и когда ты будешь получать элемент по индексу
  180.     выходящему за границы списка - будет возникать исключение
  181.     IndexOutOfRangeException
  182.     такие вещи надо ловить внутри apply
  183.  
  184.     посмотри - как реализованы стандартные селениумские кондишены
  185.     набери в коде ExpectedConditions
  186.     и зажав ctrl - кликни на этом слове
  187.     откроется модуль с реализованными стандартными кондишенами
  188.     возможно - какие-то идеи оттуда тебе пригодятся
  189.    
  190.     кстати, вспомни - имена методов - начинаются с маленькой буквы
  191.     public static ExpectedCondition<Boolean> NthElementHasText(... - это метод
  192.     в нем мы создаем объект анонимного класса
  193.     но это метод)
  194. */
  195. public static ExpectedCondition<Boolean> ElementsHaveText(final By elementsLocator, final String... texts) {
  196. /*
  197.     примени и к этому кондишену - те же комментарии
  198. */
  199. *************************************
  200.     @Step
  201.     public static void assertMail(int index, String mailTitleText) {
  202.         assertThat(NthElementHasText(By.cssSelector("[role ='main'] .zA"), index, mailTitleText));
  203.     }
  204.  
  205.     @Step
  206.     public static void assertMails(String... mailTitleTexts) {
  207.         assertThat(ElementsHaveText(By.cssSelector("[role ='main'] .zA"), mailTitleTexts));
  208.     }
  209. /*
  210.     By.cssSelector("[role ='main'] .zA") - используешь дважды
  211.     вынеси это в переменную и используй
  212.    
  213.     локатор - суть рассказ - как искать элемент
  214.     потому - это запросто можно выносить в переменную и использовать
  215. */
  216. *****************************************
  217. /*
  218.     возможно - будут проблемы с кондишенами
  219.     для начала - закомментируй проверки assertMail и assertMails
  220.     и добейся - чтоб все остальное работало
  221.     потом - сосредоточься на кондишенах
  222. */  
  223. ***************************************************
  224. /*
  225.     теперь - обещанный кусок про дженерик-типы
  226.    
  227.       Кодишенов есть много и разных
  228.         и далеко не все они ExpectedCondition<Boolean>
  229.         вот в этих <...> - могут быть разные типы
  230.         если совсем грубо - то результат вот этого ... типа и вернет нам WebDriverWait(...).until(...) -
  231.    
  232.         например
  233.              есть такой кондишен ExpectedCondition<WebElement> visibilityOfElementLocated(By locator)
  234.              https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#visibilityOfElementLocated-org.openqa.selenium.By-
  235.    
  236.              это значит WebDriverWait(...).until(visibilityOfElementLocated(...)) - вернет вебэлемент, видимость которого мы ждали
  237.    
  238.              а для кондишенов ExpectedCondition<Boolean> - new WebDriverWait(...).until вернет результат типа Boolean
  239.    
  240.              это не отменяет главной схемы работы - если проверка new WebDriverWait(...).until( - не проходит за таймаут -
  241.              то вызывается исключение
  242.    
  243.              но - помимо этого - есть вот такая разница ...
  244.    
  245.         если хочется получить результат new WebDriverWait(...).until( -
  246.         да еще и не городить кучу методов - как раз нам нужны дженерик-типы
  247.        
  248.        
  249.      Давай разберемся. Сначала "идейно".
  250.      
  251.      Этот метод until возвращает такую интересную динамическую штуку-аватар...
  252.      "воплощение" которого зависит от того что именно ты передашь вейт антилу параметром
  253.      - точнее - какой именно кондишен ты ему передаешь...
  254.      
  255.      А кондишены бывают "разные"... "Разность" эта определеятся "параметром типа" который в джава записывается
  256.      ИмяТипа<ЗДЕСЬ>
  257.      
  258.      Ты уже ведь использовал списки, например...
  259.      В частности - List<WebElement>
  260.      
  261.      вот в такой записи типа - его параметром, выступает WebElement, указывая джаве,
  262.      что это не просто список, а "список ВебЕлементов"
  263.      а мог бы быть и списком стрингов например - List<String> или еще чего :)
  264.      
  265.      Такие "умные" типы которые получают параметр (или несколько параметров) - так и называются -
  266.      параметризированными
  267.      (а фича языка, в которой они поддерживаются называется - параметрическим полиформизмом -
  268.      не путать с тем другим полиморфмизом... который называется - subtyping polymorphism,
  269.      а в джава все его знают как просто "полиморфизм")...
  270.      Еще они называются - шаблоны... или дженерики...
  271.      Именно так - Java Generics - их принято называть в Java
  272.      
  273.      Так вот... таким же дженериком является тип ExpectedCondition
  274.      который может быть параметризирован...
  275.      
  276.      Ты уже встречал запись типа:
  277.      ExpectedCondition<Boolean>
  278.      
  279.      что же значит этот булеан? что он параметризирует?
  280.      А он параметризирует внутреннюю реализацию этого кондишена...
  281.      Он определяет то, каким должен быть тип возвращаемого значения в методе apply
  282.      
  283.      То есть...
  284.      Если ты поставишь цель создать кондишен ExpectedCondition<Boolean> - ты должен будешь реализовать
  285.      его метод apply -  как возвращающий тип Boolean
  286.      
  287.      Но зачем вообще нам париться о типе возвращаемой сущности метода apply?
  288.      
  289.      А потому, что есть еще один "умный дженерик"...
  290.      Только который не "параметризированный класс", а "параметризированный метод"
  291.      (в джава бывают как Generic Types так и Generic Methods)
  292.      
  293.      и этот параметризированный метод - как раз и есть наш wait.until
  294.      
  295.      особенность реализации этого метода в том... что он вызывает внутри метод apply
  296.      нашего кондишена... и запоминает то значение, которое этот метод apply возвращает...
  297.      
  298.      И потом... в конце всей истории... этот метод until - либо бросит исключение
  299.      (в случае если "не дождется" кондишена)
  300.      либо вернет то, что вернул метод apply в "случае успеха"...
  301.      
  302.      Получается... Если ты передашь вейт антилу кондишен параметризированный типом Boolean
  303.      то в случае успеха антил - вернет тру...
  304.      
  305.      то есть ты можешь писать код вида:
  306.      
  307.      if (wait.until(enabled(composeButton))) {
  308.         doSomething();
  309.      }
  310.      
  311.      но на самом деле, такое нужно не часто...
  312.      то есть - такие кондишены - которые
  313.      параметризированы типом булеан...
  314.      
  315.      бошьше толку как раз от кондишенов параметризированных типом "того, характеристики чего ждет кондишен"...
  316.      
  317.      вот кондишен visibilityOf - как раз параметризирован типом WebElement
  318.          ExpectedCondition<WebElement>
  319.      
  320.      и его метод apply возвращает обьект типа WebElement,
  321.      а "идейно" - возвращает этот же элемент, визибилити которого мы дожидались...
  322.      (если бы мы не дождались - apply вернул бы null - что в этом случае играет роль "false")
  323.      
  324.      а until в конце концов вернет то, что вернет apply
  325.      и именно поэтому мы можем писать такой код:
  326.      
  327.          wait.until(visibilityOf(composeButton)).click()
  328.      
  329.      теперь твоим заданием будет - переделать assertThat что бы он возвращал то что возвращает wait.until
  330.      
  331.      ну и потом - переделать все свои кондишены, что бы они были параметризированы типом той сущности,
  332.      характеристики которой они должни дожидаться (кстати так выражатся немного некорректно - ведь кондишен не ждет,
  333.      он только выдает информацию - да/нет - а ждет уже вейт антил, ну то такое:) )
  334. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement