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


121

Я пытаюсь выбрать вариант из раскрывающегося списка для тестов angular 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: unknown

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

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 Capabilities [{платформа = MAC, acceptSslCerts = true, javascriptEnabled = true, browserName = firefox, rotatable = false, locationContextEnabled = true, version = 24.0, cssnabledSelectors = true, handlesAlerts = true, browserConnectionEnabled = true, nativeEvents = false, webStorageEnabled = true, applicationCacheEnabled = false, playsScreenshot = true}]

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

Ответы:


88

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

В конце концов я решил, что могу выбирать по номеру опции, и поэтому написал метод, который принимает элемент и 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/


1
У меня не сработало, получил element.findElements - это не функция.
Джастин

251

Для меня сработало как шарм

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

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


2
Незначительное примечание - только v0.22 (я просто пошел заменить свой код этим сегодня, и мне пришлось обновить его, чтобы получить его)
PaulL

Есть ли способ нацеливания на элементы с помощью этого? Например, наличие дублированных меню выбора состояния.
Кристофер Маршалл

11
Кристофер, ElementFinderумеет element(by.css('.specific-select')).element(by.cssContainingText('option', 'BeaverBox Testing')).click();
цепляться

6
Обратите внимание, что вы можете получить частичные совпадения, поэтому «Маленький» будет соответствовать «Очень маленький».
TrueWill

3
Чтобы добавить к комментарию TrueWill: обратная сторона этого решения заключается в том, что если у вас есть два похожих варианта, он будет использовать последний найденный вариант, который вызывал ошибки из-за неправильного выбора. Что сработало для меня, так это stackoverflow.com/a/25333326/1945990
Майк В.

29

Элегантный подход предполагает создание абстракции, подобной тому, что другие привязки языка селена предлагают из коробки (например, 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');

Решение взято из следующей темы: Select -> option abstraction .


FYI, создал запрос функции: Select -> option abstraction .


Почему вы используете «возврат» в избранных функциях? Это необходимо?
Michiel

1
@Michiel хороший замечание. Может потребоваться, если вы хотите явно разрешить обещание, возвращаемое click(). Спасибо.
alecxe

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

1
Для меня это самый правильный вариант. Используя cssContainText, вы не убедитесь, что захватили нужное поле. Подумайте, есть ли у вас 2 окна выбора с одинаковыми значениями. +1
YoBre

4
Извините, что такое BKN01?
Герфрид

1
@Gerfried BKN01 - это текст, который вы хотите выбрать из раскрывающегося списка.
MilanYadav

@GalBracha Извини, что тебя не
понял

Если у вас есть другой вариант с тем же префиксом, что и BKN01, он не будет работать. Будет выбран случайный.
zs2020

15

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

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

Это не дает ответа на вопрос. Чтобы критиковать или запросить разъяснения у автора, оставьте комментарий под его сообщением.
jpw

@jpw - мой ответ неправильный. или это просто неправильная формулировка моего ответа?
bekite

Формулировка ответа в виде вопроса - почему. Не знаю, правильный ли это ответ. Если это так, вы должны сформулировать это как таковое.
jpw

3
@bekite Не сработало у меня. По-прежнему появляется ошибка Элемент Невидимая ошибка, когда я попробовал ваше предложение
Ранджан Бхамбру

8

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

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

5

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

$('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();

Чтобы дождаться, пока angular завершит отложенную обработку, используйте waitForAngular()метод транспортира.
Avi Cherry

5

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

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

4

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

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
});

4

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

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

var orderTest = element (by.model ('ctrl.supplier.orderTest')) orderTest. $ ('[value = "1"]'). click (); получаю ошибку Автор (селектор css, [value = "3"])
Anuj KC

3

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

<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();

3

Мы написали библиотеку, в которой есть 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 @ hetznercloud / protractor-test-helper . Также предусмотрены типы для TypeScript.


2

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

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);

2

Проблема в том, что решения, которые работают с обычными угловыми полями выбора, не работают с угловым материалом 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
});

Я просто использую это:element(by.model('selectModel')).click(); element(by.css('md-option[value="searchOptionValue"]')).click();
Луан Нгуен

Вот еще один подход: mdSelectElement.getAttribute('aria-owns').then( function(val) { let selectMenuContainer = element(by.id(val)); selectMenuContainer.element(by.css('md-option[value="foo"]')).click(); } );
gbruins

1

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

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


1

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

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

1

Если ниже приведен раскрывающийся список -

            <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


1

Выберите вариант по индексу:

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

1

Я немного улучшил решение, написанное PaulL. Прежде всего, я исправил код, чтобы он был совместим с последней версией Protractor API. А затем я объявляю функцию в разделе 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();
        });
    };
  },

1

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

element(by.model("ModelName")).click().element(By.xpath('xpathlocation')).click();

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

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


0

Мы хотели использовать элегантное решение с использованием материала angularjs, но оно не сработало, потому что на самом деле в DOM нет тегов option / md-option до тех пор, пока не будет нажата кнопка md-select. Так что "элегантный" способ не сработал для нас (обратите внимание на угловатый материал!) Вот что мы для него сделали, не знаю, лучший ли это способ, но теперь он определенно работает.

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

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


0

Другой способ установить элемент 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');

0
----------
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')


});

0

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


0

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

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

0
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();
                   }
               }            
        }

    })

}

0

Мы можем создать для этого собственный класс 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();
    }

0

Пример ниже - самый простой способ. Я протестировал и прошел версию 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();

  });
});

0

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

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

Хотя этот код может решить вопрос, в том числе объяснение того, как и почему это решает проблему, действительно поможет улучшить качество вашего сообщения и, вероятно, приведет к большему количеству голосов за. Помните, что вы отвечаете на вопрос для будущих читателей, а не только для человека, который задает его сейчас. Пожалуйста , измените свой ответ , чтобы добавить объяснения и дать указание о том , что применять ограничения и допущения. Из отзыва
двойной звуковой сигнал

-1

Выберите вариант по свойству CSS

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

или

element(by.css("#locregion")).element(by.css("[value='1']")).click();

Где locregion (id), organization.parent_id (имя модели) - это атрибуты элемента select.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.