Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class ByText extends By {
- private final String text;
- public ByText(String text) {
- this.text = text;
- }
- @Override
- public List<WebElement> findElements(SearchContext context) {
- return ((FindsByXPath)context).findElementsByXPath(".//*[@text()= \'" + this.text + "\']");
- }
- }
- /*
- ну, я предлагаю обойтись без класса ByText)
- просто в методе byText
- воспользуемся By.xPath(...)
- а само xPath - выражение - у тебя уже есть)
- советую посмотреть на аналогичное выражение в Selenide (посмотри на реализацию byText там)
- */
- ********************************************************
- public abstract class SupportingApi {
- protected static WebDriver driver;
- ...
- public class BaseTest extends SupportingApi {
- ...
- public class Gmail extends BaseTest {
- ...
- /*
- наворочено слишком с наследованием
- наследовать пейджа от предка тест-класса - не очень решение
- следующая версия как раз будет про то, как можно исхитриться использовать наследование в наших целях
- и слеующая версия - нарушает принцип Composition over inheritance
- но она будет все равно стройнее
- давай пока сделаем проще - это и полезнее будет
- класс SupportingApi
- давай переименуем в ConciseAPI
- во все методы этого класса ConciseAPI
- которым нужен вебдрайвер - добавь первый параметр - WebDriver driver
- да, вызовы этих методов получатся не очень лаконичные
- но - зато будет легче все это реализовать
- BaseTest - ни от чего не наследуем
- там объявляем поле WebDriver driver
- и инициализируем его - как ты и делала
- Пейджи - не наследуй ни от BaseTest, ни от ConciseAPI
- В пейджи - будем передавать драйвер при вызове конструктора
- а это значит - что будем использовать
- не пейдж-модули
- а пейдж-объекты
- и в конструктор пейджа - в качестве параметра - будешь передавать вебдрайвер
- посмотришь - если поймешь как и зачем - реализуешь общего предка для пейджей
- а нет - пока обойдись без предка
- */
- public class BaseTest extends SupportingApi {
- @BeforeClass
- public static void setup() {
- ...
- Configuration.timeout = 4;
- }
- /*
- вспомни селенидовское решение этой задачи
- где ты устанавливала Configuration.timeout?
- сколько секунд требовалось для gmail?
- тут аналогично сделай
- */
- ************************************************
- protected static WebDriverWait wait;
- /*
- не нужна нам такая переменная теперь
- */
- public static WebElement $(String cssSelector) {
- wait = new WebDriverWait(driver, 10);
- /*
- инициализировать такую переменную внутри метода $(String cssSelector) - вредно
- это источник многих ошибок
- получается - если мы такой метод не вызвали первым - то все)
- обращение к wait будет приводить к Null Pointer Exception
- нам и для реализации проверок - нужен
- new WebDriverWait(...).until(....)
- вот и давай - для начала - переселим сюда методы
- assertThat
- которые ты зачем-то аж в пейже реализовала)
- и в assertThat-ы - передадим вебдрайвер и кондишен
- и там - в этом методе - и вызывай
- new WebDriverWait(...).until(....)
- а в других методах, где требуется new WebDriverWait(...).until(....)
- уже вызывай этот assertThat
- в частности, и тут в $(String cssSelector)
- вызывай assertThat для visibilityOfElementLocated
- */
- wait.until(visibilityOfElementLocated(By.cssSelector(cssSelector)));
- return getWebDriver().findElement(By.cssSelector(cssSelector));
- }
- public static WebElement $(By name) {
- /*
- name - не удачное имя для параметра
- это locator, elementLocator, by
- */
- ***************************
- public static void open(String url) {
- driver.get(url);
- }
- /*
- это - универсальный метод открытия страницы
- и ему место не в пейдже, а в ConciseAPI
- вспомни - какой метод мы в пейдже реализовывали для открытия gmail)
- мы в нем использовали open
- */
- ***********************************
- public class Mails extends BaseTest {
- ....
- public static <T> T assertThat(ExpectedCondition<T> condition, int timeout) {
- public static <T> T assertThat(ExpectedCondition<T> condition) {
- /*
- ага, а вот и assertThat)
- почему в пейдже? )
- ведь это - универсальные вещи)
- и вот ты и Configuration.timeout используешь
- да и с использованием дженерик-типов реализовала
- )
- про дженерик-типы - вставлю кусочек пояснений, вдруг нужны
- это уже внизу ревью
- */
- ***********************************************
- public static ExpectedCondition<Boolean> NthElementHasText(final By elementsLocator, final int index, final String text) {
- return new ExpectedCondition<Boolean>() {
- @Override
- public Boolean apply(WebDriver driver) {
- return driver.findElements(elementsLocator).get(index).getText().equals(text);
- }
- };
- }
- /*
- располагать кондишены в пейдже - тоже как-то странно)
- кондишены - вещь универсальная
- реализуй для ник отдельный класс CustomConditions
- еще такой момент
- toString кондишена - должен возвращать строку
- описsывающую - что проверяли, для чего проверяли, чего ожидали, и что получили
- иначе - не понятно будет - почему тест упал)
- тебе нужен кондишен, который текст index-ого элемента проверяет
- не на equals
- а на contains
- и когда ты будешь получать элемент по индексу
- выходящему за границы списка - будет возникать исключение
- IndexOutOfRangeException
- такие вещи надо ловить внутри apply
- посмотри - как реализованы стандартные селениумские кондишены
- набери в коде ExpectedConditions
- и зажав ctrl - кликни на этом слове
- откроется модуль с реализованными стандартными кондишенами
- возможно - какие-то идеи оттуда тебе пригодятся
- кстати, вспомни - имена методов - начинаются с маленькой буквы
- public static ExpectedCondition<Boolean> NthElementHasText(... - это метод
- в нем мы создаем объект анонимного класса
- но это метод)
- */
- public static ExpectedCondition<Boolean> ElementsHaveText(final By elementsLocator, final String... texts) {
- /*
- примени и к этому кондишену - те же комментарии
- */
- *************************************
- @Step
- public static void assertMail(int index, String mailTitleText) {
- assertThat(NthElementHasText(By.cssSelector("[role ='main'] .zA"), index, mailTitleText));
- }
- @Step
- public static void assertMails(String... mailTitleTexts) {
- assertThat(ElementsHaveText(By.cssSelector("[role ='main'] .zA"), mailTitleTexts));
- }
- /*
- By.cssSelector("[role ='main'] .zA") - используешь дважды
- вынеси это в переменную и используй
- локатор - суть рассказ - как искать элемент
- потому - это запросто можно выносить в переменную и использовать
- */
- *****************************************
- /*
- возможно - будут проблемы с кондишенами
- для начала - закомментируй проверки assertMail и assertMails
- и добейся - чтоб все остальное работало
- потом - сосредоточься на кондишенах
- */
- ***************************************************
- /*
- теперь - обещанный кусок про дженерик-типы
- Кодишенов есть много и разных
- и далеко не все они 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( - не проходит за таймаут -
- то вызывается исключение
- но - помимо этого - есть вот такая разница ...
- если хочется получить результат new WebDriverWait(...).until( -
- да еще и не городить кучу методов - как раз нам нужны дженерик-типы
- Давай разберемся. Сначала "идейно".
- Этот метод 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
- ну и потом - переделать все свои кондишены, что бы они были параметризированы типом той сущности,
- характеристики которой они должни дожидаться (кстати так выражатся немного некорректно - ведь кондишен не ждет,
- он только выдает информацию - да/нет - а ждет уже вейт антил, ну то такое:) )
- */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement