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

@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, но что-то упускаю. Спасибо…

1 лайк

Welcome to the club! :slight_smile:

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

1 лайк

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

    @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:

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

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

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

1 лайк

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

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

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

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

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

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

class GooglePageSpeedResultsPage{
    public GooglePageSpeedResultsPage(){
        $(".pagespeed-results").waitUntil(present, 20000);
    }
}
2 лайка

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

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

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

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

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

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

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

1 лайк

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

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

Вот как я это все дело делаю GitHub - rmarinsky/ElementObjectSelenide: Simple project builded on Selenide wrapper

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

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

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

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

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

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

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

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

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

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

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

1 лайк

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