SanchelliosProg
SanchelliosProg

Reputation: 2331

How to retrieve data from protractor's promises chain?

I have a function, which correctly retrieves index of the element, which text === "check". It is clearly printed in console.log:

function getIndex() {
    return element.all(by.css(".palette__item.ng-scope>span")).then(function (colorList) {
        colorList.forEach(function (elem, index) {
            elem.getText().then(function (text) {
                if (text == "check") {
                    console.log(index);
                    return index;
                }
            });
        });
    });
}

Then, I've tried a lot of different approaches, how to retreive data from it, but haven't succeed. Tha last approach is this:

var res = null;
webDriver.promise.fullyResolved(getIndex()).then(function (index) {
    res = index;
});
console.log(res);

So, here I have tried to init res value inside the function, which guaratees any promise resolve, but it doesn't work, and returns null.

I think, that I have mistake in getIndex() function, maybe, I have placed return opertor in a wrong place, but I need help here. I have totally lost any idea how to make it work. Help, please.

Upvotes: 1

Views: 317

Answers (3)

alecxe
alecxe

Reputation: 473833

You are overcomplicating the problem, use reduce(), not the "forEach":

function getIndex() {
    return element.all(by.css(".palette__item > span")).reduce(function (acc, elem, index) {
        return elem.getText().then(function (text) {
            if (text == "check") {
                return index;
            } 
        });
    }, -1);
}

Usage:

getIndex().then(function (index) {
    console.log(index);
});

As a side note - try not to use ng-scope class in your locators - it is a pure technical angular-specific class which does not bring meaning to your locator.

Upvotes: 2

richdotjs
richdotjs

Reputation: 214

A few things: For starters, you initialized the variable outside of the promise but assigning the variable's value within the promise. That's perfectly fine but take a look at where your console.log() is in the example you showed us. If you leave the console.log statement at the very bottom like that, it will MOST LIKELY executed before your promise resolves, therefore the value of variable res, will be null.

Have you tried to log out the value of res within the promise?

Going back to the getIndex function... Why are you using promises within the forEach function? Have you tried doing the following instead:

function getIndex() { return element.all(by.css(".palette__item.ng-scope>span")).then(function (colorList) { colorList.forEach(function (elem, index) { var temp = elem.getText() if (temp == "check") { console.log(index); return index }); }); }); }

That's all I can suggest with the amount of information that you have provided in this post. The key lesson from this is to better understand how asynchronous code differs from synchronous.

Upvotes: 1

Sirko
Sirko

Reputation: 74036

I currently can not debug it, but this should work:

function getIndex() {
    return element
            .all(by.css(".palette__item.ng-scope>span"))
            .then((colorList) => { 
              // get text for all elements
              return Promise.all( colorList.map( (el) = el.getText() ) ); 
            })
            .then((colorList) => {
              // we need both text and index
              return colorList.map( (el, ind) => [el, ind] )
              // but just the elements with text "check"
                              .filter( (elArr) => ellArr[0] == 'check' )
              // at this point we can throw away the text and just use the index
                              .map( (elArr) => elArr[1] );
            })
}

Your basic problem is, that you mix functions, that return promises, with other iterator-functions. So when you finally call return you completely lost the promise context.

Upvotes: 1

Related Questions