125

我正在尝试从使用量角器的角度 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'会话ID:bdeb8088-d8ad-0f49-aad9 -82201c45c63f 驱动程序信息:org.openqa.selenium.firefox.FirefoxDriver Capabilities [{platform=MAC, acceptSslCerts=true, javascriptEnabled=true, browserName=firefox, rotatable=false, locationContextEnabled=true, version=24.0, cssSelectorsEnabled=true, databaseEnabled =true,handlesAlerts=true,browserConnectionEnabled=true,nativeEvents=false,webStorageEnabled=true,applicationCacheEnabled=false,takeScreenshot=true}]

任何人都可以帮我解决这个问题或阐明我在这里可能做错了什么。

4

33 回答 33

257

对我来说,工作就像一个魅力

element(by.cssContainingText('option', 'BeaverBox Testing')).click();
于 2014-06-17T08:47:49.760 回答
90

我遇到了类似的问题,最终写了一个帮助函数来选择下拉值。

我最终决定我可以通过选项编号进行选择,因此编写了一个采用元素和 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/

于 2013-12-01T03:05:10.503 回答
32

一种优雅的方法将涉及进行类似于其他 selenium 语言绑定提供的开箱即用的抽象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


仅供参考,创建了一个功能请求:Select -> option abstraction

于 2015-04-03T00:17:42.027 回答
22
element(by.model('parent_id')).sendKeys('BKN01');
于 2014-08-15T19:58:28.947 回答
15

要访问特定选项,您需要提供 nth-child() 选择器:

ptor.findElement(protractor.By.css('select option:nth-child(1)')).click();
于 2013-10-25T22:07:18.320 回答
8

这就是我的选择。

function switchType(typeName) {
     $('.dropdown').element(By.cssContainingText('option', typeName)).click();
};
于 2014-05-26T13:43:12.840 回答
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();
于 2014-04-29T16:24:45.790 回答
5

试试这个,它对我有用:

element(by.model('formModel.client'))
    .all(by.tagName('option'))
    .get(120)
    .click();
于 2015-04-13T09:17:50.623 回答
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
});
于 2014-03-09T12:41:59.547 回答
4

另一种设置选项元素的方法:

var select = element(by.model('organization.parent_id'));
select.$('[value="1"]').click();
于 2016-10-06T07:24:48.187 回答
3

要选择具有唯一 ID 的项目(选项),如下所示:

<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();
于 2015-05-19T13:59:36.133 回答
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 的类型。

于 2018-06-11T10:18:18.867 回答
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);
于 2014-03-27T05:09:50.327 回答
2

问题是适用于常规角度选择框的解决方案不适用于使用量角器的 Angular Material 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
});
于 2015-07-29T01:27:28.393 回答
1

在 Firefox 中选择选项存在问题,我想在这里明确提及Droogans 的 hack修复,希望它可以为某人省去一些麻烦:https ://github.com/angular/protractor/issues/480 。

即使您的测试在 Firefox 本地通过,您也可能会发现它们在 CircleCI 或 TravisCI 或您用于 CI&deployment 的任何东西上都失败了。从一开始就意识到这个问题会为我节省很多时间:)

于 2015-07-17T09:28:41.207 回答
1

我一直在网上寻找有关如何在模型下拉列表中选择选项的答案,并且我使用了这种组合,它帮助我使用了 Angular 材料。

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

似乎将代码全部放在一行中时,它可以在下拉列表中找到该元素。

花了很多时间来解决这个问题,我希望这对某人有所帮助。

于 2016-08-31T11:33:42.417 回答
1

设置选项元素的助手:

selectDropDownByText:function(optionValue) {
            element(by.cssContainingText('option', optionValue)).click(); //optionValue: dropDownOption
        }
于 2016-12-30T18:49:55.600 回答
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

于 2017-02-26T10:19:09.870 回答
1

按索引选择选项:

var selectDropdownElement= element(by.id('select-dropdown'));
selectDropdownElement.all(by.tagName('option'))
      .then(function (options) {
          options[0].click();
      });
于 2017-04-17T15:17:28.413 回答
1

我对 PaulL 编写的解决方案进行了一些改进。首先,我修复了与最后一个 Protractor API 兼容的代码。然后我在 Protractor 配置文件的“onPrepare”部分声明该函数作为浏览器实例的成员,因此可以从任何 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();
        });
    };
  },
于 2017-05-26T12:12:15.050 回答
1

下面的例子是最简单的方法。我已经测试并通过了量角器版本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();

  });
});
于 2019-12-08T13:03:38.877 回答
1

如果以上答案都不适合你,试试这个

也适用于异步/等待

用于按文本选择选项

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

不要问我为什么,但当我已经失去希望时,这是我可以自动化下拉列表的唯一方法


更新

实际上有一种情况,即使这种方法也不起作用。解决方法有点难看,但有效。我只需要选择两次值

于 2021-02-08T22:53:02.187 回答
0

我们想在那里使用 angularjs 材料的优雅解决方案,但它不起作用,因为在单击 md-select 之前,DOM 中实际上没有 option / md-option 标签。所以“优雅”的方式对我们不起作用(注意有棱角的材料!)这是我们为它所做的,不知道它是否是最好的方式,但它现在肯定有效

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 毫秒以确保我们不会因为仍在运行的材质效果而遇到麻烦。

于 2015-03-05T13:59:43.627 回答
0

另一种设置选项元素的方法:

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');
于 2015-05-22T17:18:07.270 回答
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')


});
于 2016-05-20T08:55:36.703 回答
0

您可以按值选择下拉选项: $('#locregion').$('[value="1"]').click();

于 2016-11-22T11:34:39.123 回答
0

以下是如何通过 option value 或 index 来做到这一点。这个例子有点粗略,但它展示了如何做你想做的事:

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
于 2018-08-27T09:52:14.590 回答
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();
                   }
               }            
        }

    })

}
于 2018-12-06T10:31:08.850 回答
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();
    }
于 2019-12-02T12:39:14.250 回答
0

这是一个简单的单行答案,其中 angular 具有特殊的定位器,可以帮助从列表中选择和索引。

element.all(by.options('o.id as o.name for o in organizations')).get(Index).click()
于 2020-06-02T16:16:41.447 回答
0

这适用于Angular 材质

element(by.css("mat-select[formcontrolname=myMatSelect]")).sendKeys(valueToSet);

如果您的选项中不存在“valueToSet”,则不应设置它。

于 2021-03-02T09:45:16.417 回答
-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(model name) 是 select 元素的属性。

于 2017-10-20T08:01:15.303 回答
-1

您可以选择这样的下拉选项:

element(by.xpath(
'//*[@id="locregion"]//option[contains(text(),"Ranjans Mobile Testing")]'
)).click();
于 2017-11-02T04:58:40.487 回答