【问题标题】:How to test if an element has class using Protractor?如何使用量角器测试元素是否具有类?
【发布时间】:2013-12-14 14:37:41
【问题描述】:

我正在尝试使用 Protractor 对 Angular 应用程序进行 e2e 测试,但还没有弄清楚如何检测元素是否具有特定类。

在我的例子中,测试点击了提交按钮,现在我想知道 form[name="getoffer"] 是否有类 .ngDirty。有什么解决办法?

describe('Contact form', function() {
    beforeEach(function(){
        browser.get('http://localhost:9000');
        element(by.linkText('Contact me')).click();
    });

    it('should fail form validation, all fields pristine', function() {
        element(by.css('.form[name="getoffer"] input[type="submit"]')).click();
        expect(element(by.name('getoffer'))).toHaveClass('ngDirty'); // <-- This line
    });
});

【问题讨论】:

    标签: angularjs protractor


    【解决方案1】:

    你试过了吗?

    const el = element(by.name('getoffer'));
    expect(el.getAttribute('class')).toBe('ngDirty')
    

    或上述的变体......

    【讨论】:

    • 问题是,表单有不止一个类。
    【解决方案2】:

    如果您将 Protractor 与 Jasmine 一起使用,您可以使用 toMatch 作为正则表达式进行匹配...

    expect(element(by.name('getoffer')).getAttribute('class')).toMatch('ngDirty');
    

    另外,请注意toContain 将匹配列表项,如果您需要的话。

    【讨论】:

    • 我不确定这是否是理想的方法,但至少它可以按预期工作:)
    • 不,我会说可能不是。我希望element 返回一个带有hasClass 方法的对象,您可以将其包装在expect 调用中...
    • 在这种情况下,toContain 可能是比toMatch 更好的选择。
    • 如果你想防止部分匹配,试试/(^|\s)ngDirty($|\s)/
    • 你可能可以使用.not.toContain 来检查它是否没有特定的类或.toContain 来检查它是否存在
    【解决方案3】:

    使用toMatch() 时必须注意的一个问题是部分匹配,如已接受的答案所示。例如,假设您有一个可能具有类correctincorrect 的元素,并且您想测试它是否具有类correct。如果您要使用expect(element.getAttribute('class')).toMatch('correct'),即使元素具有incorrect 类,它也会返回true。

    我的建议:

    如果你只想接受完全匹配,你可以为它创建一个辅助方法:

    var hasClass = function (element, cls) {
        return element.getAttribute('class').then(function (classes) {
            return classes.split(' ').indexOf(cls) !== -1;
        });
    };
    

    您可以这样使用它(利用expect 自动解析 Protractor 中的承诺这一事实):

    expect(hasClass(element(by.name('getoffer')), 'ngDirty')).toBe(true);
    

    【讨论】:

    • 这对我有用,类名必须是连字符格式而不是驼峰式大小写,即expect(hasClass(element(by.name('getoffer')), 'ng-dirty')).toBe(true);
    • 我不太清楚该函数的类在做什么,特别是当传递给 .then 函数时,类在哪里或是什么,有人可以启发我吗?
    • @ErikAGriffin:hasClass 函数获得了两个参数——一个 html 元素和一个要检查的类的名称。然后该函数获取元素具有的“类”属性(类)。它拆分类字符串以获取类数组。然后它检查您要查找的类是否在数组的任何正索引中。我认为这是一种检查存在的方法。
    • 我已经将你的四行函数重写为这个性感的 ES6 单行: hasClass = (element, className) => element.getAttribute('class').then( (classes) => classes. split(' ').indexOf(className) !== -1 );
    • 在 TypeScript 中:异步函数 hasClass(elm: ElementFinder, className: string): Promise { const classNamesStr: string = await elm.getAttribute('class'); const classNamesArr: string[] = classNamesStr.split(' '); return classNamesArr.includes(className); }
    【解决方案4】:

    根据 Sergey K 的回答,您还可以添加自定义匹配器来执行此操作:

    (咖啡脚本)

      beforeEach(()->
        this.addMatchers({
          toHaveClass: (expected)->
            @message = ()->
              "Expected #{@actual.locator_.value} to have class '#{expected}'"
    
            @actual.getAttribute('class').then((classes)->
              classes.split(' ').indexOf(expected) isnt -1
            )
        })
      )
    

    然后你可以在这样的测试中使用它:

    expect($('div#ugly')).toHaveClass('beautiful')
    

    如果没有,您将收到以下错误:

     Message:
       Expected div#ugly to have class beautiful
     Stacktrace:
       Error: Expected div#ugly to have class 'beautiful'
    

    【讨论】:

      【解决方案5】:

      Here 一个 Jasmine 1.3.x 自定义 toHaveClass 匹配器与否定 .not 支持加上等待最多 5 秒(或任何你指定)。

      Find the full custom matcher to be added on your onPrepare block in this gist

      示例用法:

      it('test the class finder custom matcher', function() {
          // These guys should pass OK given your user input
          // element starts with an ng-invalid class:
          expect($('#user_name')).toHaveClass('ng-invalid');
          expect($('#user_name')).not.toHaveClass('ZZZ');
          expect($('#user_name')).toNotHaveClass('ZZZ');
          expect($('#user_name')).not.toNotHaveClass('ng-invalid');
          // These guys should each fail:
          expect($('#user_name')).toHaveClass('ZZZ');
          expect($('#user_name')).not.toHaveClass('ng-invalid');
          expect($('#user_name')).toNotHaveClass('ng-invalid');
          expect($('#user_name')).not.toNotHaveClass('ZZZ');
      });
      

      【讨论】:

        【解决方案6】:

        我制作了这个匹配器,我必须将它包装在一个承诺中并使用 2 个返回

        this.addMatchers({
            toHaveClass: function(a) {
                return this.actual.getAttribute('class').then(function(cls){
                    var patt = new RegExp('(^|\\s)' + a + '(\\s|$)');
                    return patt.test(cls);
                });
            }
        });
        

        在我的测试中,我现在可以这样做:

           var myDivs = element.all(by.css('div.myClass'));
           expect(myDivs.count()).toBe(3);
        
           // test for class
           expect(myDivs.get(0)).not.toHaveClass('active');
        

        当一个元素有多个类或一个元素根本没有类属性时,这也适用。

        【讨论】:

          【解决方案7】:
          function checkHasClass (selector, class_name) {
              // custom function returns true/false depending if selector has class name
          
              // split classes for selector into a list
              return $(selector).getAttribute('class').then(function(classes){
                  var classes = classes.split(' ');
                  if (classes.indexOf(class_name) > -1) return true;
                  return false;
              });
          }
          

          至少我是这样做的,不需要使用expect函数。如果类在元素内部,则此函数仅返回 true,否则返回 false。这也使用了 Promise,因此您可以像这样使用它:

          checkHasClass('#your-element', 'your-class').then(function(class_found){
              if (class_found) console.log("Your element has that class");
          });
          

          编辑:我刚刚意识到这与最佳答案基本相同

          【讨论】:

            【解决方案8】:

            实现此目的的一种方法是使用 xpath 并使用 contains()

            例子:

            var expectElementToHaveClass = function (className) {
                var path = by.xpath("//div[contains(@class,'"+ className +"')]");
                expect(element.all(path).count()).to.eventually.be.eq(1);
            };
            

            【讨论】:

              【解决方案9】:

              最简单的是:

              expect(element.getAttribute('class')).toContain("active");
              

              【讨论】:

              • 这会在 Microsoft Edge 上返回错误 java.util.ArrayList cannot be cast to java.lang.String
              • @Manolis 你如何在 angularjs 的 Web 控制台中获取 java 异常??
              【解决方案10】:

              您可以使用 CSS 解析器通过检查具有给定类的元素是否存在来处理此问题:

              expect(element(by.css('.form[name="getoffer"].ngDirty')).isPresent()).toBe(true);
              

              【讨论】:

                【解决方案11】:

                基本上,您正在解决一些问题:

                1. 如何上课。 class 是一个 html 属性,因此可以通过此命令检索(await 是这些天推荐的方式)
                let class = await element.getAttribute('class')
                
                1. 一旦你得到了一个类的值,你想要断言它
                // for exact value
                expect(class).toBe("active");
                
                // for partial match
                expect(class).toContain("active");
                // or
                expect(class.includes("active")).toBe(true);
                
                // BUT, keep in mind
                expect('male').toContain('male');
                expect('female').toContain('male');
                // BOTH pass
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-02-26
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-04-27
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多