Nightwatch: Returning value in function does not work. Neither getters and setters. Reading value is performed before writting.

Created on 25 Nov 2020  路  17Comments  路  Source: nightwatchjs/nightwatch

I tried returning value in function and even using simple getters and setters with global var in an page object and then read value from it.

Result is always that tests reads values of variables at the very start of running itself..... before I set the value to the variable.....

F.e.
var login = salesPage.executeGetUserFromApiAndWriteOKDONE()
console.log(login)
console.log("Oops")
console.log("Oops" + salesPage.getUATLogin())

will produce:
undefined
Oops
Oops

OKDONE

Can you please fix it, or tell me how to fix it?

So far I only figgured out that I can save to file results from API call, and next test will read it. But that means every first test run fails if there is no file or value in file, and that I need to store on my Jenkins server a bunch on unique files for each test to get its own fresh user's login.

Any help would be appreciated.

Most helpful comment

Also I get :

[Marta Case] Test Suite
=============================
- Connecting to localhost on port 9515...

i Connected to localhost on port 9515 (2554ms).
  Using: chrome (87.0.4280.66) on Windows platform.

Running:  test 

AmIEvenAccessible? YES
Button text is  Szukaj w Google
Oops I am in wrong place? Showing before browser opens and checks value? Szukaj w Google
Button text is  Szukaj w Google
Szukaj w Google
No assertions ran.

All 17 comments

Have you try do it in a callback or using async/await ?

Tried, but await told me that the function does not comply and await cannot be used. Possibly I don't know how to use it correctly.

I tried also returning whole object from the function where I set that value inside it and calling getter, but value was also empty.

login = salesPage.executeGetUserFromApi()
loginPage.loginToUAT(login.getUATLogin(), configuration.userPassword)

async mojaFunkcja(){
... yourCode ...
return yourVar
}

login = await mojaFunkcja()

Am I supposed to mark a whole test as async to call await? That does not seem to be intended use of await.
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await

I want to turn off that asychronicity and stop test from executing a few methods executing at once... or at least out of order.

Am I supposed to mark a whole test as async to call await? That does not seem to be intended use of await.
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await

I want to turn off that asychronicity and stop test from executing a few methods executing at once... or at least out of order.

yes

Checked if I can just create such method as command

async getLogin: function(loginPage,salesPage){
}

And answer was not, its not recognized as correct function. And even if it worked I still would have problem with no being able to return that variable from function to test:

Error: There was an error while trying to load the file salesPage.js: Unexpected token ':'
at Array.forEach ()
at Array.forEach ()
at new Promise ()

Could you please show your code with REPLACED data that we should not see to look at your code syntax?

Don't know which API I should use as replacement. I should pretty much need to write function to contact some API and get data from 0, because code is not my property.

I will do that, but it will take some time.

Ok. Before I tried to get that value from api. I tried getting that value from browser. This code is my work so I can share it and it has the same issues.

  1. If async is used, whole nightwatch test cannot be run, becasue of "Syntax error: Unexpected token ':'" error.
  2. Without async await, values are read before page from where they were supposed to be read from is even accessed....so console writes undefined and then message "Button text is Szukaj w Google" which shows after value of button is read

var login = "AmIEvenAccessible? YES"

const commands = {
getLogin: function(){
return login
},

setLogin: function (value) {
login = value
},

getValueFromBrowser: function(browser){
browser.url('https://www.google.pl/')
.getAttribute('center:nth-child(1)>input:nth-child(1)', 'value', function(result){
console.log("Button text is ", result.value)
this.login = result.value
commands.setLogin(result.value)
})
return this.login
},

async doSomethingWithValueReceivedFromInternet: function (browser){
console.log(await commands.getValueFromBrowser(browser))
}
}

module.exports = {
'@disabled': false,
'@tags': ['ThatWeirdThing','UAT'],
'test ': function (browser) {

 commands.getLogin() //"AmIEvenAccessible? YES"
 console.log(login)  //undefined
 console.log("Oops I am in wrong place? Showing before browser opens and checks value? " + commands.getValueFromBrowser(browser)) 
 commands.doSomethingWithValueReceivedFromInternet(browser)                                                         
 browser.end()

 //result :

 // AmIEvenAccessible? YES
 // Oops I am in wrong place? Showing before browser opens and checks value? undefined
 // undefined
 // Button text is  Szukaj w Google
 // Button text is  Szukaj w Google
 // No assertions ran.

}
}

Here you got code that work - not perfectly, just a quick shot:

var login = "AmIEvenAccessible? YES"

const commands = {
    getLogin: function () {
        return login
    },

    setLogin: function (value) {
        login = value
    },

    getValueFromBrowser: function (browser) {
        return new Promise(async (resolve) => {
            browser.url('https://www.google.pl/')
            .getAttribute('center:nth-child(1)>input:nth-child(1)', 'value', function (result) {
                console.log("Button text is ", result.value)
                this.login = result.value
                commands.setLogin(result.value)
                resolve(this.login);
            })
        })
    },

    doSomethingWithValueReceivedFromInternet: async function (browser) {
        await console.log(await commands.getValueFromBrowser(browser))
    }
}

module.exports = {
    '@disabled': false,
    '@tags': ['ThatWeirdThing', 'UAT'],
    'test ': function (browser) {

        commands.getLogin() //"AmIEvenAccessible? YES"
        console.log(login)  //undefined
        console.log("Oops I am in wrong place? Showing before browser opens and checks value? " + commands.getValueFromBrowser(browser))
        commands.doSomethingWithValueReceivedFromInternet(browser)
        browser.end()

        //result :

        // AmIEvenAccessible? YES
        // Oops I am in wrong place? Showing before browser opens and checks value? undefined
        // undefined
        // Button text is  Szukaj w Google
        // Button text is  Szukaj w Google
        // No assertions ran.
    }
}

Output:

[Marta Case] Test Suite
=============================
\ Connecting to localhost on port 9515...

/ Connecting to localhost on port 9515...
i Connected to localhost on port 9515 (2569ms).
  Using: chrome (87.0.4280.66) on Windows platform.

Running:  test 

AmIEvenAccessible? YES
Oops I am in wrong place? Showing before browser opens and checks value? [object Promise]
Button text is  Szukaj w Google
Button text is  Szukaj w Google
Szukaj w Google
No assertions ran.

Check your inbox on famous portal about finding job.

Also I get :

[Marta Case] Test Suite
=============================
- Connecting to localhost on port 9515...

i Connected to localhost on port 9515 (2554ms).
  Using: chrome (87.0.4280.66) on Windows platform.

Running:  test 

AmIEvenAccessible? YES
Button text is  Szukaj w Google
Oops I am in wrong place? Showing before browser opens and checks value? Szukaj w Google
Button text is  Szukaj w Google
Szukaj w Google
No assertions ran.

I think also you want to get such code without global variables:

const commands = {
    printSomething: function(something) {
        return console.log("Something:" + something);
    },

    getValueFromBrowser: function (browser) {
        return new Promise(async (resolve) => {
            await browser.url('https://www.google.pl/')
            await browser.getAttribute('center:nth-child(1)>input:nth-child(1)', 'value', function (result) {
                const login = result.value
                resolve(login);
            })
        })
    },
}

module.exports = {
    '@disabled': false,
    '@tags': ['ThatWeirdThing', 'UAT'],
    'test ': async function (browser) {
        const textFromBrowser = await commands.getValueFromBrowser(browser);
        commands.printSomething(textFromBrowser)
        await browser.end()
    }
}

With this output:

\ Connecting to localhost on port 9515...

i Connected to localhost on port 9515 (2616ms).
  Using: chrome (87.0.4280.66) on Windows platform.

Running:  test 

Something:Wyszukiwarka Google
No assertions ran.

No that works perfectly!

I changed a message a little, so we can see results better:

doSomethingWithValueReceivedFromInternet: async function (browser) {
await console.log(await commands.getValueFromBrowser(browser) + " <-I waited for this!")
}

And the result was perfect! :
Button text is "Szukaj w Google"

Szukaj w Google <-I waited for this!

Regarding global variables in test. I cannot use local variables in method. I need to use the exact same variable 3 times in each test: to log in, to authorize with sms code, and to log off. So it needs to be stored somewhere in the test. But I put everything from commands and page object methods into one pager so it would be easier for you to run.

Thanks a lot for helping! You really saved a day! I really wanted to unlock that proof of concept for project before leaving and I had just two days for it. With it 80% tests can be translated to work on user restricted enviroments which don't allow unrestricted test users.

If it's withing the same test file you could you variable with test scope, if it's in different files, you could use global variables with persistent flag enabled. In any other case, feel free to contact me on linkedin.

:) Thank you :) A lot of test files. For sure I will try to work more in JS, it's a weirder challenge than Java.

I'm using NW with TypeScript, it not bad, but require a bit of configuration.

Was this page helpful?
0 / 5 - 0 ratings