Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Oct 20 19:54

    asolntsev on gh-pages

    fix typo (compare)

  • Oct 02 09:41

    asolntsev on gh-pages

    fix typos (compare)

  • Sep 28 06:08

    asolntsev on gh-pages

    publish Selenide 5.15.0 release… (compare)

  • Sep 28 05:20

    asolntsev on gh-pages

    released Selenide 5.15.0 (compare)

  • Sep 27 21:26

    asolntsev on gh-pages

    publish Selenide 5.15.0 release… (compare)

  • Aug 22 15:36

    asolntsev on gh-pages

    Released Selenid 5.14.2 (compare)

  • Aug 19 10:50

    asolntsev on gh-pages

    fix typo (compare)

  • Aug 19 07:40

    asolntsev on gh-pages

    publish Selenide 5.14.0 release… (compare)

  • Aug 18 22:06

    asolntsev on gh-pages

    publish Selenide 5.14.0 release… (compare)

  • Aug 16 21:18

    asolntsev on gh-pages

    released Selenide 5.14.0 (compare)

  • Aug 08 08:55

    asolntsev on gh-pages

    update gems (there was found a … bump Selenide version to 5.13.1 (compare)

  • Jul 09 12:55

    asolntsev on gh-pages

    add selenide downloads statisti… (compare)

  • Jul 09 07:36

    asolntsev on gh-pages

    fix typos (compare)

  • Jul 08 22:56

    asolntsev on gh-pages

    publish Selenide 5.13.0 release… (compare)

  • Jul 07 22:35

    asolntsev on gh-pages

    fix links to sources in Selenid… (compare)

  • Jun 15 12:44

    asolntsev on gh-pages

    update github links on site (compare)

  • Jun 15 09:07

    asolntsev on gh-pages

    fix link to tests (compare)

  • May 29 21:12

    asolntsev on gh-pages

    publish Selenide 5.12.2 release… (compare)

  • May 25 13:53

    asolntsev on gh-pages

    publish release notes for Selen… (compare)

  • May 25 12:53

    asolntsev on gh-pages

    publish release notes for Selen… (compare)

velios
@velios

@velios А ты в курсе, что WebElement очень просто легко превратить в SelenideElement? Это ведь решит твою проблему, так?

SelenideElement se = $(webElement);

Да, решает, теперь кажется странным почему прямой cast типов не работает в лямбде как я это ожидаю...

Вот рабочий пример

trs.shouldBe(allMatch("all value same in column",
                    el -> {
                        SelenideElement se = $(el);
                        return se.findAll("td").get(finalI).has(text(cellValue));
                    }));

вот как кажется его можно было бы упростить, но почему-то так не работает

trs.shouldBe(allMatch("all value same in column",
                    el -> (SelenideElement) el.findAll("td").get(finalI).has(text(cellValue))));
Andrei Solntsev
@asolntsev

Возможно, стоит добавить сюда https://github.com/selenide-examples/testcontainers пример с прокси, чтобы мои страдания не пропали даром?

Да, хорошая идея, попробую добавить.

вот как кажется его можно было бы упростить, но почему-то так не работает

Нет, так нельзя. Ты пытаешься закастить WebElement el к типу SelenideElement, а он же не такого типа.

Denis Gaievskyi
@dengayevskiy-sb
@asolntsev я могу сделать пулл реквест туда по горячим следам
Andrei Solntsev
@asolntsev
Давай! Супер.
Denis Gaievskyi
@dengayevskiy-sb
velios
@velios
Простите за глупый вопрос, как внутри shouldHave проверить что элемент имеет определенный тэг? .shouldHave(attribute("tag", "input")) не срабатывает =(
Andrei Solntsev
@asolntsev
@velios Похоже, такого условия сейчас нет. Прикинь. :)
Надо добавить что-то типа $.shouldHave(tagName(“h1”)).
@velios Но вообще-то это неспроста, что никто этого не просил раньше. Вообще-то это странноватая проверка. Кому какая разница, какой там тэг? Важно, какой текст, визибилити и т.д. - всё, что видид юзер.
Oleksii Cherevatyi
@JustAlexOne
Докину ещё в топку насчёт тега. Название тега может быть просто частью локатора, и тем самым и проверится сам тег
Andrei Solntsev
@asolntsev
Ну да, обычно так и происходит.
velios
@velios

@velios Но вообще-то это неспроста, что никто этого не просил раньше. Вообще-то это странноватая проверка. Кому какая разница, какой там тэг? Важно, какой текст, визибилити и т.д. - всё, что видид юзер.

Такая потребность, потому что тестирую Spa и стандартный setValue не работает, сделал кастомный, ну и хочется обложить его проверками, что юзер не попробует применить его ни к чему кроме input или textarea, отсюда потребность

Сам кастомный код выглядит так

public static Command<SelenideElement> setValue(String value) {
        return (element, locator, args) -> {
            String jsCode = "return (function(webelement,text){if(webelement.getAttribute('readonly')!=undefined)return'Cannot change value of readonly element';if(webelement.getAttribute('disabled')!=undefined)return'Cannot change value of disabled element';if(typeof window.setNativeValue!=='function'){window.setNativeValue=function setNativeValue(element,value){const valueSetter=Object.getOwnPropertyDescriptor(element,'value').set;const prototype=Object.getPrototypeOf(element);const prototypeValueSetter=Object.getOwnPropertyDescriptor(prototype,'value').set;if(valueSetter&&valueSetter!==prototypeValueSetter){prototypeValueSetter.call(element,value);}else{valueSetter.call(element,value);}}} setNativeValue(webelement,text);webelement.dispatchEvent(new Event('input',{bubbles:true}));webelement.focus();var maxlength=webelement.getAttribute('maxlength')==null?-1:parseInt(webelement.getAttribute('maxlength'));webelement.value=maxlength==-1?text:text.length<=maxlength?text:text.substring(0,maxlength);return null;})(arguments[0],arguments[1]);";
            String error = Selenide.executeJavaScript(jsCode, element, value);
            if (error != null) {
                throw new IllegalArgumentException(error);
            }
            Selenide.executeJavaScript("arguments[0].blur();", element);

            element.shouldHave(value(value).because("это значение, которое заполняли"));

            return element;
        };
    }

Половина кода вытянута из стандартной реализации в Selenide разумеется

Мне хочется дополнить условием

element.shouldHave(or("input or textinput", tagName("input"), tagName("textarea")))

В данном варианте проверять через локатор не вариант

velios
@velios

@velios Похоже, такого условия сейчас нет. Прикинь. :)
Надо добавить что-то типа $.shouldHave(tagName(“h1”)).

Думаю раньше много чего не просили, пока не появился execute. Эта штука gamechanger, то что раньше реализовывать казалось надуманным, теперь имеет смысл

velios
@velios
Я пытался Kotlin в проект затащить, ради ClassExtensions, так мне не хватало execute =)
velios
@velios
В данном чате же много практиков Selenide. Многие стали использовать execute, как он появился? У меня это одна из самых частых теперь комманд. Рассматривали возможность ввести для нее короткий alias? e - например
Andrei Solntsev
@asolntsev
@velios Хм… Всё это очень интересно… :)
game changer? Кто бы мог подумать…
нет, я в своих проектах до сих пор не использовал execute.
velios
@velios

У нас проект переехал на автогенераторы классов, решал вопрос таким образом

public static Command<SelenideElement> findClassBegins(String classPart) {
        return (element, locator, args) -> element.find("[class^='" + classPart + "']");
    }

    public static Command<SelenideElement> findClassEnds(String classPart) {
        return (element, locator, args) -> element.find("[class$='" + classPart + "']");
    }

    public static Command<SelenideElement> findClassContains(String classPart) {
        return (element, locator, args) -> element.find("[class*='" + classPart + "']");
    }

    public static Command<SelenideElement> findIdBegins(String idPart) {
        return (element, locator, args) -> element.find("[id^='" + idPart + "']");
    }

    public static Command<SelenideElement> findIdEnds(String idPart) {
        return (element, locator, args) -> element.find("[id$='" + idPart + "']");
    }

    public static Command<SelenideElement> findidContains(String idPart) {
        return (element, locator, args) -> element.find("[id*='" + idPart + "']");
    }

Или проверку кастомной таблицы у которой записи могут не сразу появиться

public static Command<SelenideElement> ensureHaveSize(int size) {
        return (element, locator, args) -> {
            ElementsCollection trs = element.findAll("tr");
            if (size == 0) {
                trs.first().find("td.no-data").shouldBe(visible);
            } else if (size > 0) {
                Awaitility.with().pollInSameThread().await("Таблица отрисовала записи").atMost(20, SECONDS).until(() ->
                        (trs.first().find("td.no-data").is(not(visible).because("Ожидается колчество записей больше 0")) &&
                                trs.size() == size));
            } else {
                throw new IllegalArgumentException("Введено некоректное число {" + size + "} для проверки количества записей в grid'е");
            }
            return element;
        };
    }

Даже удивлен, что еще не приходилось использовать в своих проектах

Boris Osipov
@BorisOsipov
Awaitility.with().pollInSameThread() :D
Баранцев бы потролил за это нас
    public static Command<SelenideElement> findIdEnds(String idPart) {
        return (element, locator, args) -> element.find("[id$='" + idPart + "']");
    }
а как выглядит ипользование этого в коде?
velios
@velios

Например так

SelenideElement sortModal = root.execute(findIdEnds("_main-table-sort-modal"));

Шанс запутаться меньше чем в случае

SelenideElement sortModal = root.find("[id$='_main-table-sort-modal']"));

Awaitility.with().pollInSameThread() :D

Я возможно что-то не так делаю. А возможно testng не лучший выбор, но без этого многопоточность не работает =(

Boris Osipov
@BorisOsipov

а зачем было городить это все вот так.
кажется, что проще было бы

    public static By idEnds(String idPart) {
        return By.css"[id$='" + idPart + "']";
    }

и потом

SelenideElement sortModal = root.$(idEnds("_main-table-sort-modal"));

??

velios
@velios
Да, так гораздо круче и универсальнее, спасибо, пойду перепишу =)
velios
@velios
Какие селекторы предпочтительнее использовать? byId-style или By.id-style ? Для чего их вообще два набора?
Andrei Solntsev
@asolntsev
@velios Да особо незачем. По мне так, селениумовский By.id ок.
  1. Но один чел делал порт селенида на .NET, и он говорил, что By создавал ему какие-то проблемы, и попросил добавил аналогичные методы Selectors.byId и т.д.
  2. И был ещё такой аргумент, что новичку сложнее учить и селенид, и селением, поэтому лучше, чтобы все эти методы были в селениде.
На мой взгляд, оба аргумента стрёмные, но я тогда поддался. :)
@velios Твой ensureHaveSize - это ведь по сути не команда (Command), а проверка (Condition).
Её бы лучше переделать на $(…).shouldHave(mySize(5))
И Awaitility.with там нужно, потому что селенид и так ведь умеет ждать. Вместо него достаточно просто написать trs.first().find("td.no-data”).shouldNotBe(visible) и trs.shoudHave(size(size)).
velios
@velios
Возможно ли внутри ElementsCondition.findBy и .FilterBy использовать лямбды для поиска хитровложенных элементов?
velios
@velios

@asolntsev Недавно упоминали возможность метода execute для EllementCollection, мог бы пригодиться чтобы переписать такой блок во что-нибудь приличное, например trs.execute(firstNotEmptyCell(int columnIndex))

Сейчас в коде делаю это так

// Берем текст из первой не пустой ячейки в соответствующем столбце
            int finalI = i;
            SelenideElement cell =
                    trs
                            .stream()
                            .filter(tr -> tr.findAll("td").get(finalI)
                                    .has(and("Первая заполненная ячейка", not(empty), not(text(EMPTY_NAME)))))
                            .findFirst()
                            .orElseThrow(() -> new IllegalArgumentException("Столбец не содержит ни одной заполнненой ячейки"))
                            .findAll("td")
                            .get(i);

trs - это EllementsCollection из <tr> элементов

Думал изначально для этого использовать filterBy или findBy, но туда нельзя передать лямбду

velios
@velios

Еще execute для EllementCollection был бы крут, чтобы реализовать аналог функции map из функциональных языков. Например, чтобы вернуть все ячейки первой колонки можно было бы использовать

trs.execute(map(tr -> tr.findAll("td").get(i)))
// В результате бы получился список из ячеек
    .findBy(text(text))
    .getText();

Сейчас как такие задачи "правильно решать" без steam() ?

Andrei Solntsev
@asolntsev
Что-то я запутался в этих лямбдах. Реально сложно. :(
Я бы вообще искал нужный элемент сразу одним XPath’ом. Пусть он и получится, может, сложноватыми (хотя не факт), но зато быстро и надёжно.
А все эти хождения по стримам могут быть просто медленными, если элементов много.
rabidka
@rabidka
Доброго времени суток. А ни у кого нет проблем с WDM? Selenide 5.9, chrome 84, автоматом качает 81 драйвер, он не работает с 84. Если явно задать 83 - работает.
Andrei Solntsev
@asolntsev
У всех есть :))
мне помогла такая команда: rm -fr ~/.m2/repository/webdriver/resolution.properties
Я завёл багу в WDM: bonigarcia/webdrivermanager#483
Andrei Solntsev
@asolntsev

Вышла Selenide 5.13.0: "Вначале была подстрока”

https://ru.selenide.org/2020/07/08/selenide-5.13.0/

Andrei Solntsev
@asolntsev

Мы зарелизили Selenide 5.14.0: “Стабильный FOLDER”

https://ru.selenide.org/2020/08/17/selenide-5.14.0/

Zychkov
@Zychkov
Всем привет! Столкнулся со следующей проблемой - перестали запускаться тесты, падают с ошибкой org.openqa.selenium.SessionNotCreatedException: session not created: This version of ChromeDriver only supports Chrome version 85. Причем данная ошибка возникает вне зависимости от того, какой параметр Configuration.browser в Before задан. Т.е. задаю Configuration.browser="firefox", но тесты падают с вышеуказанной ошибкой. Пробовал добавлять System.setProperty("webdriver.chrome.driver", "path/to/chromedriver"), но при запуске через gradle ошибка остается. Пробовал обновил версию selenide - без изменений. Фрейм cucumber + selenide + junit. Может кто сталкивался с подобной ошибкой?
Andrei Solntsev
@asolntsev
Конечно. Наверняка кукумбер пытается открыть браузер ДО того, как ты проставляешь browser="Firefox".
Andrei Solntsev
@asolntsev
Доброе утро!

Мы выпустили Selenide 5.15.0: "Обкликайся и обкачайся!"

https://t.co/a4Fjj0udWB

Dmitry Munda
@dimkin-eu

Доклад “Flaky tests. Метод” - для опытных

это повтор будет или новые бонусы из тестов ? :)

Andrei Solntsev
@asolntsev
Смотря чего повтор :)