Returning a value from a from a protractor promise inside a function

14,965

Solution 1

Thanks to @alecxe for starting me off on the right foot.

I found a solution I am now using quite a bit after reading this.

By passing an object by reference, you can add properties on the fly and use them later in your spec.

Example:

describe('My Test', function () {
    var tempObject = {};

    it('should go get some text from the page', function () {
        browser.get('https://angularjs.org/');
        getTextFromElement(tempObject);    //pass an object by reference to populate with page text
    });

    it('should do some random other stuff', function () {
        $('div.someDiv').click();
    });

    it('should be able to use the text from the first page in this test', function () {
        console.log(tempObject.textFromFirstPage); //works!
    });
});

function getTextFromElement(tempObject) {
    $('a.some-link').getText().then(function (txt) {
        tempObject.textFromFirstPage = txt;
    });
}

Solution 2

First of all, you are not returning anything from the function:

function getTextFromElement() {
    return $('a.learn-link').getText();
}

Now, this function would return you a promise which you need to resolve before using:

it('should be able to use the text from the first page in this test', function () {
    tempVariable.then(function (tempVariableValue) {
        console.log('\ntempVariable: ' + tempVariableValue);    
        expect(typeof tempVariableValue).not.toBe('undefined', 'failed: tempVariable was undefined!');
    });
});

Plus, to determine whether a variable is defined or not, I would use toBeDefined() from jasmine-matchers:

expect(tempVariableValue).toBeDefined();

Solution 3

None of the above worked for me. This is working for me:

    var item = element.all(by.xpath("some xpath here"));


    this.methodToGetTheText = function () {
       return Promise.resolve(item.getText().then(function (text) {
           return text;
       }));
    }
Share:
14,965
luker02
Author by

luker02

Updated on June 04, 2022

Comments

  • luker02
    luker02 almost 2 years

    I’m trying to get text from a page and then use that text further down in the spec to assert on another element.

    I’ve pasted a very simple spec you can run that shows you can’t return a value from a function if the function’s return statement is inside a protractor promise return txt; (line 24)…

    describe('My Test', function () {
        var tempVariable;
    
        it('should go get some text from the page', function () {
            browser.get('https://angularjs.org/');
            tempVariable = getTextFromElement();    //it appears javascript immediately sets this variable before waiting for protractor to return the value
        });
    
        it('should do some random other stuff', function () {
            element.all(by.cssContainingText('a', 'Learn')).get(0).click();
            element.all(by.cssContainingText('a', 'Case Studies')).get(0).click();
            element.all(by.cssContainingText('a', ' Home')).get(0).click();
        });
    
        it('should be able to use the text from the first page in this test', function () {
            console.log('\ntempVariable: ' + tempVariable);    //this is undefined!
            expect(typeof tempVariable).not.toBe('undefined', 'failed: tempVariable was undefined!');
        });
    });
    
    function getTextFromElement() {
        $('a.learn-link').getText().then(function (txt) {
            console.log('\nInitial text:   ' + txt);
            return txt;     //how do we return this so it's available to other 'it' blocks?
        });
    }
    

    Updated snippet of code following @alecxe answer and my comment.

    I am attempting to contruct an object from various text on a page and return it to assert on in a later page...

    function getRandomProductFromList() {
        var Product = function (line, name, subname, units) {
            this.line       = line;
            this.name       = name;
            this.subname    = subname;
            this.units      = units;
        };
    
        var myProduct = new Product();
    
        myProduct.line = 'Ford';
        myProduct.units = 235;
    
        //select a random product on the page and add it to 'myProduct'
        var allProducts = element.all('div.product');
        allProducts.count().then(function (count) {
            var randomIndex = Math.floor(Math.random() * count);
            var productName = allProducts.get(randomIndex);
    
            productName.getText().then(function (prodName) {
                myProduct.name = prodName;
                productName.click();
            });
        });
    
        //If a sub-product can be chosen, select it and add it to 'myProduct'
        var subproduct = $('div.subproduct');
        subproduct.isDisplayed().then(function (subProductExists) {
            if (subProductExists) {
                subproduct.getText().then(function (subProductName) {
                    myProduct.subname = subProductName;
                });
                subproduct.click();
            }
        }, function (err) {});
    
        return myProduct;
    }