I have a SPA where there are multiple divs with the same class. I want protractor to select the visible div and click it. I keep getting the Failed: element not visible
which makes be believe it's getting some element that isn't on this particular page (maybe?). I also get WARNING - more than one element found for locator By.cssSelector('.myDiv') - the first result will be used
which again makes me think it's not clicking the visible one, but the invisible one.
Here is my spec:
describe('User actions', function () {
it("should be able to click a my div.", function () {
var myDiv = element(by.css('.myDiv'));
myDiv.click();
// some expect... haven't gotten this far yet.
});
How do I select the visible .myDiv
and click it?
Working with angular, it is pretty common to have many layers of the same bit of html hidden, but earlier in the overall html page than the visible element you would like to work with.
For general debugging, open up your site to the position you expect your protractor test to be in, then open the html and do a search on the html for the element your protractor test is searching for. Note if it is visible or not and where it is located overall.
Consider if you would like to add a tag for different areas of the page where the element can appear, and then use parent and child selectors to get the one you'd like.
You can also use this to select just the first visible element:
// Takes a protractor webelement and returns the first displayed version
// Ex:
// var coolBox = $('.coolBox');
// var visibleCoolBox = getFirstVisibleProtractorElement(coolBox);
this.getFirstVisibleProtractorElement = function(selector){
var allElementsOfSelector = element.all(by.css(selector.locator().value));
return allElementsOfSelector.filter(function(elem) {
return elem.isDisplayed().then(function(displayedElement){
return displayedElement;
});
}).first();
};
Pass in any element you'd like, it will take the locator and get the first visible version of it. You can also take off the .first() portion to return an array of the visible elements to work with.
EDIT:
To use this, I will give a protractor+jasmine example. I thiiiink this should work given there is any number of desired elements on the page, with at least one being visible. This is off the top of my head though, so I may have made a mistake somewhere.
example_spec.js
var examplePage = require('./example_page.js');
describe('Extracting visible elements', function(){
it('A visible element can be extracted', function(){
expect(examplePage.isACoolBoxVisible()).toBeTruthy('Error: No visible CoolBoxes');
});
});
example_page.js
var protractorUtils = require('./protractor_utils.js');
module.exports = new function(){
var elements = {
coolBox: $('.coolBox')
};
this.getVisibleCoolBox = function(){
return protractorUtils.getFirstVisibleProtractorElement(elements.coolBox);
};
this.isACoolBoxVisible = function(){
return getVisibleCoolBox.isDisplayed();
};
};
protractor_utils.js
module.exports = new function(){
this.getFirstVisibleProtractorElement = function(selector){
var allElementsOfSelector = element.all(by.css(selector.locator().value));
return allElementsOfSelector.filter(function(elem) {
return elem.isDisplayed().then(function(displayedElement){
return displayedElement;
});
}).first();
};
};
You can filter()
it out:
var myDiv = element.all(by.css('.myDiv')).filter(function (elm) {
return elm.isDisplayed().then(function (isDisplayed) {
return isDisplayed;
});
}).first();