Ожидание элемента в selenide, возвращающее boolean

Использую selenide + java.

Нужен совет (бестпрактис), как реализовать ожидание элемента с результатом boolean в селениде?

текущий вариант

  1. implicitlyWait(2000)
  2. exists()
  3. implicitlyWait(0)

Может есть более красивое решение?

не знаю как в селениде но на чистом селениуме
implicitly 0
explicitylywait for exists 2000
implicitly default

Это какой-то ахтунг…

Что вам вообще надо? Что вы хотит сделать? Какую проблему решаете?

Вот так надо написать, и никаких ожиданий не надо прописывать:
$("div").should(exist);

3 лайка

Да, сомнительно, по этому и тема создана.
Бывает что нужно проверить есть ли элемент, который появляется с задержкой. Только в случае отсутствия элемента возвращается false, а не эксепшен(not found).
Например информационное окно, которое не влияет на логику, но блокирует выполнение. Если оно появилось, то его нужно закрыть. Что то типо verify.

трай кетч пробовали?
try {
wait for element
return true
}
catch(NotFoudnException e){
return false;
}

угу, но селенид поймает исключение первым и тест завершится, т.е завершится на шаге wait for element.
Для селениума красивое решение(ваш вариант), есть еще вариант через коллекцию элементов, если кол-во равно нулю, то элемента нет.
Просто у селенида методы проверки состояния элемента сделаны через (assert) и при NotFoudnException тест завершает…

Это невозможно, гуглите про стек вызовов
Вот так никуда эксепшн не улетит:

public boolean isVisible() {
    try {
        $("div").should(exist);
        return true
    } catch (error) {
        return false
    }
}

Давайте разберем на примере

public boolean isVisible() {
    try {
        $("div").should(exist);
        return true
    } catch (error) {
        return false
    }
}

Если элемент не найден в строке “$(“div”).should(exist);” то по истечении 4х секунд, тест завершиться ошибкой элемент не найден. Т.е. мы не попадем в блок catch, так как тест дальше не выполняется.
Разве не так?

.shoud бросает исключение про прошествии 4 секунд.

Мы ловим это исключение и останавливаем движение эксепшена по стеку. А вместо делаем обычный (не аварийный) выход из функции

https://en.wikibooks.org/wiki/Java_Programming/Throwing_and_Catching_Exceptions

Насколько я разобрался в selenide то метод $(getElemet) где то дальше вызывает метод
public Object invoke(Object proxy, Method method, Object... args)
где proxy уже содержит исключение, а дальше в теле метода идет обработка этого исключения.

т.е. в примере isVisible исключение уже отловлено и обработано в методе $. и как бы тест завершен уже…)
Разве не так?

Если кто знает как через селенид красиво определять существует ли элемент, только что бы проверка была не ключевая, а информационная и не влияла на ход теста. [quote=“asolntsev, post:3, topic:19650, full:true”]
$(“div”).should(exist);
[/quote]
В данном случае, если элемента нет, то тест будет завершен, а нужно что бы продолжился…

старался понятно объяснить, если что сорян

Любопытная тема обсуждается :slight_smile:

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

Делаю в модуле utils пару функций:

  • waitFor - принимает функцию и время ожидания, возвращает true если функция вернула truly в течение таймаута, false если таймаут истек, a функция так и не вернула truly;
  • waitDuring - принимает функцию и время ожидания, возвращает true если функция постоянно возвращает truly в течение таймаута, false если в течение таймата был возвращен falsy, используется гораздо реже.

А для селениум-объектов создаются методы:

  • isExist - возвращает true если объект существует в виде DOM-объекта (но может быть и не видимый), false если не существует.
  • isVisible - возвращает true если объект существует и видимый на экране (полностью или частично - можно указать в виде параметра функции), false если не существует или не видимый.
    И на базе их, н-р так:
waitForExist = function (timeout=30) {
    var result = utils.waitFor(() => this.isExist(), timeout);
    if (!result) {
        throw new Error(`Element ${this.selector} doesn't exist after ${timeout}`);
    }
}

waitForNonExist = function (timeout=30) {
    var result = utils.waitFor(() => !this.isExist(), timeout);
    if (!result) {
        throw new Error(`Element ${this.selector} still exists after ${timeout}`);
    }
}

waitForVisible = function (timeout=30) {
    var result = utils.waitFor(() => this.isVisible(), timeout);
    if (!result) {
        throw new Error(`Element ${this.selector} isn't visible after ${timeout}`);
    }
}

waitForInvisible = function (timeout=30) {
    var result = utils.waitFor(() => !this.isVisible(), timeout);
    if (!result) {
        throw new Error(`Element ${this.selector} is still visible after ${timeout}`);
    }
}

Тогда если нужно подождать появления или бросить исключение, то используется функция waitForVisible.
А если более низкоуровневое типа подождать и вернуть true/false то utils.waitFor(() => element.isVisible(), /* timeout */ 30)

Ну и конечно есть свой матчер waitFor для chaijs, н-р так:

expect(() => page.table.getRows()).to.waitFor({ "be equal": 5 });
1 лайк

Вот в этом весть ахтунг!
Так чего же вы вообще хотите?

  1. Если элемент есть - чтобы тест продолжался.
  2. Если элемента нет - чтобы тест продолжался.

Зачем вообще тогда проверять элемент, если тест в обоих случаях продолжается?

2 лайка

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

Какой софт, такие тесты :slight_smile: Видимо компания “Ломаем моторы” решила, что хватит делать ручное тестирование, пора внедрять трендовую автоматизацию, но вот не учли, что автоматизация магически сбоку не прилипнет, и нужно менять процессы. А то так и будут тесты на костылях.

2 лайка

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

2 лайка

Конечно же, это возможно. Не верите мне - поверьте Билану.

Но ок, если предположить, что невозможно, то вот такой код закроет окно, если оно открылось:

if ($("#info").isDisplayed()) {
  $("#info-close").click();
}

Как видите, тут не нужны никакие ожидания.

2 лайка

Может я что то не догоняю, но какой то бег по кругу…
окно появляется с задержкой
$("#info").isDisplayed() - метод без задержки. Очевидно что будут ситуации когда окно будет появляться позже отработки метода isDisplay(). Это будет работать если перед if поставить ожидание - sleep ()… Но суть темы, в том что бы не было этого.

Может вот так попробовать:
if ($("#info").waitUntil(visible, 4000).isDisplayed()) {
$("#info-close").click();
}

Да, это бег по кругу, потому что тут нет хорошего решения. Если окно может появиться с задержкой, вы просто обязаны сделать sleep, причём максимально возможный. И это в любом случае будет плохо. Нет никакой магии, которая решила бы эту проблему за вас.

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

3 лайка

Два чаю этому господину. Я бы тоже разобрался с приложением вместо разбирательств с тестами.

1 лайк