Testing asynchronous mongodb calls in nodejs with jasmine - node

I use jasmine-node to run tests against my nodejs functions. As a newbie to nodejs and mongodb, the first thing I came across was testing some database calls, and I was immediately stuck due to the asynchronous nature of nodejs.

What I want to do:

1) Add the add function to add new records to the mongodb table

2) Get the status bar from this function to check the status of the action

Below is the code for my specification. In the beforeEach call beforeEach I initialize the database. As you can see in the implementation, it is created only once because of the condition, if it already exists.

 var mongo = require('../mongo.js'); describe('mongo', function() { // generate a random number in order to test if the written item and the retrieved result match var randomNumber = Math.random(); var item = { 'cities': { 'london': randomNumber } }; beforeEach(function() { mongo.init(); waitsFor(function() { return mongo.getCollection(); }, "should init the database", 10000); }); it('should return "added" after adding an item to the database', function() { var result; waitsFor(function() { result = mongo.add(item); // the result value here is always undefined, // due to the problem i'm having in my implementation return result !== undefined; }, "adding an item to the database", 10000); runs(function() { expect(result).toEqual('added'); }); }); }); 

Now for each database query, I can define a callback function that runs when the query was successfully completed. What I don’t know how to achieve is the result of the result of the mongodb callback back to the specification.

This is the current implementation of the database functions:

 var mongo = require('mongodb'), Server = mongo.Server, Db = mongo.Db; var server = new Server('localhost', 27017, {auto_reconnect: true}); var db = new Db('exampleDb', server); var collection = false; // initialize database var init = function() { if (collection === false) { db.open(dbOpenHandler); } }; var dbOpenHandler = function(err, db) { db.collection('myCollection', dbCollectionHandler); }; var dbCollectionHandler = function(err, coll) { collection = coll; }; /** returns the current db collection status * @return object db collection */ var getCollection = function() { return collection !== false; }; /** Add a new item to the database * @param object item to be added * @return string status code */ var add = function(item) { var result = collection.insert( item, {safe: true}, function(err) { // !! PROBLEM !! // this return call returns the string back to the callee // question: how would I return this as the add function return value return 'added'; }); }; // module export functions exports.init = init; exports.getCollection = getCollection; exports.add = add; 

I am also open to other approaches on how to test database calls in mongodb. I read a bunch of articles on this topic, but none of them relate to my specific case.

Decision

Finally, and with the help of JohnnyHK's answer, I managed to get it to work with a callback. Take a look at the following test case to see what I did:

 it('should create a new item', function() { var response; mongo.add(item, function( err, result) { // set result to a local variable response = result; }); // wait for async call to be finished waitsFor(function() { return response !== undefined; }, 'should return a status that is not undefined', 1000); // run the assertion after response has been set runs(function() { expect(response).toEqual('added'); }); )} 
+8
mongodb jasmine-node
source share
2 answers

You will need to modify your add method to accept the callback parameter so that it can deliver the asynchronous result to the caller through this callback:

 var add = function(item, callback) { collection.insert(item, {safe: true}, function(err) { callback(err, 'added'); }); }; 
+3
source share

You can do this much more cleanly now with the done function in jasmine-node:

 it('should create a new item', function(done) { mongo.add(item, function(error, result) { expect(result).toEqual('added'); done(); }); }); 

This test will wait for done() be called asynchronously. There, the default timeout is 5 seconds, after which your test will fail. You can change this, say, for 15 seconds:

 it('should create a new item', function(done) { mongo.add(item, function(error, result) { expect(result).toEqual('added'); done(); }); }, 15000); 
+13
source share

All Articles