How to use protractor to check if an element is visible?

I'm trying to test if an element is visible using protractor. Here's what the element looks like:

<i class="icon-spinner icon-spin ng-hide" ng-show="saving"></i>

When in the chrome console, I can use this jQuery selector to test if the element is visible:

$('[ng-show=saving].icon-spin')
[
<i class=​"icon-spinner icon-spin ng-hide" ng-show=​"saving">​</i>​
]
> $('[ng-show=saving].icon-spin:visible')
[]

However, when I try to do the same in protractor, I get this error at runtime:

InvalidElementStateError: 
invalid element state: Failed to execute 'querySelectorAll' on 'Document': 
'[ng-show=saving].icon-spin:visible' is not a valid selector.

Why is this not valid? How can I check for visibility using protractor?


This should do it:

expect($('[ng-show=saving].icon-spin').isDisplayed()).toBe(true);

Remember protractor's $ isn't jQuery and :visible is not yet a part of available CSS selectors + pseudo-selectors

More info at https://stackoverflow.com/a/13388700/511069


The correct way for checking the visibility of an element with Protractor is to call the isDisplayed method. You should be careful though since isDisplayed does not return a boolean, but rather a promise providing the evaluated visibility. I've seen lots of code examples that use this method wrongly and therefore don't evaluate its actual visibility.

Example for getting the visibility of an element:

element(by.className('your-class-name')).isDisplayed().then(function (isVisible) {
    if (isVisible) {
        // element is visible
    } else {
        // element is not visible
    }
});

However, you don't need this if you are just checking the visibility of the element (as opposed to getting it) because protractor patches Jasmine expect() so it always waits for promises to be resolved. See github.com/angular/jasminewd

So you can just do:

expect(element(by.className('your-class-name')).isDisplayed()).toBeTruthy();

Since you're using AngularJS to control the visibility of that element, you could also check its class attribute for ng-hide like this:

var spinner = element.by.css('i.icon-spin');
expect(spinner.getAttribute('class')).not.toMatch('ng-hide'); // expect element to be visible