Nodejs, mongoose and Qunit - node.js

I have been at this for hours and its like banging my head into a brick wall.
I have a node.js server application that uses mongoose to store data.
Now this all works amazingly but my problem is when I try and use Qunit to test my code I can get me mongoose save function to fire.
This is my unit test class.
mongoose.connect('mongodb://localhost/test');
var User = require('C:/SVN/RPGMMO/Server/Users/User');
QUnit.config.testTimeout = 50000;
QUnit.module("User", {
setup: function() {
user = new User();
ok(user != undefined, "Test Data Created");
},
teardown: function() {
user = undefined;
ok(user == undefined, "Test Data Deleted");
}
});
test("Create User", function() {
var user = new User({
name: 'test_user',
email: 'blah'
});
user.setPassword('test');
user.save(function(err, result) {
util.log("saving");
if (err) throw err;
ok (result, "Created User")
});
});
But when I run this test the user.save is never fired, only the setup and teardown is run.
Could anyone point out where am going wrong.
Am new to Quint on server side.
Regards
Iain

Related

How can I test my asynchronous code in a restify HTTP handler?

I have a function in my Restify project that handles an HTTP GET request. After some processing it uses Sequelize to find the user entity for my current session. The User.findOne function returns a promise and depending on the result of that promise, I'm sending an HTTP response with 200 or 404.
static getMe(req, res, next) {
const userInfo = BaseController.getUserSession(req);
// hard to test this part
User.findOne({
where: {email: userInfo.email}
}).then(function(user) {
if (user) BaseController.respondWith200(res, user);
else BaseController.respondWith404(res, 'User not found.');
}, function(error) {
BaseController.respondWith404(res, error);
}).then(function() {
return next();
});
}
I've tried a few different libraries to help with testing so I'm sorry if this is a messy combination of things. This is in my beforeEach function for my tests:
const usersFixture = [
{id:2, email:'ozzy#osbourne.com', facebookId:54321, displayName: 'Ozzy Osbourne'},
{id:3, email:'zakk#wylde.com', facebookId:34521, displayName: 'Zakk Wylde'},
{id:4, email:'john#lennon.com', facebookId:12453, displayName: 'John Lennon'}
];
this.findOneSpy = sinon.spy(function(queryObj) {
return new Promise(function(resolve, reject) {
const user = usersFixture.find(function(el) { return el.email === queryObj.where.email });
if (user) resolve(user);
else resolve(null);
});
});
this.respondWith200Spy = sinon.spy(function(res, data) {});
this.respondWith400Spy = sinon.spy(function(res, error) {});
this.respondWith404Spy = sinon.spy(function(res, error) {});
this.controller = proxyquire('../../controllers/user-controller', {
'../models/user': {
findOne: this.findOneSpy
},
'./base-controller': {
respondWith200: this.respondWith200Spy,
respondWith400: this.respondWith400Spy,
respondWith404: this.respondWith404Spy
}
});
And here is what one of my tests looks like:
it('should return 200 with user data if user email matches existing user', function() {
// THIS FUNCTION IS NEVER HIT
this.respondWith200Spy = function(res, data) {
data.should.equal({id:4, email:'john#lennon.com', facebookId:12453, displayName: 'John Lennon'});
done();
};
const req = {session:{user:{email:'john#lennon.com'}}};
this.controller.getMe(req, this.res, this.nextSpy);
this.findOneSpy.should.have.been.called;
});
Since we aren't actually passing a callback to the function and the function doesn't really return anything (just does asynchronous things elsewhere), I can't figure out how to test it to make sure it's working right. Any help is appreciated.
The actual code works just fine. I'm just trying to get some quality unit testing into the project. Thanks!
I ended up finding a way to do it using proxyquire. I just re-stubbed the controller class that I am testing and made the respondWith200 callback make an assertion. Then I created a new spy for the next function that just calls done (which is passed into the test case). I verified that the code is all getting hit.
it('should return 200 with user data if user email matches existing user', function(done) {
const controller = proxyquire('../../controllers/user-controller', {
'../models/user': {
findOne: this.findOneSpy
},
'./base-controller': {
respondWith200: function(res, data) {
data.displayName.should.equal('John Lennon');
},
respondWith400: this.respondWith400Spy,
respondWith404: this.respondWith404Spy
}
});
const req = {grft_session:{user:{email:'john#lennon.com'}}};
const nextSpy = sinon.spy(function() {
done();
});
controller.getMe(req, this.res, nextSpy);
this.findOneSpy.should.have.been.called;
});

Not able to display the current data sent from server

i am using nodejs as server, I am sending parameters to mongodb and saving it in database after that i am fetching it from database. But when i try to fetch the data i can't able to see the current data in nodejs terminal ,but it will be present in database. Again if i send the other data i will able to see the previous data but not the current data which i have sent now. I think my server is calling find function before save function. what should i do to make my save function to complete its task and then it should call the find function.
this mongodb code
import mongoose from 'mongoose';
var Schema = mongoose.Schema;
//connect to a MongoDB database
var db = mongoose.connect('mongodb://127.0.0.1:27017/student');
mongoose.connect('connected', function() {
console.log("database connected successfully")
});
var userSchema = new Schema({
Name: {
type: String,
required: true
},
Age: {
type: Number,
required: true
}
}, {
collection: ('studentcollection2')
});
var User = mongoose.model('User', userSchema);
function createStudent(name, age) {
var list = new User({
Name: name,
Age: age
});
list.save(function(err) {
if (err) throw err;
console.log("SUCCESSFUL");
});
}
function listStudent() {
User.find({}, function(err, studentcollection2) {
if (err) throw err;
console.log(studentcollection2);
});
}
exports.createStudent = createStudent; //module.exports = User;
exports.listStudent = listStudent;
this is my server code
import config from './config';
import express from 'express';
const server = express();
import mongodbInterface from './mongodbInterface';
server.set('view engine', 'ejs');
server.get('/', (req, res) => {
res.render('index', {
content: '...'
})
});
console.log(typeof mongodbInterface.createStudent);
mongodbInterface.createStudent("a9", 112);
mongodbInterface.listStudent();
server.use(express.static('public'));
server.listen(config.port, () => {
console.info('express listening on port', config.port);
});
I haven't run your code, but I imagine it's coming down to these two lines:
mongodbInterface.createStudent("a9", 112);
mongodbInterface.listStudent();
Both of these statements call asynchronous functionality. That is to say that when you call createStudent("a9", 112);, that functionality will run asynchronously in the background, and Node will continue to call listStudent(); straight away. Therefore, your createStudent method may not have written the data to the database by the time your listStudent function is run.
To solve this, you need to make use of callback functions to only retrieve the data once it's actually been saved. For example, you could do the following:
function createStudent(name, age, cb) {
var list = new User({
Name: name,
Age: age
});
list.save(function(err) {
if (err) return cb(err);
return cb();
});
}
function listStudent(cb) {
User.find({}, function(err, studentcollection2) {
if (err) return cb(err);
return cb(null, studentCollection2);
});
}
Then, in your server code:
mongodbInterface.createStudent("a9", 112, function(err) {
if (err) throw err;
mongodbInterface.listStudent(function(err, students) {
console.log(students); // You should see the newly saved student here
});
});
I'd recommend reading more about Node.js callbacks here - they are really core to the usage of Node.js.
The mongo methods are async so the data will write whenever it's ready. Use a callback function, promise or async/await to wait for the result without blocking the event loop and control order of execution.

Storing a MongoDb result in a variable to run a Mocha test, getting undefined

So, I'm trying to run a Mocha test, more precisely a Chakram test.
The problem is, I'm getting data from a collection in MongoDB and I want to store that data in a global variable to run some tests.
The problem is that inside the call back I get the data, but it doesn't set the global variables to run the tests.
Here is the code
var chakram = require('chakram'),
expect = chakram.expect;
describe("Test", function() {
var gl_email;
var gl_token;
before("Getting user data", function() {
var setAccessData = function() {
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost/virtusapp', function(err, db) {
if (err) throw err;
console.log("Connected to Database");
var user = db.collection('users').findOne({
name: "virtus-app"
});
user.then(function(result) {
email = result.email;
token = result.token1 + result.token2;
db.close(test(email, token))
});
});
}
var test = function(email, token) {
gl_email = email;
gl_token = token;
//Here the email and token are set, but it doesnt set the global variables
}
setAccessData();
});
it("should have set global email variable", function() {
//here gl_email should be set, but I get UNDEFINED.
expect(gl_email).to.eql("virtus-app#virtus.ufcg.edu.br");
})
});
I believe that the problem is not with Chakram, because I haven't used in this code yet.
Your before function is asynchronous. You should use a different signature to tell mocha that it has to wait until it's finished before running the tests.
before("Getting user data", function(done) {
...
var test = function(email, token) {
gl_email = email;
gl_token = token;
done();
}
...
});
Only after done() is called the rest of the code is going to be executed by mocha.
Mocha docs has a very comprehensive guide on how to test asynchronous code https://mochajs.org/#asynchronous-code

Mongoose Insert never returns in unit test

I'm creating a unit test to test Passport, and the first step is to create a user. Creating the user times out and the test is unable to progress.
Test (login.js):
'use strict';
var app = require('../index'),
kraken = require('kraken-js'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
should = require('chai').should(),
Q = require('q'),
agent = require('supertest'),
cookie,
pUser = {
firstName: 'pasport-test',
lastName: 'user',
userName: 'passport-user',
email: 'passport-user#here.com',
password: 'h#rdP#ssw0rd'
}
describe('#create user and log them in with passport', function () {
this.timeout(10000);
var mock;
beforeEach(function (done) {
kraken.create(app).listen(function (err, server) {
mock = server;
done(err);
});
});
afterEach(function (done) {
mock.close(done);
});
describe('#login the user', function () {
it('should create a user', function (done) {
var user = new User({
firstName: pUser.firstName,
lastName: pUser.lastName,
userName: pUser.userName,
email: pUser.email,
password: pUser.password
});
user.save(function(err, data) {
if(err) {
done(err);
} else {
done();
}
});
//it should then login that user with passport
});
});
If I connect o to mongoose directly:
mongoose.connect("mongodb://localhost/testing");
and require User this way:
User = require('../models/user');
It works.
I'd like to use the server and connection that the beforeEach sets up with kraken, so that inserts happen in the configured database...
Question is why does the mongoose insert never come back in the test?
You need to call mongoose.connect in your test code. mongoose queues all pending operations until a first db connection is made, which is why your save callback never gets called.
As noted by #Peter Lyons, I needed to perform the connect to the database.
I wrote a small helper to do this (that I can use across my test files).
db.js:
'use strict';
var nconf = require('nconf'),
mongoose = require('mongoose'),
env = process.env.NODE_ENV || 'testing';
//get the db config stuff for mongoose from the application config file
nconf.use('file', {
file: process.cwd() + '/config/app.json',
format: nconf.formats.json
});
var dbConf = nconf.get('databaseConfig')[env];
var db = function() {
return {
connect: function() {
if(!mongoose.connection.db) {
mongoose.connect("mongodb://" + dbConf.host + '/' + dbConf.database);
}
}
};
};
module.exports = db();
Then in my tests:
var db = require('./db');
db.connect();
And the model classes perform as expected.

On moving to TDD with node and mongo

I want to use mocha to add to my program feature by feature, test by test.
var assert = require('assert');
var mongoskin = require('mongoskin');
describe('basic database tests', function(){
before(function(){
});
it('should have 3 users', function(done){
var db = mongoskin.db('mongodb://localhost:27017/stuffTest', {safe:true});
db.collection('users').find().toArray(function (err,result){
console.log(result.length);
assert.equal(result.length,3);
});
});
});
It doesn't work. I get an error no matter where I put stuff in the test. With this arrangement I get Error: timeout of 2000ms exceeded
This is the code to set up the database. My old way of development was to litter my code with console.logs and such. This code uses console.logs to let me know if the collection is empty and then if so was it filled with 3 records.
var mongoskin = require('mongoskin')
var db = mongoskin.db('mongodb://localhost:27017/stuffTest', {safe:true})
db.collection('users').find().toArray(function (err,result){
console.log(result.length)
})
db.collection('users', {strict:true}, function(err, collection) {
if (err) {
console.log("The 'users' collection doesn't exist. Creating it with sample data...");
populateDB(users);
}
});
var populateDB = function(huh) {
console.log("Populating database...");
var name= huh.name;
var coll= huh.items;
db.collection(name, function(err, collection) {
collection.insert(coll, {safe:true}, function(err, result) {
console.log(result.length);
});
});
};
var users = [];
users.name = 'users';
users.items= [
{name: 'tim', email: 'mckenna.tim#gmail.com', lists:[]},
{name: 'peri', email: 'perimckenna#gmail.com', lists:[]},
{name: 'tim2', email: 'mckt_jp#yahoo.com', lists:[]}
];
How would I write this test? This code plus package.json and dropDb.js is here: https://github.com/mckennatim/tdd
You're not calling done. If you don't call done in an asynchronous test you are guaranteed to get a timeout. Modify the test to call done at the end of your callback. Like this:
it('should have 3 users', function(done){
var db = mongoskin.db('mongodb://localhost:27017/stuffTest', {safe:true});
db.collection('users').find().toArray(function (err,result){
console.log(result.length);
assert.equal(result.length,3);
done();
});
});

Resources