Gradle > Как определить что элемент есть или нет?

Gradle + Selenide + Cucumber всё в Intelj Idea

имеется страница… обычно при переходе на неё есть данные (больше или меньше это не важно сейчас)… но так же случается ситуация когда данных нет и на странице висит “No results found”

дело в том, что если результатов много, то их загрузка (и как следствие ожидание появления) может затянуться, ввиду чего выставлен глобальный таймаут 20 сек…
в тоже время, если случается “No results found” - он происходит практически мгновенно.

вопрос: как проверить (не найти а именно узнать) есть объект на странице или нет?

попробовал закинуть в try/catch, но тут проблема:

если No results found - случилось - всё отлично - происходит ФейлСтеп и сценарий автоматом переходит на @After
но если значение НЕ появилось - происходит ошибка сценария - объект не найден.

была идея закинуть в If - но тут проблема как вернуть (например boolean) isShown = Y/N из кода вроде: $(By.xpath("//div[@class=‘classname’]")).shouldBe(visible);

Ответ тут: Как надругаться над Селенидом

спасибо за подсказку… но я решил старым добрым функциональным программированием…

if ($By.xpath…).exist()){
throw new InterruptedExection();
}
если объект есть - выкинуть эксепшин, который вернёт ФейледСтеп в лог… и продолжит исполнение @After + (если есть) прогняет следующий сценарий.

в противном случае продолжаем сценарий дальше…

если позволите ещё 1 вопрос, чтоб не создавать 100500 тем:

всё те же условия и всё та же страница…
в заголовке есть ряд input-ов + кнопка Apply

когда пишу код типа:

$(By.xpath(input#1…).sendKeys(“gfdgdfgsdfg”);
$(By.xpath(button…).click();

действие происходит настолько мгновенно, что система НЕ успевает “прочитать” установленный фильтр и просто применяет тот же самый что и установлен в текущий момент.

логика страницы: типа надо ввести значение + перевести фокус из поля…
на самом деле - если (руками) ввести значение и затем мышкой нажать кнопку - значение подхватывается… другими словами проблема именно в скорости исполнения команд.

вопрос: как заставить чуть медленнее переходить между действиями?
ставить Thread.sleep (или просто слип) - не хочется… даже вас “пожурили” на “Воркшоп (часть 1): Как начать свой проект автоматизации с нуля” - за использование слипов :smile:

Но вы же хотите именно подождать. Тупо подождать. Значит, слип. :slight_smile:

Вопрос в том, сколько именно надо ждать. Одну секунду? А если мало? Лучше две для надёжности?
Проблема слипа только в том, что в большинстве случаев он будет ждать больше, чем реально нужно. И поэтому вместо тупого слипа лучше прописать ожидание какого-то условия. Типа $.should(appear). Но для этого надо знать, чего именно ждать. Если не знаешь, чего ждать - остаётся только слип.

1 симпатия

спасибо… в моём случае - ничего ожидать не нужно, кроме факта что страница “скушала” введённое значение… и ни единого изменения, кроме самого факта появления значения в инпуте - нету…

а потому нужна просто пауза в исполнении след. шага в 1-1,5 секунд не более…

Не всегда есть это условие, поэтому да, только слип.

Меня всегда удивлял на собеседованиях вопрос: “а у вас в тестах есть Thread.sleep ?”
Да !
В моём проекте у меня их полно.
Мы не в идеальном мире живём, и невозможно сделать тест без слипов.
Банальный пример: идет выгрузка heavy-документа(upload *.doc документа на 5 Mb).
Селенидовский uploadFile просто может не успеть сделать запрос. Поэтому я в этих местах подстраховываюсь и делаю слип 2 секунды после вызова uploadFile.

1 симпатия

просто бытует мнение что использование слипов - это признак низкого уровня профессионализма…

я начинал “автоматизацию” (через AutoIT) всевозможных флеш-игрушек… и когда я заводил тему о слипах - меня выставляли неучем… на что я спрашивал: а ты пробовал автоматизировать флеш-игру без какого-либо доступа к коду (от слова вообще!) - и КАК ты отработаешь ивент например смены цвета объекта в некоторых условиях которые могут случится (и наверняка случатся) в произвольный момент

а никак… только дать паузу и проверить наличие цвета в координатах… и так н-цить раз (н - определяет сам авто скрипта)…

1 симпатия

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

но я решил старым добрым функциональным программированием…

Извиняюсь, но никаких признаков функционального программирования я не увидел. Классический императивный стиль.

ни единого изменения, кроме самого факта появления значения в инпуте - нету…

Если действительно нет, то стоит поднять вопрос о проблеме юзабилити. Как пользователь поймёт, что фильтр применился? Что, если пользователь успеет кликнуть до того, как фильтр применился? Скорее всего стоит кнопку дизайблить, пока фильтр “применяется”. Тогда и тест сможет ждать, пока кнопка снова заэнейблится.

Селенидовский uploadFile просто может не успеть сделать запрос

Стоп-стоп, вот этого примера я не понял. Может, можно показать код, хотя бы схематично?
Я себе представляю так: после вызова uploadFile на экране должно появиться какое-то сообщение типа “Спасибо, файл загружен”. Или где-то поменяться статус. Или загореться какая-то иконка. Ну хоть какое-то изменение должно быть. Иначе как пользователь поймёт, что файл загрузился?

Так вот этого изменения и надо ждать вместо тупого слипа.

функциональным - имелось ввиду - ловить if/else вместо - try/catch (что было бы профессиональнее)

про изменения - вы не поняли…
когда юзер ввёл в поле значение ДЛЯ поиска - на самой странице ничего не изменилось… только само поле заполненно значением… кнопка Apply - не изменила (динамически) цвет или др. параметр… приложение ооочень серьёзная биржевая программа… а потому любые новшества, даже если они весьма полезны, проходят ооочень нелегко…

на счёт того что “пользователь успеет нажать фильтр” - я автоматизирую приложение с которым работаю уже более 5лет… и у меня ну никак не получается столь же “резво” вбить поисковое значение + нажать кнопку Apply… а потому на 99% уверен что среди юзеров таких не найдётся…
ну а на тот 1% - это уже вопрос к разрабочикам - есть ли смысл писать “защиту” от человека-молнии…

История с полем странная. Такого не бывает, что “значение вбил”, но “оно ещё не применилось”.
Значение в <input> не грузится ниоткуда, оно сразу там, в поле. Оно не может “не примениться”.
Думаю, вам надо получше разобраться, что же там происходит.

там серия input-ов и пара drop-down (со значениями на выбор)
пользователь должен установить какой-либо фильтр + нажать кнопку Apply (без нажатия которой можете заполнить хоть ВСЕ поля - ничего не изменилось ЕЩЁ)
сам факт ввода того или иного значения не меняет сути страницы, от слова вообще.

и как говориться “as per design”… и тут даже обсуждать нечего :slight_smile:

если не затруднит - гляньте плз в тему " Gradle > как нажать линк в нужном вложенном повторяющемся классе" - уже который час пытаюсь решить вопрос

заранее спасибо.

Тогда я не понимаю, в чём проблема с этим кодом:

$(By.xpath(input#1…).sendKeys(“gfdgdfgsdfg”);
$(By.xpath(button…).click();

Вбиваешь значение в поле фильтра, жмякаешь кнопку - фильтр применяется. Что именно тут не работает?

уже описал выше: из-за того что действие практически мгновенное - то нажатие кнопки НЕ подхватывает введённый фильтр…
я соглашусь с вами, что это можно считать дефектом, но если я занесу его, меня спросят:
а сколько людей успеют такое провернуть? или в оригинале будет звучать как “i’m almost sure that this is not real world scenario”… и на дефект просто забьют

стоит поставить между этими шагами слип в 1,5 сек - и всё работает штатно.

Вот этого я и не понимаю: что значит “не подхватывает”? Значение в <input> - оно сразу в input, его никто ниоткуда не “подхватывает”. Если, конечно, у вас не используется вместо стандартного инпута какой-то хитрый самодельный компонент. Тогда с этим компонентом надо разбираться.

На вопрос “а сколько людей успеют такое провернуть?” всегда можно ответить, что это исправление нужно для ускорения/стабилизации тестов, а это положительно влияет на процесс релиза, скорость выкатки новых фич в продакшн и т.д. В этом заинтересована вся команда.

Я себе представляю так: после вызова uploadFile на экране должно появиться какое-то сообщение типа “Спасибо, файл загружен”. Или где-то поменяться статус. Или загореться какая-то иконка. Ну хоть какое-то изменение должно быть. Иначе как пользователь поймёт, что файл загрузился?

Так вот этого изменения и надо ждать вместо тупого слипа.

Конечно, после аплоада файла он отобразится на html морде и на это можно заматчиться, но
тут дело в другом - именно само время на аплоад тяжелого файла может просто не хватить.
Пример:

public void clickUploadMyTeamDocuments(File fileToUpload)
    {
        try
        {
            $(".js-upload-my-team-document-btn").parent().parent().find("input").waitUntil(Condition.visible, 7_000);
            $(".js-upload-my-team-document-btn").parent().parent().find("input").waitUntil(Condition.enabled, 7_000);

            SelenideElement uploadMyTeamDocumentsButton = $(".upload__body input[style='display: block; height: auto; visibility: visible;']");

            uploadMyTeamDocumentsButton.shouldBe(Condition.visible).shouldBe(Condition.enabled).uploadFile(fileToUpload);
            Thread.sleep(2_000); // this sleep after firing of uploadFile is necessary too
        }
        catch (InterruptedException e)
        {
            logger.error("InterruptedException", e);
        }
    }

Без нижнего слипа в 2 секунды этот метод становится flaky.

А вот это интересно. С какой именно ошибкой упадет тест без этого слипа?
Для меня очевидно, что этот слип никак не влияет на работу метода uploadFile, т.к. он вызывается после завершения uploadFile.

Если честно, аргумент что тут единственное спасение Thread.sleep - весьма неубедителен
Ты уверен, что до самого конца исследовал вопрос ожидания ?

  1. Вместо Thread.sleep ты можешь воспользоваться Selenide.sleep()
  2. shouldBe(Condition … condition) - это означает, что ты можешь писать вместо
    shouldBe(Condition.visible).shouldBe(Condition.enabled) → shouldBe(Condition.appears, Condition.enabled)
  3. Вопрос ожидания лучше бы обсудить с командой разработки, не факт, что они знают, но все же полезную инфу могут дать, которую можно исследовать
  • Может есть какой-то аттрибут в кнопке, который фиксирует, что файл еще грузиться или body элемент дома
  • Может есть какой-то ответ в Network на это событие
  • Может через js что-то можно словить
  • Можно продебажить страничку эту в браузере
  1. void метод - сделать бы по PageObject и чтобы метод возвращал текущую или след страницу

Ошибки не будет.
Документ просто не загрузится и всё. Ну и далее тест пойдет что-то там делать, а текста нет. => там уже повалятся ошибки.

  1. Вместо Thread.sleep ты можешь воспользоваться Selenide.sleep()

В чем отличие можешь рассказать ?

  1. shouldBe(Condition … condition) - это означает, что ты можешь писать вместо
    shouldBe(Condition.visible).shouldBe(Condition.enabled) → shouldBe(Condition.appears, Condition.enabled)

Знаю :slight_smile: Просто там не переписал.

  • Может есть какой-то аттрибут в кнопке, который фиксирует, что файл еще грузиться или body элемент дома

Ничего нет. Более того - это реактовская кнопка, которая скрывает свой input и нужны дополнительные пляски с css чтобы этот инпут отобразить непосредственно перед выгрузкой.

  1. void метод - сделать бы по PageObject и чтобы метод возвращал текущую или след страницу

Цимес в том, что возвратиться страничка может каждый раз разная , в зависимости от того, где делается этот upload. Я в курсе про page object :slight_smile:
Кстати говоря, как правильно архитектурно тогда решить этот вопрос ?

Тогда тем более непонятно, как тут слип может повлиять на работу uploadFile. Не может!

Замени

$.uploadFile();
sleep(2000);

На

$.uploadFile();
$(".message").shouldHave(text("Спасибо, братан, файл загружен"));