node.js: calling a function in webdriverio using mocha - node.js

I am writing many test cases. In all of them there is a common part (signing in the user and doing some other stuff).
So instead of writing that part in every test, I want a function to call it.
I have tried using .then and .call but it throws error:
.setValue('#signin_email', LogInEmail)
^
SyntaxError: Unexpected token .
How is this thing done?

Do you mean this? http://webdriver.io/guide/usage/customcommands.html
browser.addCommand("LogInEmail", function () {
return browser
.setValue('#signin_email', 'emailaddress')
.setValue('#password', 'password');
});
// to invoke
browser.LogInEmail()

If you want to run your common part before every mocha test then put it in beforeEach() function like this.
describe('some test', function() {
beforeEach(function() {
// your common part here
});
it('it should do something, function() {
...
});
...
it('it should do something else', function() {
...
});
});

Related

Callback not a function - Mocha/Mongoose

So I've tried looking up this bug, but I can't seem to find an answer that caters to my bug. I'm using mocha and chai-http to test some API's. I'm just hitting the endpoints using their corresponding RESTFUL methods (POST, GET, PUT) and checking the response (really straight forward). The problem is, individually my test suites work (if I were to run them one at a time), but when I run them using my gulp command ... I get "callback not a function" for some of the test cases (the ones in the if hook if you're familiar with mocha)
Here's the error I'm getting:
Uncaught TypeError: callback.apply is not a function
at Immediate.<anonymous> (node_modules/mongoose/lib/model.js:3683:16)
at Immediate._onImmediate (node_modules/mongoose/node_modules/mquery/lib/utils.js:137:16)
Here's the structure of my directory that my test cases reside:
test
backend
assignments_tests.js
application_tests.js
courses_test.js
& I have a gulp file with the following:
// Set the environment variable for the test cases to point to production
gulp.task('set-testing-env', function() {
return process.env.NODE_ENV = 'production';
})
// gulp task for backend
gulp.task('test-backend', ['set-testing-env'], function() {
return gulp.src('test/backend/**/*.js', {read: false})
.pipe(mocha({
reporter: 'spec',
timeout: 60000
}))
.on('error', function(err) {
// console.log(err);
process.exit();
});
});
& finally a sample of my test case:
describe("testing GET" ....
before(function(done) {
... setting up stuff here and calling done ...
})
describe("get courses information and courses offered", function() {
it("gets a courses information", function(done) {
const endpoint = test.endpoint + "/courseInfo/" + test.course
chai.request(app)
.get(endpoint)
.end(function(err, res) {
expect(err, "Error hitting endpoint").to.be.null;
expect(res, "Expected data in json format").to.be.json;
expect(res, "Expected status to be 200").to.have.status(200);
expect(res.body, "Expected course info!").to.have.length(1);
expect(res.body[0],"Missing keys").to.have.all.keys(courseInfo);
done();
})
})
})
describe("testing POST" ...
before(function(done) {
... setting up and calling done ...
})
describe(...
it(...)
})
})
I'm not too sure why I'm getting a callback not a function error. :(
Any help would be much appreciated!
Probably in some part of code that you didn't include here you are calling a Mongoose method passing something like too many objects as parameters, like in this question:
Async.each throwing error
One of those objects gets interpreted as a function but cannot be called as such.
This is a common problem but you didn;t include any code that runs Mongoose methods so it's hard to tell if that is the issue here.

MochaJS: How to share assertion/"it('should')" code between tests

I have some mocha tests I run with Nodejs to test a web server.
Many of the tests should cause the server to return an error, e.g. 400 Bad Request.
Currently the tests are peppered with many copies of the following code:
it('should respond with 400 (Bad Request)', function (){
expect(httpResponse.statusCode).to.equal(httpstatus.BAD_REQUEST);
});
Here's a simplified pseudocode example:
describe('When passing bad JSON data', function(){
var response
before(function(done){
callUrlToInsert(url, badJson, function(err, resp){
response = resp
done()
}
}
it('should respond with 400 (Bad Request)', function (){
expect(httpResponse.statusCode).to.equal(httpstatus.BAD_REQUEST)
})
}
This bugs me because as a programmer I avoid duplicate code wherever possible.
However, putting this into a function does not work:
function verifyItReturnedBadRequest400(httpResponse)
{
it('should respond with 400 (Bad Request)', function (){
expect(httpResponse.statusCode).to.equal(httpstatus.BAD_REQUEST);
});
}
because the call to it() doesn't test the assertion right then; my [limited] understanding is that it() adds the closure to the list of tests. So by the time that check is done, the httpResponse variable has gone out of scope. (I don't understand why that is the case, because in both cases there is a call to it(); why would it matter that in one case it's inside another level of function call? I'm probably missing something with regard to Javascript scoping.)
Is there a common way to avoid all this duplicate code? Or is everyone out there duplicating all their assertion code everywhere? This is my first foray into Mocha so I am probably missing something obvious.
Also, bonus points for explaining why doesn't the function approach work?
Thanks!
There is an article on wiki about this.
https://github.com/mochajs/mocha/wiki/Shared-Behaviours
I guess you have some bugs in your test. Placing it() into wrapper function works fine. Here's a small working demo.
'use strict';
const assert = require('assert');
const xEqualsOne = () => {
it('should be equal 1', () => {
assert.equal(this.x, 1);
});
};
describe('async number', () => {
this.x = 0;
before(done => {
this.x++
setTimeout(done, 100);
});
xEqualsOne();
});
I guess your code looks something like this:
describe('When passing bad JSON data', function(){
var response
before(function(done){
callUrlToInsert(url, badJson, function(err, resp){
response = resp
done()
}
}
verifyItReturnedBadRequest400(httpResponse)
}
Think about it like this:
it() creates a test.
All the calls to it happen before any tests are actually run (you have to create tests before you run them)
The function passed to `before' is run after the tests have been created, but before they are run.
verifyItReturnedBadRequest400 calls it, to create a test, but you're passing in httpResponse right then before any tests have run, so before hasn't run yet either.
You could continue to use that sort of pattern, but you'll need to put the httpresponse in a container so you can pass a reference to it:
describe('When passing bad JSON data', function(){
var data = {};
before(function(done){
callUrlToInsert(url, badJson, function(err, resp){
data.response = resp
done()
}
}
verifyItReturnedBadRequest400(data)
}
and then your verifyItReturnedBadRequest400 becomes:
function verifyItReturnedBadRequest400(data) {
it('should respond with 400 (Bad Request)', function (){
expect(data.response.statusCode).to.equal(httpstatus.BAD_REQUEST);
});
}

Mocha beforeEach and afterEach during testing

I have been trying to test my test server using mocha. This is the following code that I use, almost the same as one found in another similar post.
beforeEach(function(done) {
// Setup
console.log('test before function');
ws.on('open', function() {
console.log('worked...');
done();
});
ws.on('close', function() {
console.log('disconnected...');
});
});
afterEach(function(done) {
// Cleanup
if(readyState) {
console.log('disconnecting...');
ws.close();
} else {
// There will not be a connection unless you have done() in beforeEach, socket.on('connect'...)
console.log('no connection to break...');
}
done();
});
describe('WebSocket test', function() {
//assert.equal(response.result, null, 'Successful Authentification');
});
the problem is that when I execute this draft, none of the console.log that is expected to be seen is visible on the command prompt. Can you please explain to me what am I doing wrong?
Georgi is correct that you need an it call to specify a test but you don't need to have a top level describe in your file if you don't want to. You could replace your single describe with a bunch of it calls:
it("first", function () {
// Whatever test.
});
it("second", function () {
// Whatever other test.
});
This works very well if your test suite is small and composed of only one file.
If your test suite is bigger or spread among multiple files, I would very strongly suggest you put your beforeEach and afterEach together with your it inside the describe, unless you are absolutely positive that every single test in the suite needs the work done by beforeEach or afterEach. (I've written multiple test suites with Mocha and I've never had a beforeEach or afterEach that I needed to run for every single test.) Something like:
describe('WebSocket test', function() {
beforeEach(function(done) {
// ...
});
afterEach(function(done) {
// ...
});
it('response should be null', function() {
assert.equal(response.result, null, 'Successful Authentification');
});
});
If you do not put your beforeEach and afterEach inside describe like this, then let's say you have one file to test web sockets and another file to test some database operations. The tests in the file that contains the database operation tests will also have your beforeEach and afterEach executed before and after them. Putting the beforeEach and afterEach inside the describe like shown above will ensure that they are performed only for your web socket tests.
You have no tests in your example. If there are no tests to be run, then before and after hooks won't be invoked. Try adding a test like:
describe('WebSocket test', function() {
it('should run test and invoke hooks', function(done) {
assert.equal(1,1);
done();
});
});
You need to have a test-callback(eg. it) inside suite-callback(eg, describe) to execute beforeEach() and afterEach() hooks. More info https://mochajs.org/#run-cycle-overview

Mocha failed assertion causing timeout

I'm getting started with mocha testing framework with NodeJS. Success assertions working fine but if the assertion fails, my test timeouts. For asserting I've tried Should and Expect. For example (async code)
it('should create new user', function(done){
userService.create(user).then(function(model){
expect(model.id).to.be(1); //created user ID
done();
}, done)
});
Here the if model id is not 1 then the test timesout instead of reporting failed assertion. I'm sure I'm doing something wrong. Appreciate your help. Thanks!
Shawn's answer works, but there is a simpler way.
If you return the Promise from your test, Mocha will handle everything for you:
it('should create new user', function() {
return userService.create(user).then(function(model){
expect(model.id).to.be(1); //created user ID
});
});
No done callback needed!
expect is throwing an error that is being caught by the promise. Adding a catch condition that calls done fixes this.
it('should create new user', function(done) {
userService.create(user).then(function(model) {
expect(model.id).to.be(1); //created user ID
done();
}).catch(function(e) {
done(e);
})
});
Looks like done is never called. Besides then, you may also need an else to handle the failure.

In mocha testing while calling asynchronous function how to avoid the timeout Error: timeout of 2000ms exceeded

In my node application I'm using mocha to test my code. While calling many asynchronous functions using mocha, I'm getting timeout error (Error: timeout of 2000ms exceeded.). How can I resolve this?
var module = require('../lib/myModule');
var should = require('chai').should();
describe('Testing Module', function() {
it('Save Data', function(done) {
this.timeout(15000);
var data = {
a: 'aa',
b: 'bb'
};
module.save(data, function(err, res) {
should.not.exist(err);
done();
});
});
it('Get Data By Id', function(done) {
var id = "28ca9";
module.get(id, function(err, res) {
console.log(res);
should.not.exist(err);
done();
});
});
});
You can either set the timeout when running your test:
mocha --timeout 15000
Or you can set the timeout for each suite or each test programmatically:
describe('...', function(){
this.timeout(15000);
it('...', function(done){
this.timeout(15000);
setTimeout(done, 15000);
});
});
For more info see the docs.
I find that the "solution" of just increasing the timeouts obscures what's really going on here, which is either
Your code and/or network calls are way too slow (should be sub 100 ms for a good user experience)
The assertions (tests) are failing and something is swallowing the errors before Mocha is able to act on them.
You usually encounter #2 when Mocha doesn't receive assertion errors from a callback. This is caused by some other code swallowing the exception further up the stack. The right way of dealing with this is to fix the code and not swallow the error.
When external code swallows your errors
In case it's a library function that you are unable to modify, you need to catch the assertion error and pass it onto Mocha yourself. You do this by wrapping your assertion callback in a try/catch block and pass any exceptions to the done handler.
it('should not fail', function (done) { // Pass reference here!
i_swallow_errors(function (err, result) {
try { // boilerplate to be able to get the assert failures
assert.ok(true);
assert.equal(result, 'bar');
done();
} catch (error) {
done(error);
}
});
});
This boilerplate can of course be extracted into some utility function to make the test a little more pleasing to the eye:
it('should not fail', function (done) { // Pass reference here!
i_swallow_errors(handleError(done, function (err, result) {
assert.equal(result, 'bar');
}));
});
// reusable boilerplate to be able to get the assert failures
function handleError(done, fn) {
try {
fn();
done();
} catch (error) {
done(error);
}
}
Speeding up network tests
Other than that I suggest you pick up the advice on starting to use test stubs for network calls to make tests pass without having to rely on a functioning network. Using Mocha, Chai and Sinon the tests might look something like this
describe('api tests normally involving network calls', function() {
beforeEach: function () {
this.xhr = sinon.useFakeXMLHttpRequest();
var requests = this.requests = [];
this.xhr.onCreate = function (xhr) {
requests.push(xhr);
};
},
afterEach: function () {
this.xhr.restore();
}
it("should fetch comments from server", function () {
var callback = sinon.spy();
myLib.getCommentsFor("/some/article", callback);
assertEquals(1, this.requests.length);
this.requests[0].respond(200, { "Content-Type": "application/json" },
'[{ "id": 12, "comment": "Hey there" }]');
expect(callback.calledWith([{ id: 12, comment: "Hey there" }])).to.be.true;
});
});
See Sinon's nise docs for more info.
If you are using arrow functions:
it('should do something', async () => {
// do your testing
}).timeout(15000)
A little late but someone can use this in future...You can increase your test timeout by updating scripts in your package.json with the following:
"scripts": {
"test": "test --timeout 10000" //Adjust to a value you need
}
Run your tests using the command test
For me the problem was actually the describe function,
which when provided an arrow function, causes mocha to miss the
timeout, and behave not consistently. (Using ES6)
since no promise was rejected I was getting this error all the time for different tests that were failing inside the describe block
so this how it looks when not working properly:
describe('test', () => {
assert(...)
})
and this works using the anonymous function
describe('test', function() {
assert(...)
})
Hope it helps someone, my configuration for the above:
(nodejs: 8.4.0, npm: 5.3.0, mocha: 3.3.0)
My issue was not sending the response back, so it was hanging. If you are using express make sure that res.send(data), res.json(data) or whatever the api method you wanna use is executed for the route you are testing.
Make sure to resolve/reject the promises used in the test cases, be it spies or stubs make sure they resolve/reject.

Resources