Reputation: 356
I am using selenium webdriver and I get specific elements by id. After getting the elements with the correct id, I try to pick 1 element from the list which has a unique attribute value.
I have managed to get to the values I need, but I'm not happy with the solutions I found.
Situation:
var attributeName = "bla";
var id = "icon";
var iconElementsPromise = driver.findElements(By.id(id)); // returns a promise containing an array with WebElements
Solution 1: nested then
's: This just looks so wrong, but it works.
iconElementsPromise
.then(function(iconElements) {
iconElements.forEach(function(element, index) {
element.getAttribute(attributeName)
.then(function(attribute) {
console.log("attribute: " + attribute);
});
});
});
Solution 2: just 1 nested then
: It looks better but now I need to create an array of Promises, which is ok... but I want NO Nesting at all
iconElementsPromise
.then(function(iconElements) {
var promises = [];
iconElements.forEach(function(element, index) {
promises.push(element.getAttribute("tag"));
});
return promises;
})
.then(function(promises) {
Promise.all(promises)
.then(function(attributes) {
console.log("attributes: " + attributes);
});
});
Solution 3:By returning the Promise.all(promises)
I can stay on the same indet-level and don't nest the then
s.
iconElementsPromise
.then(function(iconElements) {
var promises = [];
iconElements.forEach(function(element, index) {
promises.push(element.getAttribute(attributeName));
});
return promises;
})
.then(function(promises) {
return Promise.all(promises);
})
.then(function(attributes) {
console.log("attributes: " + attributes);
});
Solution 1 has 2 then
s and gets each attribute
Solution 2 and 3 have 3 then
s each, and get me the attributes array
Getting each attribute or just the array is ok.
I do believe that Solution 3 is more or less what I want. But the code is rather long. I get the feeling that there must be a better, more readable and shorter way to get the attributes.
So my question is: **What is the best way to get the attributes using promises? **
Examples appreciated.
Upvotes: 1
Views: 477
Reputation: 42518
If your goal is to pick 1 element having a unique attribute, then it would be easier to include this attribute in a locator:
// select with an XPath the first element having an attribute "bla" and a parent with the "icon" id
var element = driver.findElement(By.xpath("id('icon')/*[@bla]"));
// select with a CSS selector the first element having the attribute "bla" and a parent with the "icon" id
var element = driver.findElement(By.cssSelector("#icon > [bla]"));
But if you really want all the attributes, then a short solution is to use webdriver.promise.map
:
var webdriver = require('selenium-webdriver');
var promise = webdriver.promise;
var By = webdriver.By;
var Key = webdriver.Key;
var EC = webdriver.until;
var driver = new webdriver.Builder()
.withCapabilities({'browserName': 'firefox'})
.build();
driver.get('http://stackoverflow.com/');
driver.findElements(By.xpath('//a')).then(function(elts) {
promise.map(elts, function(elt) {
return elt.getAttribute("href");
}).then(function(links) {
console.log(links);
})
});
Upvotes: 1
Reputation: 731
A little shorter version of 3
using map
to reduce one then
while still keeping it readable
iconElementsPromise
.then(function(iconElements) {
return Promise.all(iconElements.map(function(element){
return element.getAttribute(attributeName);
}));
})
.then(function(attributes) {
console.log("attributes: " + attributes);
});
Upvotes: 2