I'm writing a Protractor test that has to wait for an element attribute to have a non-empty value and then I want to return that value to the caller function. This has proven to be more difficult to write than I expected!
I am able to correctly schedule a browser.wait()
command to wait for the element attribute to have a non-empty value and I have verified that this value is in fact what I am expecting to get inside the callback function, but for some reason, I am not able to return that value outside of the callback function and onto the rest of the test code.
Here is how my code looks like:
function test() {
var item = getItem();
console.log(item);
}
function getItem() {
var item;
browser.wait(function() {
return element(by.id('element-id')).getAttribute('attribute-name').then(function(value) {
item = value;
// console.log(item);
return value !== '';
});
});
return item;
}
I can tell that the order of execution is not as I expect it to be, because when I uncomment the console.log()
call inside the callback function, I see the expected value printed out. However, the same call in the test()
function prints 'undefined'.
What is going on here? What am I missing? How can I get the attribute value out of the callback function properly?
I appreciate your help.
I would not combine the wait and the getting attribute parts - logically these are two separate things, keep them separate:
browser.wait(function() {
return element(by.id('element-id')).getAttribute("attribute").then(function(value) {
item = value;
// console.log(item);
return value !== '';
});
});
element(by.id('element-id')).getAttribute("attribute").then(function (value) {
console.log(value);
});
Note that, you may simplify the wait condition this way:
var EC = protractor.ExpectedConditions;
var elm = $('#element-id[attribute="expected value"]');
browser.wait(EC.presenceOf(elm), 5000);
elm.getAttribute("attribute").then(function (value) {
console.log(value);
});
Just FYI, you may have solved your current problem with the deferred
:
function test() {
getItem().then(function (value) {
console.log(value);
});
}
function getItem() {
var item = protractor.promise.defer();
browser.wait(function() {
return element(by.id('element-id')).getAttribute('attribute').then(function(value) {
var result = value !== '';
if (result) {
item.fulfill(value);
}
return result;
});
});
return item.promise;
}
After doing some more reading about how protractor works with promises and schedules/registers them with the control flow, I found an easier work-around close to the first solution @alecxe provided. Here it goes:
function test() {
var item = getItem().then(function(item) {
console.log(item);
});
}
function getItem() {
return browser.wait(function() {
return element(by.id('element-id')).getAttribute('attribute-name').then(function(value) {
return value;
});
});
}
Since browser.wait()
returns a promise itself, it can be chained with another then()
inside the caller and this way the right order of execution is guaranteed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With