Как выбрать опцию в выпадающих тестах protractorjs e2e

Я пытаюсь выбрать вариант из выпадающего списка для угловых испытаний e2e с использованием транспортира.

Вот фрагмент кода опции выбора:

<select id="locregion" class="create_select ng-pristine ng-invalid ng-invalid-required" required="" ng-disabled="organization.id !== undefined" ng-options="o.id as o.name for o in organizations" ng-model="organization.parent_id">
    <option value="?" selected="selected"></option>
    <option value="0">Ranjans Mobile Testing</option>
    <option value="1">BeaverBox Testing</option>
    <option value="2">BadgerBox</option>
    <option value="3">CritterCase</option>
    <option value="4">BoxLox</option>
    <option value="5">BooBoBum</option>
</select>

Я пытался:

ptor.findElement(protractor.By.css('select option:1')).click();

Это дает мне следующую ошибку:

Указана неверная или недопустимая строка. Информация о сборке: версия: '2.35.0', версия: 'c916b9d', время: '2013-08-12 15:42:01' Информация о системе: os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.9', java.version: '1.6.0_65'Информация о драйвере: driver.version: неизвестно

Я также попробовал:

ptor.findElement(protractor.By.xpath('/html/body/div[2]/div/div[4]/div/div/div/div[3]/ng-include/div/div[2]/div/div/organization-form/form/div[2]/select/option[3]')).click();

Это дает мне следующую ошибку:

ElementNotVisibleError: Элемент в данный момент не виден и поэтому может не взаимодействовать с длительностью или временем ожидания команды: 9 миллисекунд. Информация о сборке: версия: '2.35.0', версия: 'c916b9d', время: '2013-08-12 15:42: 01 'Системная информация: os.name:' Mac OS X ', os.arch:' x86_64 ', os.version: '10.9', java.version: '1.6.0_65' Идентификатор сеанса: bdeb8088-d8ad-0f49-aad9-82201c45c63f Информация о драйвере: org.openqa.selenium.firefox.FirefoxDriver Возможности [{platform=MAC, acceptSslCerts=true, javascriptEnabled=true, browserName=firefox, rotatable=false, locationContextEnabled=true, версия =24.0, база данных =24.0, css =true, handlesAlerts=true, browserConnectionEnabled=true, nativeEvents=false, webStorageEnabled=true, applicationCacheEnabled=false, takeScreenshot=true}]

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

34 ответа

Решение

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

В конце концов я решил, что у меня все в порядке, выбирая номер опции, и поэтому написал метод, который берет элемент и optionNumber и выбирает этот optionNumber. Если параметр optionNumber равен нулю, он ничего не выбирает (оставляя невыбранным выпадающее меню).

var selectDropdownbyNum = function ( element, optionNum ) {
  if (optionNum){
    var options = element.all(by.tagName('option'))   
      .then(function(options){
        options[optionNum].click();
      });
  }
};

Я написал пост в блоге, если вы хотите получить более подробную информацию, он также включает проверку текста выбранного параметра в раскрывающемся списке: http://technpol.wordpress.com/2013/12/01/protractor-and-dropdowns-validation/

For me worked like a charm

element(by.cssContainingText('option', 'BeaverBox Testing')).click();

Надеюсь, поможет.

Элегантный подход включал бы создание абстракции, аналогичной тому, что предлагают другие привязки языка селена из коробки (например, Select класс в Python или Java).

Давайте сделаем удобную оболочку и скроем детали реализации внутри:

var SelectWrapper = function(selector) {
    this.webElement = element(selector);
};
SelectWrapper.prototype.getOptions = function() {
    return this.webElement.all(by.tagName('option'));
};
SelectWrapper.prototype.getSelectedOptions = function() {
    return this.webElement.all(by.css('option[selected="selected"]'));
};
SelectWrapper.prototype.selectByValue = function(value) {
    return this.webElement.all(by.css('option[value="' + value + '"]')).click();
};
SelectWrapper.prototype.selectByPartialText = function(text) {
    return this.webElement.all(by.cssContainingText('option', text)).click();   
};
SelectWrapper.prototype.selectByText = function(text) {
    return this.webElement.all(by.xpath('option[.="' + text + '"]')).click();   
};

module.exports = SelectWrapper;

Пример использования (обратите внимание, насколько он читаем и прост в использовании):

var SelectWrapper  = require('select-wrapper');
var mySelect = new SelectWrapper(by.id('locregion'));

# select an option by value
mySelect.selectByValue('4');

# select by visible text
mySelect.selectByText('BoxLox');

Решение взято из следующей темы: Выберите -> опция абстракция.


К вашему сведению, создан запрос объекта: выберите -> опция абстракция.

element(by.model('parent_id')).sendKeys('BKN01');

Для доступа к определенной опции вам нужно предоставить селектор nth-child():

ptor.findElement(protractor.By.css('select option:nth-child(1)')).click();

Вот как я сделал свой выбор.

function switchType(typeName) {
     $('.dropdown').element(By.cssContainingText('option', typeName)).click();
};

Попробуйте это, это работает для меня:

element(by.model('formModel.client'))
    .all(by.tagName('option'))
    .get(120)
    .click();

Вот как я это сделал:

$('select').click();
$('select option=["' + optionInputFromFunction + '"]').click();
// This looks useless but it slows down the click event
// long enough to register a change in Angular.
browser.actions().mouseDown().mouseUp().perform();

Другой способ установить элемент option:

var select = element(by.model('organization.parent_id'));
select.$('[value="1"]').click();

Вы можете попробовать эту надежду, это сработает

element.all(by.id('locregion')).then(function(selectItem) {
  expect(selectItem[0].getText()).toEqual('Ranjans Mobile Testing')
  selectItem[0].click(); //will click on first item
  selectItem[3].click(); //will click on fourth item
});

Мы написали библиотеку, которая включает в себя 3 способа выбора варианта:

selectOption(option: ElementFinder |Locator | string, timeout?: number): Promise<void>

selectOptionByIndex(select: ElementFinder | Locator | string, index: number, timeout?: number): Promise<void>

selectOptionByText(select: ElementFinder | Locator | string, text: string, timeout?: number): Promise<void>

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

Вы можете найти его на npm https://www.npmjs.com/package/@hetznercloud/protractor-test-helper. Типы для TypeScript также предоставляются.

Чтобы выбрать элементы (варианты) с уникальными идентификаторами, как здесь:

<select
    ng-model="foo" 
    ng-options="bar as bar.title for bar in bars track by bar.id">
</select>

Я использую это:

element(by.css('[value="' + neededBarId+ '"]')).click();

Проблема состоит в том, что решения, которые работают с обычными угловыми полями выбора, не работают с угловым материалом md-select и md-option с использованием транспортира. Этот был опубликован другим, но он сработал для меня, и я пока не могу комментировать его сообщение (всего 23 повторения). Кроме того, я немного прибрался, вместо browser.sleep, я использовал browser.waitForAngular();

element.all(by.css('md-select')).each(function (eachElement, index) {
    eachElement.click();                    // select the <select>
    browser.waitForAngular();              // wait for the renderings to take effect
    element(by.css('md-option')).click();   // select the first md-option
    browser.waitForAngular();              // wait for the renderings to take effect
});

Если ни один из приведенных выше ответов не помог вам, попробуйте это

также работает с async / await

Для выбора вариантов по тексту

      let textOption = "option2"
await element(by.whichever('YOUR_DROPDOWN_SELECTOR'))
  .getWebElement()
  .findElement(by.xpath(`.//option[text()="${textOption}"]`))
  .click();

или по номеру

      let optionNumber = 2
await element(by.whichever('YOUR_DROPDOWN_SELECTOR'))
  .getWebElement()
  .findElement(by.xpath(`.//option[${optionNumber}]`))
  .click();

Конечно, вам может потребоваться изменить xpath дочерних параметров

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

Может быть, не супер элегантный, но эффективный:

function selectOption(modelSelector, index) {
    for (var i=0; i<index; i++){
        element(by.model(modelSelector)).sendKeys("\uE015");
    }
}

Это просто отправляет ключ вниз по желаемому выбору, в нашем случае мы используем modelSelector, но, очевидно, вы можете использовать любой другой селектор.

Тогда на моей странице объектная модель:

selectMyOption: function (optionNum) {
       selectOption('myOption', optionNum)
}

И из теста:

myPage.selectMyOption(1);

Помощник для установки элемента option:

selectDropDownByText:function(optionValue) {
            element(by.cssContainingText('option', optionValue)).click(); //optionValue: dropDownOption
        }

Пример ниже - самый простой способ. Я протестировал и прошел версию Protractor.5.4.2

//Drop down selection  using option's visibility text 

 element(by.model('currency')).element(by.css("[value='Dollar']")).click();
 Or use this, it   $ isshort form for  .By.css
  element(by.model('currency')).$('[value="Dollar"]').click();

//To select using index

var select = element(by.id('userSelect'));
select.$('[value="1"]').click(); // To select using the index .$ means a shortcut to .By.css

Полный код

describe('Protractor Demo App', function() {

  it('should have a title', function() {

     browser.driver.get('http://www.way2automation.com/angularjs-protractor/banking/#/');
    expect(browser.getTitle()).toEqual('Protractor practice website - Banking App');
    element(by.buttonText('Bank Manager Login')).click();
    element(by.buttonText('Open Account')).click();

    //Drop down selection  using option's visibility text 
  element(by.model('currency')).element(by.css("[value='Dollar']")).click();

    //This is a short form. $ in short form for  .By.css
    // element(by.model('currency')).$('[value="Dollar"]').click();

    //To select using index
    var select = element(by.id('userSelect'));
    select.$('[value="1"]').click(); // To select using the index .$ means a shortcut to .By.css
    element(by.buttonText("Process")).click();
    browser.sleep(7500);// wait in miliseconds
    browser.switchTo().alert().accept();

  });
});

Если ниже дан данный выпадающий

            <select ng-model="operator">
            <option value="name">Addition</option>
            <option value="age">Division</option>
            </select>

Тогда код protractorjs может быть

        var operators=element(by.model('operator'));
      operators.$('[value=Addition]').click();

Источник - https://github.com/angular/protractor/issues/600

Я немного улучшил решение, написанное PaulL. Прежде всего я исправил код, чтобы он был совместим с последним API-интерфейсом Protractor. И затем я объявляю функцию в разделе "onPrepare" конфигурационного файла Protractor как член экземпляра браузера, так что на нее можно ссылаться из любой спецификации e2e.

  onPrepare: function() {
    browser._selectDropdownbyNum = function (element, optionNum) {
      /* A helper function to select in a dropdown control an option
      * with specified number.
      */
      return element.all(by.tagName('option')).then(
        function(options) {
          options[optionNum].click();
        });
    };
  },

Существует проблема с выбором опций в Firefox, которую Хак Дрооганс исправляет, о которой я хочу упомянуть здесь в явном виде, надеясь, что это может спасти кого-то от неприятностей: https://github.com/angular/protractor/issues/480.

Даже если ваши тесты проходят локально с Firefox, вы можете обнаружить, что они терпят неудачу в CircleCI или TravisCI или любом другом, который вы используете для CI и развертывания. Осознание этой проблемы с самого начала сэкономило бы мне много времени:)

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

element (by.model ("ModelName")). click (). element (By.xpath ('местоположение xpath')).click();

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

Я потратил много времени на это решение, я надеюсь, что это поможет кому-то.

Выберите опцию по индексу:

var selectDropdownElement= element(by.id('select-dropdown'));
selectDropdownElement.all(by.tagName('option'))
      .then(function (options) {
          options[0].click();
      });

Самый простой способ выбрать вариант с использованием найденного мной индекса:

      var selectDropdownElement = await element(by.xpath("Some Xpath"));
                await selectDropdownElement.all(by.tagName('option')).then(function (options) {
                        options[index].click();
                });

'index' - это номер опции, которую вы хотите щелкнуть

Другой способ установить элемент option:

var setOption = function(optionToSelect) {

    var select = element(by.id('locregion'));
    select.click();
    select.all(by.tagName('option')).filter(function(elem, index) {
        return elem.getText().then(function(text) {
            return text === optionToSelect;
        });
    }).then(function(filteredElements){
        filteredElements[0].click();
    });
};

// using the function
setOption('BeaverBox Testing');
----------
element.all(by.id('locregion')).then(function(Item)
{
 // Item[x] = > // x is [0,1,2,3]element you want to click
  Item[0].click(); //first item

  Item[3].click();     // fourth item
  expect(Item[0].getText()).toEqual('Ranjans Mobile Testing')


});

Вы можете выбрать параметры раскрывающегося списка по значению:$('#locregion').$('[value="1"]').click();

static selectDropdownValue(dropDownLocator,dropDownListLocator,dropDownValue){
    let ListVal ='';
    WebLibraryUtils.getElement('xpath',dropDownLocator).click()
      WebLibraryUtils.getElements('xpath',dropDownListLocator).then(function(selectItem){
        if(selectItem.length>0)
        {
            for( let i =0;i<=selectItem.length;i++)
               {
                   if(selectItem[i]==dropDownValue)
                   {
                       console.log(selectItem[i])
                       selectItem[i].click();
                   }
               }            
        }

    })

}

Мы можем создать для этого собственный класс DropDown и добавить метод как:

async selectSingleValue(value: string) {
        await this.element.element(by.xpath('.//option[normalize-space(.)=\'' + value + '\']')).click();
    }

Кроме того, чтобы проверить, какое значение выбрано в данный момент, мы можем иметь:

async getSelectedValues() {
        return await this.element.$('option:checked').getText();
    }

Это простой однострочный ответ, в котором у angular есть специальный локатор, который может помочь выбрать и индексировать из списка.

element.all(by.options('o.id as o.name for o in organizations')).get(Index).click()

Вот как это сделать по значению опции или по индексу. Этот пример немного грубоват, но показывает, как сделать то, что вы хотите:

HTML:

<mat-form-field id="your-id">
    <mat-select>
        <mat-option [value]="1">1</mat-option>
        <mat-option [value]="2">2</mat-option>
    </mat-select>
</mat-form-field>

TS:

function selectOptionByOptionValue(selectFormFieldElementId, valueToFind) {

  const formField = element(by.id(selectFormFieldElementId));
  formField.click().then(() => {

    formField.element(by.tagName('mat-select'))
      .getAttribute('aria-owns').then((optionIdsString: string) => {
        const optionIds = optionIdsString.split(' ');    

        for (let optionId of optionIds) {
          const option = element(by.id(optionId));
          option.getText().then((text) => {
            if (text === valueToFind) {
              option.click();
            }
          });
        }
      });
  });
}

function selectOptionByOptionIndex(selectFormFieldElementId, index) {

  const formField = element(by.id(selectFormFieldElementId));
  formField.click().then(() => {

    formField.element(by.tagName('mat-select'))
      .getAttribute('aria-owns').then((optionIdsString: string) => {
        const optionIds = optionIdsString.split(' ');

        const optionId = optionIds[index];
        const option = element(by.id(optionId));
        option.click();
      });
  });
}

selectOptionByOptionValue('your-id', '1'); //selects first option
selectOptionByOptionIndex('your-id', 1); //selects second option
Другие вопросы по тегам