I have a problem with mocha and async/sequelize I think.
I have a form that allow the user to enter his pseudo and password and do some asynchronous work with that. It works really fine. But I want to write unit testing for all my application.
When I wrote the test for this part, it doesn't work, because sequelize never call the success function back and I really don't know why, because it works without mocha.
Here is the code for the processing of the form :
var inscrire = function(data, cb){
//Getting the data
var pseudo = data.pseudonyme;
var password = data.password;
var passConfirm = data.passwordConfirmation;
//Verifying the form
//Pseudonyme
if(pseudo.length < 1 || password.length > 255){
cb(null, 'form');
return;
}
//Password
if(password.length < 1 || password.length > 255){
cb(null, 'form');
return;
}
//Password confirmation
if(passConfirm != password){
cb(null, 'form');
return;
}
async.waterfall([
//Finding the user
function(callback){
//Find the user with the pseudonyme
db.User.find({where : {'pseudonyme' : pseudo}}).done(function(err, user){
console.log('AAAA');
if(err){
throw err;
}
console.log('YEAH');
callback(null, user);
});
},
//Creating the user if he's not here
function(user, callback){
//If the user is not in the base
if(!user){
//Hash the password
password = hash(password);
//Create the user
db.User.create({'pseudonyme' : pseudo,
'password' : password}).success(function(){
callback(null, true);
});
}else{
//The user is alreadyhere
callback(null, 'useralreadyhere');
}
}
], function(err, result){
//Throw any exception
if(err){
throw err;
}
//Returning the result
cb(null, result);
});
}
And here is the part of my unit test:
describe('#user-not-in-db', function() {
it('should succeed', function(){
var data = {
'pseudonyme' : 'test',
'password' : 'test',
'passwordConfirmation' : 'test'
};
async.waterfall([
function(callback){
index.inscrire(data, callback);
}
], function(err, result){
console.log('YO');
result.should.equal('YOO');
});
});
});
Thank you in advance.
I see at least one problem with the unit test as you have written it:
It's running as a synchronous test.
To run an async tests in mocha, the it test callback must take a "done" argument or return a promise. For example:
describe('foo', function(){
it('must do asyc op', function(done){
async.waterfall([
function(cb){ setTimeout(cb,500); },
function(cb){ cb(null, 'ok'); }
], function(err, res){
assert(res);
done();
}
);
});
});
See part of the mocha documentation for more examples:
http://visionmedia.github.io/mocha/#asynchronous-code
Related
I'm working on node js for the first time.My nodejs project is in MVC style and I am doing Ajax request for login.but i'm not getting data from the model...
Here is the code....
Controller / Auth.js
var data = req.body;
Auth_model.login(data, function(err,result){
if(!result){
response = {
error:true,
message : "Username or Password is wrong."
};
res.send(JSON.stringify(response));
}else{
response = {
error:false,
message : "Logged in Successfully."
};
// console.log(result);
res.send(JSON.stringify(response));
}
});
});
Model / Auth_model.js
module.exports.login = function(data, callback){
var email = data.email;
var password = data.password;
var sql = 'SELECT * FROM `users` WHERE email='+mysql.escape(email);
db.query(sql, callback,function (err, result, fields) {
if (result) {
bcrypt.compare(password,result[0].password, function(err, result) {
if(result){
return result;
}else{
return err;
}
});
}
});
}
Controller / Auth.js
var data = req.body;
// here you are passing your callback function as second argument
// So, you can use it in your login model when you get your response
Auth_model.login(data, function(err,result){
.........
}
Model / Auth_model.js
module.exports.login = function(data, callback){
.......
if(result){
// use your callback function pass error : null and result:result
callback(null,result);
}else{
callback(err,null)
}
......
}
You can use promise as well instead of callback function like
module.exports.login = (data) = new Promise(function(resolve, reject) {
.......
if(result){
// use your callback function pass error : null and result:result
resolve(result);
}else{
reject(err);
}
......
});
// use it like :
login(data).then(result=>console.log(result)).catch(err=>console.log(err))
Learn more and more about callback function and promises.
as I see that you are passing a callback function within the login function but inside the function definition of login function you are not calling the callback and passing the data to it.
You would have to do something like this.
module.exports.login = function(data, callback) {
var email = data.email;
var password = data.password;
var sql = "SELECT * FROM `users` WHERE email=" + mysql.escape(email);
db.query(sql, callback, function(err, result, fields) {
if (result) {
bcrypt.compare(password, result[0].password, function(err, result) {
if (result) {
return callback(null, result);
} else {
return callback(err, null);
}
});
}
});
};
How can I return the count of documents returned by a query?
I have a routing file, which have the following code:
router.post('/facebookLogin', function(req, res, next){
var User=require('../models/user');
var a=User.facebookUserExist(req.body.id, req.body.email);
console.log(a);
res.end();
});
And here is the content of the User model file:
var User=function(data){
this.data=data;
}
User.prototype.data={};
User.prototype.facebookUserExist=function(id, email){
var output;
db.collection('users').find({
$or:[
{
facebookID:id
},
{
email:email
}
]
}).count(function(err, numOfDocs){
output=numOfDocs;
});
return output;
}
module.exports=new User;
I set the value of the output variable in the count method callback, but the function still return undefined.
We know that JavaScript is asynchronous and won't wait for result. So you may either use callback or Promise object, here is example of callback for your code
router.post('/facebookLogin', function(req, res, next){
var User=require('../models/user');
User.facebookUserExist(req.body.id, req.body.email, function(err, count)
if(err)
console.log('Error ', err);
else
console.log(count);
res.end();
});
});
and your User model take a callback as last argument
var User=function(data){
this.data=data;
}
User.prototype.data={};
User.prototype.facebookUserExist=function(id, email, callback){
var output;
db.collection('users').find({
$or:[
{
facebookID:id
},
{
email:email
}
]
}).count(function(err, numOfDocs){
callback(err, numOfDocs);
});
//return output;
}
module.exports=new User;
.count() is required to get total docs in MongoDB. It might help.
USER.find(req.body.id, req.body.email).count(function(err, count) {
console.log("Number of docs: ", count); });
I am trying to transfer results data from query function to an object.
console.log(results) line returns 'undefined' result. What should I do?
module.exports = {
show: function(req, res) {
var results;
User.native(function(err, User) {
if(err) {
console.log("There is no exist a User by _id");
}
User.findOne({'_id' : req.param('id')},
function(err, user) {
results = user;
});
});
console.log(results);
return res.view({ stuff : results });
}
};
You have an async issue, the callback from findOne isn't necessarily executed in line with the rest of the code, so you get to the console.log(results) before results = user gets called. You'd want to change it to something like this:
show: function(req, res) {
var results;
User.native(function(err, User) {
if(err) {
console.log("There is no exist a User by _id");
}
User.findOne({'_id' : req.param('id')},
function(err, user) {
results = user;
console.log(results);
// Send response or make a callback here
});
});
}
I am sending a post request from a form but async.waterfall() doesn't execute the mongoose's User.find() function to fetch users from the database and as a result the post request's status in the network inspector is pending as res.send() is not being called.
exports.createUser = function(req,res){
var email1 = req.body.mail.toString();
var password = req.body.password.toString();
async.waterfall([
function(callback) {
// verify user in the db
User.find({email:email1},function(err,data){
if (err){
res.send(404);
return callback(err);
}
// user is found
if (data.length != 0){
res.send(404);
return callback(new Error("User Found"));
}
callback();
});
},
// generate salt password
function(callback) {
bcrypt.genSalt(SALT_WORK_FACTOR,function(err,salt){
if (err) return callback(err);
bcrypt.hash(password,salt,function(err,hash){
if (err) return callback(err);
return callback(null,hash);
});
});
},
//generate random string
function(hash,callback){
crypto.randomBytes(48,function(err,buf){
if (err) return callback(err);
var randomString = buf.toString('hex');
return callback(null,hash,randomString);
});
},
// save them in the mongoDb using mongoose
function(hash,randomString,callback){
var userModel = new User;
userModel.email = email1;
userModel.password = hash;
userModel.verificationId = randomString;
userModel.save();
callback(null,'done');
}
],function(err){
if (err){
console.log(err);
res.send(404);
} else{
console.log("done");
res.send("200");
}
});
}
Here is my app.js file using express
// render the registration page
app.get('/users/create',register.renderUserPage);
app.post('/users/create',function(req,res){
register.createUser(req,res);
});
Here is the Db.js file which connects to mongoDb using mongoose
console.log("connection succeeded");
var UserSchema = new Schema ({
email: {type:String ,require : true ,index : {unique : true}} ,
password:{ type : String ,required: true} ,
verificationId:{type:String, required:true,index:true}
});
UserSchema.plugin(ttl,{ttl:90000000});
module.exports = mongoose.model('User',UserSchema);
I'm using nodeJs express 3 framework with postgreSQL, I'm using the script below to look for a username in DB and populate a variable so I can pass it to my view.
Here is my script :
app.js
var app = express();
app.use(express.bodyParser());
......
function fncCheckUsernameAvailability(vstrUsername){
var pg = require("pg");
var client = new pg.Client({user: 'xxx', password: 'xxxx', database: 'xxx', host: 'example.com'});
var response = "";
client.connect(function(err) {
if(err) {
return console.error('could not connect to postgres', err);
}
client.query("SELECT username FROM users WHERE username ='"+vstrUsername+"'", function(err, result) {
if(err) {
return console.error('error running query', err);
}
if(result.rows[0] == undefined){
//console.log("Username available");
response = "Username available";//Populating The variable here
}else{
//console.log("Username already taken");
response = "Username already taken";//Populating The variable here
}
client.end();
});
});
return response;
}
app.post("/Signup", function(req, res){
var username = req.body.username;
var Response = fncCheckUsernameAvailability(username);
console.log(Response);
}
The response variable is allways "undefined", so how can I make that script waiting until the DB checking is done to populate the "response" variable?
You cannot place return values into asynchronous functions. You would instead need to use a callback, and this is what your code might look like:
function fncCheckUsernameAvailability(vstrUsername, callback) {
client.connect(function(err) {
if (err) {
callback(err, null);
return;
}
client.query("SELECT username FROM users WHERE username ='" + vstrUsername + "'", function (err, result) {
client.end();
if (err) {
callback(err, null);
return;
}
if (result.rows[0] == undefined) callback(null, 'Username available.');
else callback(null, 'Username taken.');
});
});
};
You would use the function like this:
app.post("/Signup", function(req, res) {
var username = req.body.username;
fncCheckUsernameAvailability(username, function(err, result) {
console.log(result);
});
});