如何在ProtractorJS E2E测试中选择下拉选项

127

我正在尝试使用Protractor为Angular的端到端测试从下拉框中选择选项。

这是选择选项的代码片段:

<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'
会话ID:bdeb8088-d8ad-0f49-aad9-82201c45c63f
驱动程序信息:org.openqa.selenium.firefox.FirefoxDriver
功能 [{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,takesScreenshot=true}]


请问有谁能帮我解决这个问题或指点一下我在这里做错了什么。
34个回答

258

对我来说起了魔法的作用

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

2
小提示 - 仅适用于v0.22版本(我今天刚刚尝试替换我的代码,结果不得不升级才能使用) - PaulL
12
Christopher,ElementFinder 可以通过链式调用,因此您可以这样做:element(by.css('.specific-select')).element(by.cssContainingText('option', 'BeaverBox Testing')).click(); - Joel Kornbluh
7
注意,您可以获得部分匹配,因此 "Small" 将匹配 "Extra Small"。 - TrueWill
3
补充TrueWill的评论:这种解决方案的缺点是,如果您有两个类似的选项,它将使用最后找到的选项 - 这会基于错误选择而导致错误。对我有效的是https://dev59.com/wGIk5IYBdhLWcg3wFKlK#25333326 - user115014
使用这种方法,form.$pristine 的值没有被更新。对我来说,使用 sendKeys() 方法可以正常工作。 - David Casillas
显示剩余2条评论

90

我曾经遇到过类似的问题,最终编写了一个辅助函数来选择下拉列表中的值。

我最终决定通过选项编号进行选择,并编写了一个方法,该方法接受元素和选项编号,然后选择该选项编号。 如果选项编号为null,则不选择任何内容(使下拉列表保持未选择状态)。

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不是一个函数的错误。 - Justin
即使它能正常工作,但这段代码存在多个问题。1. 如果命令的输出总是未定义的,那么为什么要创建options变量并不清楚。2. 从elementArrayFinder中获取一个元素,最好(也更容易)使用.get()方法。3. 如果将一个元素传递给函数,那么element.all语句将无法工作。4. 现在最好使用异步函数。下面是一个例子 https://dev59.com/wGIk5IYBdhLWcg3wFKlK#66110526 - Sergey Pleshakov

32

一种优雅的方法是采用类似于其他Selenium语言绑定在开箱即用的抽象化方法(例如Python或Java中的Select类)。

让我们做一个方便的包装器,并将实现细节隐藏起来:

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


为什么在选择函数中使用'return'?这是必要的吗? - Michiel
1
@Michiel 很好的观点。如果您想显式解决 click() 返回的 Promise,这可能是必要的。谢谢。 - alecxe

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

1
这对我来说是最正确的。使用cssContainingText,您可以确保捕获所需的字段。只需想象一下如果您有两个具有相同值的selectbox。+1 - YoBre
4
抱歉,什么是BKN01? - ESP32
1
@Gerfried BKN01 是您想从下拉菜单中选择的文本。 - Milan Kumar
@GalBracha 抱歉,我没有听懂你的意思。 - Milan Kumar
如果您有另一个与BKN01相同前缀的选项,它将无法工作。将随机选择其中一个。 - zs2020
这在 Angular 2+ 应用程序中可能不起作用,因为 modelbinding 不可用。但是。 - javafueled

15

要访问特定的选项,您需要提供第 n 个子元素(nth-child())选择器:

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

这并没有回答问题。如果你想对作者提出批评或请求进一步解释,请在他们的帖子下方留言。 - jpw
@jpw是我的答案错了,还是我的回答方式有问题? - bekite
将答案表述为问题的形式是为什么。我不知道它是否正确。如果是正确答案,你应该这样表述。 - jpw
3
对我没有起作用。当我尝试了你的建议后,仍然出现“元素不可见”错误。 - Ranjan Bhambroo

8
这是我进行选择的方法。
function switchType(typeName) {
     $('.dropdown').element(By.cssContainingText('option', typeName)).click();
};

5

试试这个方法,我已经测试过了,可以正常工作:

element(by.model('formModel.client'))
    .all(by.tagName('option'))
    .get(120)
    .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完成挂起的处理,请使用Protractor的waitForAngular()方法。 - Avi Cherry

4

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

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

变量orderTest = element(by.model('ctrl.supplier.orderTest')) orderTest.$('[value="1"]').click();我得到了一个错误By(css选择器,[value="3"])。 - Anuj K.C.

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接