如何使用量角器测试一个元素是否有类?

我正在试验量角器 e2e 测试角度应用程序,还没有想出如何检测一个元素是否有一个特定的类。

在我的示例中,测试单击提交按钮,现在我想知道 form [ name = “ getoffer”]是否具有 class。肮脏。解决方案可能是什么?

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
});
});
93118 次浏览

Have you tried this?

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

or a variation of the above...

If you're using Protractor with Jasmine, you could use toMatch to match as a regular expression...

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

Also, note that toContain will match list items, if you need that.

One gotcha you have to look out for with using toMatch(), as in the accepted answer, is partial matches. For instance, let's say you have an element that might have the classes correct and incorrect, and you want to test that it has the class correct. If you were to use expect(element.getAttribute('class')).toMatch('correct'), that will return true even if the element has the incorrect class.

My suggestion:

If you want to only accept exact matches, you can create a helper method for it:

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

You can use it like this (taking advantage of the fact that expect automatically resolves promises in Protractor):

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

Based on the answer from Sergey K, you could also add a custom matcher to do this:

(coffeescript)

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

Then you can use it in tests like this:

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

And you'll get the following error if it doesn't:

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

Here a Jasmine 1.3.x custom toHaveClass matcher with negation .not support plus wait up to 5 seconds (or whatever you specify).

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

Sample usage:

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

I made this matcher, I had to wrap it in a promise and use 2 returns

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

in my test i can now do stuf like this:

   var myDivs = element.all(by.css('div.myClass'));
expect(myDivs.count()).toBe(3);


// test for class
expect(myDivs.get(0)).not.toHaveClass('active');

this also works when an element has multiple classes or when an element has no class attribute at all.

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

This is how I do it at least, without the need to use the expect function. This function simply returns true if the class is inside the element and false if not. This also uses promises so you would use it like:

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

Edit: I just realized this is essentially the same as the top answer

One way to achieve this would be to use xpath and use contains()

Example:

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

Simplest is:

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

You can use the CSS parser to handle this by checking if an element with the given class exists:

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

Essentially, you're solving a few problems:

  1. how to get class. class is an html attribute and thus can be retrieved by this command (await is the recommended way these days)
let class = await element.getAttribute('class')
  1. Once you got the value of a class, you want to assert it
// 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