Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

Как добавить свои листенеры к Selenide коду?

listeners
selenide
webdriver
java
Теги: #<Tag:0x00007f7b60faec80> #<Tag:0x00007f7b60faeb40> #<Tag:0x00007f7b60fae9d8> #<Tag:0x00007f7b60fae898>

(Eugene Moskalenko) #1

@asolntsev, писал долго свой #selenide фреймворк, много опыта получил. Теперь пришел к тому моменту, когда можно уже начинать юзать selenide :slight_smile:

подскажите пожалуйста, как лучше добавить вот такие листенеры:

  • EventListener
  • Highlighter

я вот нашел как их можно добавить:

addListener(new EventListener());
addListener(new Highlighter());

это надо в BaseTest их указать, перед сьютом?

@BeforeSuite
    public void setUp() {
        addListener(new EventListener());
        addListener(new Highlighter());
    }

пробовал еще как-то через WebDriverRunner, но что-то упускаю. Спасибо…


Selenide: Лаконичные UI тесты на Java
(asolntsev) #2

Welcome to the club! :slight_smile:

Да, всё верно, в BaseTest.setUp()


(Eugene Moskalenko) #3

вот странно очень, я так и сделал сразу, по логике так то оно так, но чето не применяются листенеры

    @BeforeSuite
    public void setUp() {
        addListener(new EventListener());
        addListener(new Highlighter());
    }

и в тестах унаследовался от класса BaseTest

и такой еще вопросик, в документациях посмотрел, как тесты пишутся, но с вейтами немного не понял, набыдлокодил как-то так:

  1. есть страничка при вводе на которой в поле урла, появляется лоадинг-бар
  2. когда лоадинг-бар доходит, до 100% - он пропадает и появляется новый контент завернутый в дивчик с классом - .pagespeed-results

не костыль ли это я сделал? Может есть проще решение?

public class GooglePageSpeed extends BasePage implements Waiting {

    private static final Logger logger = LogManager.getLogger(GooglePageSpeed.class);

    public GooglePageSpeedResultsPage searchFor(String urlCriteria) {
        // нахожу поле и ввожу туда урл, затем нажимаю Enter
        $(".url").val(urlCriteria).pressEnter();
        // жду пока пропадет прогресс-бар с классом - ".jfk-progressStatus"
        waitUntilPagesIsLoaded(".jfk-progressStatus", disappears, 20000);
        // ожидаю нового элемента с контентом, пока он не появится на странице - ".pagespeed-results"
        $(".pagespeed-results").shouldBe(present);
        // возвращаю себе новый обьект странички, в котором уже работаю с контентом, который подгрузился после поиска
        return page(GooglePageSpeedResultsPage.class);
    }

}
public interface Waiting {
    default void waitUntilPagesIsLoaded(String cssSelector, Condition condition, int timeInMilliseconds) {
        $(cssSelector).waitUntil(condition, timeInMilliseconds);
    }
}

не усложнил ли я с ожиданиями? Может есть проще? Просто:

$(".pagespeed-results").shouldBe(present);

не канает

:slight_smile:

Я так понял, по докам, оно ждет 4 секунды, а прогресс-бар может лоадиться и 6 секунд и тогда часть тестов с урлом падает, а часть нет :slight_smile:


(asolntsev) #4
  1. Про BaseTest.setUp(): важно, чтобы эти строчки вызывались ДО того, как открылся браузер. То есть ДО вызова метода open().

  2. В принципе всё верно, но можно чуть упростить. Вот так:

$(".pagespeed-results").waitUntil(present, 20000);


(Eugene Moskalenko) #5

Про BaseTest.setUp(): важно, чтобы эти строчки вызывались ДО того, как открылся браузер. То есть ДО вызова метода open().

именно так и делаю. Спасибо большое за наводку, двигаюсь в правильном направлении, буду смотреть, где я натупил :slight_smile:

В принципе всё верно, но можно чуть упростить. Вот так: $(".pagespeed-results").waitUntil(present, 20000);

так тоже делал. Ну в принципе мой вариант, не так и ужасен, как я понял, значит так и оставлю, если ваш вариант будет крешить часть тестов

Спасиб за помощь


(Roma Marinsky) #6

Я обычно ожидание страницы/формы/блока делаю в конструкторе соответствующего объекта
Так как метод searchFor ничего не знает о странице результата, она просто на сревак отправит запрос, по которуму вернётся ответ с результатом и редиректом на соответствующую страницу результата поиска, на которой есть нужный тебе локатор. И поэтому ожидание открытия нужной страницы лежит в конструкторе класса нужного мне.
Т.е. в твоём случае это:

class GooglePageSpeedResultsPage{
    public GooglePageSpeedResultsPage(){
        $(".pagespeed-results").waitUntil(present, 20000);
    }
}

(Eugene Moskalenko) #7

Довольно интересное решение, раньше об этом не задумывался, спасибо. В ситуациях, когда на пейджах контент меняется не динамически - довольно хороший вариант реализаций ожидания.

А вот как тогда делаешь, если скажем страница у тебя HomePage, при клике, аяксом или js-ом подгружается другой контент. Затем есть еще один таб там или несколько, и при клике на каждый контент меняется. по сути остаешься на том-же HomePage, но контент меняется динамически. В моем этом случае именно так. Я конечно разделил эту страницу на несколько объектов:

  • просто пейдж
  • серч-резалт пейдж

но если таких табов, изменений будет более 3-4, то уже так делать не стоит, думаю. Тогда уже надо будет на каждый ивент вешать ожидание и ждать пока он не отработает, в пределах одного объекта - страницы.


(Roma Marinsky) #8

Ну если хочешь заморочиться с этим, можешь в конструктор строку передавать, и в конструкторе свич или иф элс фигачить. Но всё же я бы обошёлся уже без такого умного конструктора в таком случае)


(Eugene Moskalenko) #9

Та полюбому, это будет уже избыточно… Вот просто у меня как раз такой случай :slight_smile:


(Pavel Ponomaryov) #10

тогда просто в методе который кликает на определённый элемент вы можете возвращать return new HomePageTab1(); в конструкторе которого находятся уже свои ожидания и условия. Я бы не делал один мега класс HomePage, который отвечает за все вкладки.


(Eugene Moskalenko) #11

Да так будет правильней. Я так с попапами делаю всякими


(Рома Маринский) #12

А у меня для таких задач есть класс MainComponent, а HomePage только с нужными ему методами


(Рома Маринский) #13

Вот как я это все дело делаю https://github.com/rmarinsky/ElementObjectSelenide


(Pavel Ponomaryov) #14

объясните мне смысл проверки $$(buttonAddToCart).forEach(SelenideElement::isDisplayed); ?


(Eugene Moskalenko) #15

объясните мне смысл проверки $$(buttonAddToCart).forEach(SelenideElement::isDisplayed); ?

пройтись по каждому элементу (buttonAddToCart) на странице и проверить присутствует ли он на ней


(Eugene Moskalenko) #16

Если честно, глянул я его, непонятно что он делает - MainComponent


(Рома Маринский) #17

Он сабмитит любую форму на странице, хранит локаторы информационных сообщений. А эти штуки есть на любой странице и на любом попапе


(Рома Маринский) #18

Грубо говоря, на странице должен быть видим хотя бы один элемент.


(Eugene Moskalenko) #19

Есть конечно интересные моменты в вашем фреймворке :slight_smile:

Но мне больше нравится концепция PageObject:

И напоследок про ООП
Хочу напомнить, что изначальный смысл Page Objects состоял в том, чтобы инкапсулировать (то есть прятать!) логику работы с элементами. Тесты не должны ничего знать о веб-элементах, не должны оперировать напрямую с XPath или другими селекторами. Тесты должны использовать публичные методы пэдж объекта.

То есть если уж вы объявляете поля для элементов, то пусть они будут приватными, а все операции с ними пусть осуществляются через публичные методы.

Иначе зачем весь этот ООП?


(Pavel Ponomaryov) #20

может тогда проще проверять $$(buttonAddToCart).shouldHave(CollectionCondition.sizeGreaterThan(0))? Или цель проверить именно видимость? Не совсем уверен, включает ли в себя ElementsCollection невидимые элементы. В принципе в данном случае хватило бы $(buttonAddToCart).shouldBe(visible);