Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public static void assertThat(WebDriver driver, ExpectedCondition condition) {
- assertThat(driver, condition, timeout);
- }
- /*
- А вот тут как раз тот случай, когда нету смысла импортить статически core.Configuration.timeout;
- лучше быть точнее и указывать в коде - Configuration.timeout
- чтобы явно подчеркнуть - что за таймаут тут в данном случае
- */
- ******************************
- $(driver, By.id("Email")).sendKeys(email + Keys.ENTER);
- /*
- можно в ConciseAPI
- дореадизовать метод
- public static WebElement $(WebDriver driver, String cssSelector)
- т к зачастую - он будет удобнее в работе
- тут, например,
- вместо
- $(driver, By.id("Email"))
- получил бы
- $(driver, "#Email")
- не забывай про DRY
- и в $(WebDriver driver, String cssSelector)
- переиспользуй ранее реализованный метод $(...)
- */
- *****************************************
- public void createEmail() {
- $(driver, By.cssSelector(".z0 .T-I")).click();
- }
- /*
- В Selenide-версии было лучше - нагляднее )
- */
- public static void createEmail() {
- $(byText("НАПИСАТЬ")).click();
- }
- /*
- реализуй в ConciseAPI метод byText
- подсмотри - как это реализовано в Selenide
- фактически - тебе через xPath выражение надо получить локатор
- можно выражение и попроще, чем в Selenide, использовать
- там просто оно большее к-во вариантов покрывает
- про имя метода - писала еще в http://pastebin.com/XgnLDBuR, строки 20-27
- не настаиваю, но я бы воспользовалась термином с UI = compose
- термины с UI - самые наглядные термины)
- не обязательно, но можно (не обязательно - т к ты в этом проекте вполне обойдешься без таких методов)
- реализовать метод byTitle
- применить его для переходов в Inbox & Sent
- цель - реализовать полезный в будущем метод и отладить его тут
- как реализовать - см идеи в Selenide
- еще - для уменьшения количества писанины - можно было бы реализовать
- By byCss(String cssSelector)
- */
- ************************************
- public void goToSend() {
- /*
- goToSen___t___
- буковку поправь )
- */
- *******************************
- public void send(String email, String subject) {
- ...
- $(driver, By.id(":lo")).click();
- }
- /*
- в селенидовской версии - было понагляднее)
- */
- $(byText("Отправить")).click();
- /*
- т к уже и тут byText есть - смело применяй
- */
- **********************************************
- public static ExpectedCondition<Boolean> listNthElementHasText(final List<WebElement> elements, final int index, final String expectedText) {
- return new ExpectedCondition<Boolean>() {
- ...
- public Boolean apply(WebDriver driver) {
- try {
- ...
- } catch (StaleElementReferenceException var3) {
- ...
- }
- }
- /*
- лови в catch-секции и вот это исключение - IndexOutOfBoundsException
- оно возникает - когда мы пытаемся получить элемент списка по индексу за пределами списка
- чтобы применять одну catch-секцию
- http://stackoverflow.com/questions/3495926/can-i-catch-multiple-java-exceptions-in-the-same-catch-clause
- */
- *****************************************************
- public static ExpectedCondition<Boolean> texts(final List<WebElement> elements, final String ... expectedTexts) {
- return new ExpectedCondition<Boolean>() {
- private int listSize;
- private int textsSize;
- /*
- без этих переменных можно обойтись
- т к есть expectedTexts.length
- и будет elementsTexts.size()
- */
- private int index;
- /*
- это тоже лишнее
- в toString() достаточно вывести
- actual & expected тексты
- этого будет более чем достаточно
- остальные варианты приведут только к усложнению логики
- */
- private List<String> elementsTexts = new ArrayList<String>();
- /*
- ну, в принципе - можно и инициализировать тут
- только вот вспомни - как работает until (WebDriverWait)
- метод кондишена apply - вызывается в цикле
- до тех пор пока - не закончится таймаут или условие не выполнится
- потому - если далее в apply только вызывать elementsTexts.add
- то elementsTexts - будет пополняться и пополняться
- ерунда получится
- внутри apply - надо инициализировать
- или
- тут - инициализировать + внутри apply перед циклом - очищать
- */
- public Boolean apply(WebDriver driver) {
- try {
- ...
- for (int index = 0; index < listSize; index++) {
- /*
- тут вполне подошел бы вариант цикла
- for(WebElement element:elements)
- */
- if (listSize != textsSize) {
- return false;
- } else {
- /*
- сравнивать - можно размеры
- expectedTexts.length и elementsTexts.size()
- не надо нам лишних сущностей)
- else-блока можно не делать
- если размеры не равны - мы сразу выйдем
- дальнейший код - будет выполняться только если размеры равны
- так - чуть упростишь структуру кондишена
- */
- for(index = 0; index < listSize; index++) {
- if (elementsTexts.get(index).contains(expectedTexts[index])) {
- continue;
- } else {
- return false;
- }
- /*
- тут и правда - удобнее цикл с целочисленным счетчиком
- для таких счетчиков - можно использовать однобуквенные переменные
- for(int i = 0; i < elementsTexts.size(); i++)
- цитата из http://www.oracle.com/technetwork/java/codeconventions-135099.html
- one-character variable names should be avoided except for temporary "throwaway" variables.
- Common names for temporary variables are i, j, k, m, and n for integers;
- c, d, and e for characters.
- нам не нужно для счетчика испольовать переменную, которая доступна еще где-то,
- кроме этого цикла
- if - можно упростить
- если не содержит - вернули false;
- так уйдет else-блок
- .....
- public String toString() {
- return String.format("Lists size is %s, expectedTexts size is %s. " +
- "Text in element %s isn't contains expected text '%s'. " +
- "Expected text: '%s'", listSize, textsSize, index, expectedTexts[index], elementsTexts.get(index));
- }
- /*
- тут, при получении - expectedTexts[index] - ты уже можешь получить проблемы
- да и не надо нам этих подробностей
- проверяли то-то для элемента такого-то
- expected ...
- actual ...
- т е - достаточно вывести полностью - ожидаемые тексты и фактические тексты
- все есть, все получено
- и этого достаточно
- */
- *************************************************************************************
- /*
- это мы улучшали написанное, дальше - идем вперед)
- */
- /*
- Кодишенов есть много и разных
- и далеко не все они 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 - будет работать с любым из кондишенов
- правда - ничего нам не вернет)
- а вот если хочется получить результат new WebDriverWait(...).until( -
- да еще и не городить кучу методов - придется подумать и немного теории почитать
- */
- public static WebElement $(WebDriver driver, By elementLocator) {
- assertThat(driver, visibilityOfElementLocated(elementLocator));
- return driver.findElement(elementLocator);
- }
- /*
- вот этот кондишен visibilityOfElementLocated - типа ExpectedCondition<WebElement>
- значит - если бы assertThat возвращал то же, что и new WebDriverWait(...).until(...)
- то - assertThat вернул бы вебэлемент
- и нам не пришлось бы его искать дополнительно
- и метод выглядел бы вот так
- */
- public static WebElement $(WebDriver driver, By elementLocator) {
- return assertThat(driver, visibilityOfElementLocated(elementLocator));
- }
- /*
- Это не единственный вариант, когда нам это может пригодиться
- но для самого простого и полезного примера - самое то)
- теперь - как этого добиться
- */
- /*
- Давай разберемся. Сначала "идейно".
- Этот метод 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