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

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

Меня всегда удивлял на собеседованиях вопрос: “а у вас в тестах есть 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("Спасибо, братан, файл загружен"));

Тут есть разные школы. Одни говорят, что метод должен быть void. Другие говорят, что у пэджобжекта должно быть несколько “upload” методов, которые возвращают разные страницы.

1 лайк

Мне проще сделать void и далее уже по скрипту понять, на какую страницу оно выведет и сделать new ThatNewPage(); чем плодить кучу методов со специфическим return value;

К сожалению, текст “Спасибо, братан, файл загружен” каждый раз разный, и зависит от того, какой документ грузим.
Мне же нужен универсальный метод на загрузку, не зависящий от содержимого загружаемого документа.
Именно sleep(2000); помог, т.к. я предполагаю, что для тяжелых файлов (от 5Mb и более) скрипт просто не успевает зааплоадить его. Запрос не успевает отослаться. Не знаю как еще объяснить…

Как раз таки один раз подумав какой return page тебе необходимо сделать, позволит тебе сделать цепочку вызовов через точку и даже думать не придеться, на какой ты странице - вот в этом и фишка. Такой способ позволяет реализовать kiss, и паттерн chain of invocation

У меня цепочки вызовов в другом месте реализованы. Я в курсе про это.