Nightwatchjs: как проверить, существует ли элемент без создания ошибки/сбоя/исключения

На странице, которую я тестирую, могут отображаться две кнопки: BASIC или ADVANCED.

Я хочу узнать, отображается ли кнопка ADVANCED - и если да, щелкните по ней.

Если отображается кнопка BASIC, я ничего не хочу делать и продолжу свой тест.

Все параметры Nightwatchjs, которые я экспериментировал, генерируют сообщение об ошибке. Например, если я "waitforpresent" или "waitforvisible", и кнопки там нет, он генерирует ошибку/сбой. Я просто хочу знать, какая кнопка присутствует, поэтому я могу принять решение в своем коде.

Вот что я пробовал:

try { 
    browser.isVisible('#advanced-search', function(result) {console.log(result.state); }) 
} catch (myError) 
{ 
    console.log(myError); 
}

Мысли?

Ответ 1

Вы можете достичь этого, используя элемент "Selenium protocol" и функцию обратного вызова, чтобы проверить статус результата, чтобы определить, был ли найден элемент, Например:

browser.element('css selector', '#advanced-search', function(result){
    if(result.status != -1){
        //Element exists, do something
    } else{
        //Element does not exist, do something else
    }
});

Ответ 2

Синтаксис может быть немного выключен. Не очень хорошо знаком с NightWatchJS. Однако концепция остается той же.

//I would not wait for a element that should not exist
//rather I would find the list of the element and see if the count is greater than 0
//and if so, we know the element exists
browser.findElements(webdriver.By.css('#advanced-search')).then(function(elements){
    if(elements.length> 0){
        console.log(elements.length);
    }
});

См. еще один пример здесь

Ответ 3

Кажется, вы на правильном пути с isVisible. Из документа nightwatch мы видим, что в обратном вызове вы можете проверить свойство result.value, чтобы увидеть, был ли этот элемент видимым, т.е.

browser.isVisible('#advanced-search', results => {
  if (results.value) { /* is visible */ }
  else { /* is not visible */ }
});

В качестве альтернативы вы можете использовать подход, предложенный Сайфуром. Вызовите команду selenium api .elements, а затем проверьте длину массива результатов:

browser.elements('css selector', '#advanced-search', results => {
  if (results.value.length > 0) { /* element exists */ }
  else { /* element does not exist */ }
});

Это фактически можно было бы обернуть в пользовательскую команду:

// isPresent.js
module.exports.command = function (selector, callback) {
  return this.elements('css selector', selector, results => {
    if (results.status !== 0) { // some error occurred, handle accordingly
    }

    callback(results.value.length > 0);
  });
};

то в нормальном коде вы можете называть его следующим образом:

browser.isPresent('#advanced-search', advancedSearchPresent => {
  // make decisions here
}

Если вы будете делать дополнительные вызовы api в обратном вызове, может быть разумным обернуть все это при вызове .perform:

browser.perform((_, done) => {
  browser.isPresent('#advanced-search', advancedSearchPresent => {

    // ...do more stuff...

    done();
  });
});

Что касается необходимости .perform, возможно, this.

Ответ 4

Моя команда использует одну функцию для аутентификации с помощью нескольких разных форм signin, и мы используем пользовательскую команду под названием ifElementExists для выполнения логики ветвления для понимания того, в какой форме мы находимся. Мы также используем это на нескольких других страницах, которые не имеют лучшего метода для определения текущего состояния.

import { CustomCommandShorthand } from './customCommands';
import { isFunction } from 'lodash';

exports.command = function ifElementExists(this: CustomCommandShorthand, selector: string, ifTrue: Function, ifFalse?: Function) {
    this.perform(() => {
        if (!isFunction(ifTrue)) {
            throw new Error(`The second argument must be callable. You passed a ${typeof ifTrue} instead of a function.`);
        }

        this.element('css selector', selector, function ifElementExistsCallback({ status }) {
            if (status !== -1) {
                return ifTrue();
            }

            if (isFunction(ifFalse)) {
                ifFalse();
            }
        });
    })
}