【问题标题】:How to select option in drop down protractorjs e2e tests如何在下拉 protractorjs e2e 测试中选择选项
【发布时间】:2013-11-05 03:20:03
【问题描述】:

我正在尝试从下拉列表中选择一个选项,以使用量角器进行角度 e2e 测试。

这里是select选项的代码sn-p:

<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 功能 [{platform=MAC,acceptSslCerts=true,javascript Enabled=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}]

谁能帮我解决这个问题,或者说明我在这里可能做错了什么。

【问题讨论】:

    标签: javascript angularjs selenium testing protractor


    【解决方案1】:

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

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

    【讨论】:

    • 次要注意 - 仅限 v0.22(我今天刚去用这个替换我的代码,并且必须升级才能获得它)
    • 有没有办法使用这个来定位元素?比如有重复的状态选择菜单。
    • Christopher, ElementFinder 是可链接的,所以你可以这样做:element(by.css('.specific-select')).element(by.cssContainingText('option', 'BeaverBox Testing')).click();
    • 请注意,您可以获得部分匹配,因此“Small”将匹配“Extra Small”。
    • 添加到 TrueWill 的评论中:此解决方案的缺点是,如果您有两个类似的选项,它将使用最后找到的选项 - 它会根据错误的选择引发错误。对我有用的是stackoverflow.com/a/25333326/1945990
    【解决方案2】:

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

    我最终决定我可以通过选项编号进行选择,因此编写了一个方法,该方法接受一个元素和 optionNumber,并选择该 optionNumber。如果 optionNumber 为 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/

    【讨论】:

    • 对我不起作用,得到 element.findElements 不是函数。
    • 即使有效,此代码也存在多个问题。 1. 如果命令的输出始终为undefined,则不清楚为什么要创建变量options。 2. 要从 elementArrayFinder 中获取一个元素,最好(也更容易)使用 .get() 方法。 3. 如果将元素传递给函数,那么element.all 语句将不起作用。 4.现在最好用async函数。这是一个例子stackoverflow.com/a/66110526/9150146
    【解决方案3】:

    一种优雅的方法将涉及进行抽象,类似于其他 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 好点。如果您想明确解决 click() 返回的承诺,则可能是必需的。谢谢。
    【解决方案4】:
    element(by.model('parent_id')).sendKeys('BKN01');
    

    【讨论】:

    • 这对我来说是最正确的。使用 cssContainingText 不是您确保捕获所需的字段。试想一下,如果您有 2 个具有相同值的选择框。 +1
    • 抱歉,BKN01 是什么?
    • @Gerfried BKN01 是您要从下拉列表中选择的文本。
    • @GalBracha 抱歉没听懂你
    • 如果您有另一个与 BKN01 共享相同前缀的选项,它将不起作用。将随机抽取一个。
    【解决方案5】:

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

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

    【讨论】:

    • 这没有提供问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论。
    • @jpw 我的回答错了。还是只是我的答案的表述是错误的?
    • 将答案表述为问题就是为什么。我不知道这是否是正确的答案。如果是,你应该这样表述。
    • @bekite 对我不起作用。当我尝试您的建议时,仍然收到错误 Element Not visible 错误
    【解决方案6】:

    这就是我的选择。

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

    【讨论】:

      【解决方案7】:

      我是这样做的:

      $('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() 方法。
      【解决方案8】:

      试试这个,它对我有用:

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

      【讨论】:

        【解决方案9】:

        你可以试试这个希望它会工作

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

        【讨论】:

          【解决方案10】:

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

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

          【讨论】:

          • var orderTest = element(by.model('ctrl.supplier.orderTest')) orderTest.$('[value="1"]').click();我收到错误 By(css selector, [value="3"])
          【解决方案11】:

          要选择具有唯一 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();
          

          【讨论】:

            【解决方案12】:

            我们编写了一个库,其中包含 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 的类型。

            【讨论】:

              【解决方案13】:

              也许不是很优雅,但很高效:

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

              【讨论】:

                【解决方案14】:

                问题在于,适用于常规角度选择框的解决方案不适用于使用量角器的 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
                });
                

                【讨论】:

                • 我只用这个: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(); } );
                【解决方案15】:

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

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

                【讨论】:

                  【解决方案16】:

                  帮助设置一个选项元素:

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

                  【讨论】:

                    【解决方案17】:

                    如果下面是给定的下拉菜单-

                                <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

                    【讨论】:

                      【解决方案18】:

                      按索引选择选项:

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

                      【讨论】:

                        【解决方案19】:

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

                        【讨论】:

                          【解决方案20】:

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

                          【讨论】:

                            【解决方案21】:

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

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

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

                            这个解决方案花了很多时间我希望这对某人有所帮助。

                            【讨论】:

                              【解决方案22】:

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

                              也适用于 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

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


                              更新

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

                              的值

                              【讨论】:

                                【解决方案23】:

                                我们想在上面使用 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 毫秒以确保我们不会因为仍在运行的材质效果而陷入麻烦。

                                【讨论】:

                                  【解决方案24】:

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

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

                                  【讨论】:

                                    【解决方案25】:
                                    ----------
                                    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')
                                    
                                    
                                    });
                                    

                                    【讨论】:

                                      【解决方案26】:

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

                                      【讨论】:

                                        【解决方案27】:

                                        这里是如何通过期权价值或指数来做到这一点。这个例子有点粗略,但它展示了如何做你想做的事:

                                        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
                                        

                                        【讨论】:

                                          【解决方案28】:
                                          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();
                                                             }
                                                         }            
                                                  }
                                          
                                              })
                                          
                                          }
                                          

                                          【讨论】:

                                            【解决方案29】:

                                            我们可以为此创建一个自定义的 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();
                                                }
                                            

                                            【讨论】:

                                              【解决方案30】:

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

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

                                              【讨论】:

                                              • 虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的答案以添加解释并说明适用的限制和假设。 From Review
                                              猜你喜欢
                                              • 2017-05-09
                                              • 1970-01-01
                                              • 1970-01-01
                                              • 1970-01-01
                                              • 1970-01-01
                                              • 1970-01-01
                                              • 1970-01-01
                                              • 2014-06-02
                                              • 1970-01-01
                                              相关资源
                                              最近更新 更多