Selena
Selena

Reputation: 2268

How to get a boolean value for element visibility in Protractor and return it before other code executes?

I am writing a page object for a non-Angular page that I need to use to get to the Angular app I am testing.

I just want some methods that provide information about the state of components on the page: is a menu expanded or collapsed? When I call these accessor methods, I want them to return true or false. The problem is that 'isDisplayed()' doesn't just return a boolean value. And it seems that when I call these accessor methods from other code, they don't 'wait' for the value to be returned. They just go on executing. How do I prevent that?

"use strict";

function Page () {
    this.menuAccessor = element(by.css("blah"));
    this.menuContainer = element(by.css("blahblah"));
}

Page.prototype.expandMenu = function () {
    if(!this.isMenuExpanded()) {
        this.menuAccessor.click();
    }
};

Page.prototype.collapseMenu = function () {
    if(this.isMenuExpanded()) {
        this.menuAccessor.click();
    }
};

Page.prototype.isMenuExpanded = function () {
    return this.menuContainer.isDisplayed().then(
        function(isVisible) {
            if(isVisible) {
                console.log("Menu is expanded");
            } else {
                console.log("Menu is not expanded");
            }
            return isVisible
        },
        function (err) {
            console.log("Menu is not expanded");
            return false;
        }
    )
};

module.exports = Page;

So, I was trying to test this out:

var Page = require('./../blahblah/Page.js');

describe('Test page object',function(){

    //Page is non-Angular
    browser.ignoreSynchronization=true;

    var p = new Page();
    var isExpanded = p.isMenuExpanded();
    console.log("State of menu: " + isExpanded);
    console.log("Logging something else");
});

When I execute this, I get this output:

/blahblah;bah/node_modules/protractor/built/cli.js /Users/someperson/blalbahlbah/config.js
[14:46:20] I/local - Starting selenium standalone server...
[14:46:20] I/launcher - Running 1 instances of WebDriver
[14:46:21] I/local - Selenium standalone server started at http://192.168.2.4:59574/wd/hub
State of menu: ManagedPromise::464 {[[PromiseStatus]]: "pending"}
Logging something else <== Test method goes on executing before state of menu is known.
Started


No specs found
Finished in 0.001 seconds
chrome
Menu is not expanded <== The state of the menu is determined after the test method finishes executing.
[15:05:14] I/local - Shutting down selenium standalone server.
[15:05:14] I/launcher - 0 instance(s) of WebDriver still running
[15:05:14] I/launcher - chrome #01 passed

Process finished with exit code 0

How do I accomplish what I want? I can't find a good example online for how to develop these kinds of accessor methods for providing information about the state of UI components in JavaScript.

Upvotes: 1

Views: 1070

Answers (1)

alecxe
alecxe

Reputation: 474161

The usual way to solve this problem is to pass around promises and resolve them once you need an actual value from the promise:

Page.prototype.expandMenu = function () {
    var self = this;
    this.isMenuExpanded().then(function (isExpanded) {
        if (!isExpanded) {
            self.menuAccessor.click();
        }
    });
};

Page.prototype.collapseMenu = function () {
    var self = this;
    this.isMenuExpanded().then(function (isExpanded) {
        if (isExpanded) {
            self.menuAccessor.click();
        }
    });
};

Page.prototype.isMenuExpanded = function () {
    return this.menuContainer.isDisplayed();
};

Upvotes: 2

Related Questions