In this chapter, we'll be talking about Tests and Global Hooks.
Nightwatch provides us with standard before
, after
, beforeEach
, and afterEach
hooks to be used in our tests if we need them.
Most testing frameworks, if not all, have hooks that we can use, because they're beneficial based on what we'd like to do.
I'll go ahead and show you the different hooks that we have available to us, and explain how they are used.
First off, let us create a test file and call it test.hooks.js
. Let's go ahead and create our hooks.
So, let's say module.exports
and we'll define our "before" hook by using the keyword before
and define a function.
We'll also define our after
, our beforeEach
, and our afterEach
.
The before
is run before our suite gets executed, and that is the current file that we're in. The after
is the opposite.
The beforeEach
will be run before each test within our suite, within the current test file. And afterEach
is the opposite.
module.exports = {
// This is ran before our suite gets executed
before: () => {
},
// This is ran after our suite was executed
after: () => {
},
// This will be run before each test within our suite
beforeEach: () => {
},
// This will be run after each test within our suite
afterEach: () => {
}
};
All of these methods should have the Nightwatch instance passed in an argument, so we'll just use client
to define our Nightwatch instance.
We can say 'Starting up' before our test suite and 'Closing down' after.
Before each of our tests - we might want to navigate to our URL.
After each of our tests, let's just output 'Test completed'.
module.exports = {
// This is ran before our suite gets executed
before: (client) => {
console.log('Starting up')
},
// This is ran after our suite was executed
after: (client) => {
console.log('Closing down')
},
// This will be run before each test within our suite
beforeEach: (client) => {
client.url('https://ultimateqa.com/filling-out-forms')
},
// This will be run after each test within our suite
afterEach: (client) => {
console.log('Test completed')
}
};
So now that we have defined our hooks, we can go ahead and write some tests.
We can call our first one "Should verify page tile". We'll just use a very simple test.
Because the beforeEach
hook would already be taking us to the URL, we can just go ahead and perform our assertion.
So we can say client.expect.title().to.contains
.
module.exports = {
// This is ran before our suite gets executed
before: (client) => {
console.log('Starting up')
},
// This is ran after our suite was executed
after: (client) => {
console.log('Closing down')
},
// This will be run before each test within our suite
beforeEach: (client) => {
client.url('https://ultimateqa.com/filling-out-forms')
},
// This will be run after each test within our suite
afterEach: (client) => {
console.log('Test completed')
}
"Should verify page tile": (client)=> {
client.expect.title().to.contains('Filling Out')
}
};
We can also add test "Should verify page url", and use client.expect.url().which.contains
.
module.exports = {
// This is ran before our suite gets executed
before: (client) => {
console.log('Starting up')
},
// This is ran after our suite was executed
after: (client) => {
console.log('Closing down')
},
// This will be run before each test within our suite
beforeEach: (client) => {
client.url('https://ultimateqa.com/filling-out-forms')
},
// This will be run after each test within our suite
afterEach: (client) => {
console.log('Test completed')
}
"Should verify page tile": (client)=> {
client.expect.title().which.contains('Filling Out')
},
"Should verify page url" : (client) => {
client.expect.url().which.contains('filling-out-forms')
}
};
Let's run our test with our hooks and see what happens.
./node_modules/.bin/nightwatch -t ./tests/test.hooks.js
So "before", when that one starts running our first test, we can see you got the printout of "Starting up".
So that shows that the before
hook was executed before.
Then, after we had our beforeEach
run, and it took us to the URL because we saw the URL loaded in the browser.
Then our tests ran and it passed.
Then we see that our afterEach
was executed, because just after the test, it said "Test completed".
Then we see that our next test started to run, and it passed as well.
Then we see "Test completed".
Also, we did notice that the URL loaded twice when we ran our tests, because the beforeEach
run was executed.
And then after the last test when everything was finished, we see that we have the "Closing down", which is our after
hook that was executed.
This gives us a fair idea of how we can use these hooks in our tests, if we need them. And we were also able to verify how each one of these methods works, and when they are executed.
Now let's move on to talking about global hooks.
Nightwatch makes the same set of hooks per test suite available globally, but these hooks are outside the scope of your tests.
The beforeEach
and afterEach
refers to a suite, which is your test file and are run before and after a test suite.
Now for us to use these global hooks, we first have to define our globals path, in our nightwatch.json
, because this is how Nightwatch uses globals.
We'll go ahead and create a new folder and call it globals
.
Within that folder, we'll call it globalModule.js
.
So we can go back to our configuration file nightwatch.json
and we'll add the path globals/globalModule.js
as the globals_path
.
Now we need to also define our global module.exports
and now we'll be able to define our global hooks. So we can say before
- this is outside of our test scope.
And this gets executed before our Selenium session gets started, and it's expecting to have a callback.
So a global hook like this is very beneficial, say, if we wanted to start a server before we actually execute our tests against that server.
For the after
hook, this is executed at the very end of our test run, which is the same as after closing the selenium session.
We can use this to stop our service that our automation was using, if we had started one in our before
.
module.exports = {
//Executed before selenium session is created
before: (done) => {
done();
},
//Executed after closing the selenium session
after: (done) => {
done();
}
}
The beforeEach
and afterEach
are executed before our test suite, and it has access to the browser instance.
So what we can do - we could check the client status with the results and print the results.
Then we have to call the callback
, so we can let the function know that we're through using it.
For the afterEach
, we can say console log the client.currentTest
and call done()
We'll also add some console log statements to each hook so we can see what's going on.
module.exports = {
//Executed before selenium session is created
before: (done) => {
console.log('before');
done();
},
//Executed after closing the selenium session
after: (done) => {
console.log('after');
done();
},
beforeEach: (client, done) => {
console.log('beforeEach');
client.status(result => {
console.log(result.value)
done()
});
},
afterEach: (client, done) => {
console.log('afterEach');
console.log(client.currentTest);
done()
}
}
Let's run our tests hook file and see what happens. Now that we have our global before
, after
, beforeEach
, and afterEach
defined.
As you can see, shortly after we executed the test, we saw that the before
was executed.
Then we had our Selenium connection.
Then we have the beforeEach
that was created before our suite started.
We printed out the status, and then this is our before
within our test file that were created. That's it starting up.
Our test ran, then we had our test complete, which is our afterEach
within our test file that was run, and so forth.
And after everything was done, then we see that the afterEach
, the global afterEach
was executed after our test suite, with the current information of our test suite.
Then after, when all of our reporting and our afterEach
was executed, long after we see the after
.
So now, we have an understanding of how we can use test hooks and global hooks to benefit our automation.