Using Nightwatch global variables to write tests that work everywhere
Why Use Global Variables in your Test Automation?
Nightwatch and other test automation frameworks allow you to use variables instead of hardcoding values in your tests. The benefits of this aren't always immediately obvious when you start writing a new test suite, but inevitably
- The dataset changes
- You realize it's bad hardcoding sensitive data like login information in the test
- Someone asks if you can run the test against a different environment
- You add translation or localization functionality
and you are left with a lot of finding and replacing to do, duplicate code, or unnecessary rework.
You can use Nightwatch global variables so that this information is read out of a config file instead of being hardcoded in your tests.
If something changes you only have to make the change in one place similar to how the page object model is a great pattern for the DOM.
In addition, to the delight of your security team, you can safely store sensitive information like logins outside of your source code repository.
Using global variables in your tests
The nightwatch.json
config file has a test settings section that let's you store default and environment-based global variables to hold values unique to your test environments.
For example, below we have a default and sandbox environment.
"test_settings": {"default": {"launch_url": "http://localhost","skip_testcases_on_fail": false,"desiredCapabilities": {"browserName": "chrome"},"globals": {"username": "nightwatchTutorial","password": "${TUTORIAL_PASS}","firstName": "Sharon","lastName": "Trouble","shirtSize": "L"}},"sandbox": {"launch_url": "https://sandbox.davidmello.com","globals": {"username": "sandboxUser","password": "${TUTORIAL_SANDBOX_PASS}","firstName": "Aneeda","lastName": "Showstopper","shirtSize": "XL"}}}
From your command line, when you run your test if you simply type nightwatch
the test will run with the values from the default test_settings section.
To run your test against a different environment all you need to do is pass the -e
flag. For example, nightwatch -e sandbox
would run the test with the sandbox settings above.
Any values specified in the non-default environment would override any entries with the same name from default. Conversely, anything not specified in the environment would use the value from default.
Refactoring your tests to use global environment variables
Nightwatch makes it pretty easy to use variables in place of hardcoded values in your tests. Here is an example, of a test suite not using global environment variables.
module.exports = {before: function(browser) {browser.url('https://test.davidmello.com')browser.page.login().loginAs('janna', 'i like testing and horses');browser.page.navigation().goToProfilePage();},"profile page shows saved tshirt size": function(browser) {browser.page.profile().expect.element('@shirtSize').text.to.equal('Large');}}
Now pretend you have hundreds of tests like this, your security team does an audit, and tells you need to stop posting the sandbox credentials to the public github repository 😭 💀
Also, what happens if the company adds language preferences and Large
turns to Largo
or product decides instead of using written out sizes like Large
it will be abbreviated to L
.
You'd have some rework on your hands.
So let's refactor the tests to use global environment variables.
module.exports = {before: function(browser) {browser.page.login().navigate(); // Page object model will read launch_url from configbrowser.page.login().loginAs(browser.globals.username, browser.globals.password);browser.page.navigation().goToProfilePage();},"profile page shows saved tshirt size": function(browser) {browser.page.profile().expect.element('@shirtSize').text.to.equal(browser.globals.shirtSize);}}
With this automation pattern Nightwatch will just read the value out of your config file and when you run the test it will grab the correct values from there so you don't need to maintain multiple copies of your tests for different environments or do expensive rewrites later on when data or data formats change.
If the data changes you just change it in one place in your Nightwatch config file.
Organizing Global Variables in Nightwatch
As a real example, my team and I were involved in a fun initiative to automate some manual environment smoke tests. It covered a large range of pages and rather than having a large list of key value pairs like this
"sandbox": {"globals": {"someField1": "some value","someField2": "some value",..."someField42": "some value"}}
We thought it would be better to use JSON nested objects to keep things logically organized together with the page. This prevents confusion when there are similarly named fields on different pages that contain different information.
"sandbox": {"globals": {"profile": {"firstName": "Janna","lastName": "Levtus","shirtSize": "L"},"emergencyContact": {"firstName": "Rick","lastName": "Astley"}}}
The data inside the variables can be accessed by drilling in through dot notation in your tests.
module.exports = {"profile page shows saved tshirt size": function(browser) {browser.page.navigation().goToProfilePage();browser.page.profile().expect.element('@firstName').text.to.equal(browser.globals.profile.firstName);browser.page.profile().expect.element('@lastName').text.to.equal(browser.globals.profile.lastName);},"emergency contact page shows saved emergency contact": function(browser) {browser.page.navigation().goToEmergencyContactPage();browser.page.emergencyContact().expect.element('@lastName').text.to.equal(browser.globals.emergencyContact.lastName);}}
This keeps things descriptive, well organized, and prevents name pollution when there are similarly named fields on different pages.
I've posted the entire example for multi-environment testing with test globals on my GitHub 👉 Nightwatch.js Global Environment Variables Tutorial.
If you are a Nightwatch beginner be sure to watch my Software Testing Playlist
If you have any questions or comments please reach out through my social links below 👇