I am just getting started learning nightwatchjs to test my webapp. I need to call a 'setup' and a 'teardown' script before and after everything else, respectively. These scripts create the necessary conditions in the database for the tests to run (creating test licenses, users, etc), and remove them afterward. I have an API call in my app that triggers these.
In globals.js, you can set before
and after
methods that should execute before and after everything else, and also a beforeEach
and afterEach
that should execute before and after each test suite, if I'm not mistaken. It seems the beforeEach
and afterEach
methods accept as arguments a browser
object and a done
callback. The before
and after
methods, however, only get the done
callback.
In a particular test suite, the same four methods can be added, but in this case, the before
and after
run before everything and after everything, respectively, and the beforeEach
and afterEach
run before and after each individual test in the suite.
Ideally, I would call my setup
and teardown
scripts in the global before
and after
methods, but those do not get an instance of nightwatch (browser), so I don't know how I'd do that.
I am able to fire off the 'setup' call just fine, in my globals beforeEach
method. This isn't ideal for me, but it would still work, it would just be a but superfluous (calling it before each test suite rather than just once before everything).
However, I run into issues when I try to call the teardown
script from my globals afterEach
method. When I run my test, the output hangs at the end, until I hit CTRL+C
.
Here is my nightwatch.conf.js:
const seleniumServer = require("selenium-server");
const chromedriver = require("chromedriver");
// we use a nightwatch.conf.js file so we can include comments and helper functions
module.exports = {
"src_folders": [
"tests",
],
"page_objects_path": './pages',
"globals_path": "./globals.js",
"output_folder": "./reports", // reports (test outcome) output by nightwatch
"custom_commands_path" : "./commands",
"selenium": {
"start_process": true, // tells nightwatch to start/stop the selenium process
"server_path": seleniumServer.path,
"host": "127.0.0.1",
"port": 4444, // standard selenium port
"cli_args": {
"webdriver.chrome.driver" : chromedriver.path
}
},
"test_settings": {
"default": {
"silent": true,
"launchUrl": 'http://local.mytestwebsite.com',
"screenshots": {
"enabled": true, // if you want to keep screenshots
"path": "./screenshots/" // save screenshots here
},
"globals": {
"waitForConditionTimeout": 5000 // sometimes internet is slow so wait.
},
"desiredCapabilities": { // use Chrome as the default browser for tests
"browserName": "chrome",
"chromeOptions": {
"args": [
"window-size=1366,768",
"--incognito"
]
}
}
}
}
}
Here is my globals.js:
var chromedriver = require('chromedriver');
module.exports = {
beforeEach: function(browser, done) {
console.log('Executing the global `beforeEach`');
browser.url('http://www.vulfpeck.com');
browser.expect.element('body').to.be.present;
browser.end();
// getting the session info
browser.status(function(result) {
console.log("Session Info: ", result.value);
done();
});
},
afterEach: function(browser, done){
console.log('Executing the global `afterEach`');
browser.url('http://www.vulfpeck.com');
browser.expect.element('body').to.be.present;
browser.end();
// getting the session info
browser.status(function(result) {
console.log("Session Info: ", result.value);
done();
});
},
before: function(done) {
console.log('Executing the global `before`');
console.log('starting the chromedriver');
chromedriver.start();
done();
},
after: function(done) {
console.log('Executing the global `after`');
console.log('stoppin the chromedriver');
chromedriver.stop();
done();
}
};
And here is my test suite:
module.exports = {
'Test 1': function(browser){
browser.url('http://www.google.com');
browser.expect.element('body').to.be.present;
browser.end();
},
'Test 2': function(browser){
browser.url('http://www.vulfpeck.com');
browser.expect.element('body').to.be.present;
browser.end();
},
before: function(browser, done){
console.log('test before');
done();
},
beforeEach: function(browser, done){
console.log('test beforeEach');
done();
},
after: function(browser, done){
console.log('test after');
done();
},
afterEach: function(browser, done){
console.log('test afterEach');
done();
}
};
Here is the output.
$ nightwatch
Executing the global `before`
starting the chromedriver
Starting selenium server... started - PID: 11772
[Login] Test Suite
======================
Executing the global `beforeEach`
√ Expected element <body> to be present - element was present in 31ms
Session Info: { ready: true,
message: 'Server is running',
build:
{ revision: '63f7b50',
time: '2018-02-07T22:42:28.403Z',
version: '3.9.1' },
os: { arch: 'amd64', name: 'Windows 10', version: '10.0' },
java: { version: '9' } }
test before
Running: Test 1
test beforeEach
√ Expected element <body> to be present - element was present in 30ms
test afterEach
OK. 1 assertions passed. (3.56s)
Running: Test 2
test beforeEach
√ Expected element <body> to be present - element was present in 20ms
test afterEach
OK. 1 assertions passed. (2.503s)
test after
Executing the global `afterEach`
Session Info: { ready: true,
message: 'Server is running',
build:
{ revision: '63f7b50',
time: '2018-02-07T22:42:28.403Z',
version: '3.9.1' },
os: { arch: 'amd64', name: 'Windows 10', version: '10.0' },
java: { version: '9' } }
× Expected element <body> to be present - element was not found - expected "present" but got: "not present"
at Object.afterEach (C:\sites\mytestwebsite.com\selenium\globals.js:29:21)
So, am I missing something? Why can I not hit a URL in the global afterEach method without it hanging? (I just figured out that if I remove the browser.end();
from my last test in the suite, my global afterEach
will work just fine. Why is this?). Is there some other recommended way of hitting a URL before and after running all tests?
Thanks! Any help is appreciated!