Mocha route testing not executing asynchronously - node.js

I have started working with mocha and I have a problem with one particular test case. Here is the code:
var assert = require("chai").assert;
var request = require('supertest');
var http = require("http");
var conf = require("../config/config");
var app = require("../app");
var mongoose = require('mongoose');
var User = mongoose.model('User');
describe('User controller', function(){
describe('POST /register', function(){
it('should return false when the parameters are not unique', function (done) {
request(app)
.post('/user/register')
.send({username:"janette_doe", email:"janette_doe#gmail.com", password:"test123"})
.expect('Content-Type',/json/)
.expect({success:true, redirect:'/user/registerConfirmation'})
.end(function(err, res) {
if (err) {
return done(err);
}
request(app)
.post('/user/register')
.send({username:"janette_doe", email:"janette_doe#gmail.com", password:"test123"})
.expect('Content-Type',/json/)
.expect({success:false}, done);
});
});
});
I am expecting the result to be false because after the insertion of a user inside the database, the unique index rule should raise an error. When I run this test, I get this: {success: true, redirect: '/user/registerConfirmation'} , I should be getting this: {success: false}. I noticed that when I don't clear the database before each tests (in utils.js) I am getting the expected value. Do I get this error because of an asynchronous error? How can I rewrite this test to make sure that it works?
Thanks
Files
util.js contains the configurations for the test sequence:
'use strict';
process.env.NODE_ENV = 'test';
var config = require('../config/config');
var mongoose = require('mongoose');
beforeEach(function (done) {
mongoose.connection.db.dropDatabase();
return done();
});
afterEach(function (done) {
return done();
});
user.js the user model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
var UserSchema = new Schema({
username: {type: String, required: true, unique: true},
email: {type: String, required: true, unique: true},
password: {type: String, required: true},
status: {type: Number, default:0}
});
UserSchema.virtual('date')
.get(function(){
return this._id.getTimestamp();
});
UserSchema.pre('save', function(next) {
//Password encryption ...
});
mongoose.model('User', UserSchema);
user.js (controller) is the controller for all the user routes.
...
router.post('/register', function (req,res,next){
var newUser = new User({
username: req.body.username
, email: req.body.email
, password: req.body.password
});
newUser.save(function(err){
if(err){
res.send({success: false});
}else{
var newToken = new UserToken({
userId: newUser._id
, email: newUser.email
});
newToken.save(function(err){
if(err){
res.send({success: false});
}else{
res.send({success: true, redirect: '/user/registerConfirmation'});
}
});
}
});
});
...
Edit
I have tried the end() function and it still doesn't work.

There is a problem in how you chain supertest requests in your test test suite - the second request is not invoked properly. When you were not clearing the database the test was failing on the first .expect({success: true, ...}) and you were getting the expected value.
The correct way is to perform the first request with .end method, check for potential errors, and then perform the second request to see if it has failed:
describe('User controller', function(){
describe('POST /register', function(){
it('should return false when the parameters are not unique', function (done) {
request(app)
.post('/user/register')
.send({username:"janette_doe", email:"janette_doe#gmail.com", password:"test123"})
.expect('Content-Type',/json/)
.expect({success:true, redirect:'/user/registerConfirmation'})
.end(function(err, res) {
// Check if first request has failed (it should not!)
if (err) {
return done(err);
}
// Testing the second, not unique request. that should fail
request(app)
.post('/user/register')
.send({username:"janette_doe", email:"janette_doe#gmail.com", password:"test123"})
.expect('Content-Type',/json/)
.expect({success:false}, done);
});
});
});

In mocha, the done() function should be called when your async call is done - regardless of whether an error is hit. Also, use the .done() function - which is part of the promise API - to end the promise chain and ensure any exceptions are caught. Without the done function, you can miss runtime errors completely, as they are suppressed by the promise library.

Related

Stuck on NodeJS mongoDB find() Query

I am unable to write the correct query.
I am trying to check if the user already exists in the database and it will respond in Login Successfully Response.
This code is in working position problem lies in Query.
I hope somebody will help
function login() {
app.post("/login/", async(req, res) => {
const query = new Model({
email: req.body.email,
password: req.body.password,
});
const cursor = Model.find(query); // (*Here's the problem*)
console.log(cursor);
if (query === cursor) {**strong text**
console.log(query);
res.send("login successfully");
} else {
console.log(query);
res.send("user does not exist ");
}
});
}
login();
// Model and Schema
const LoginSchema = new mongoose.Schema({
email: { type: String, required: true },
password: { type: String, required: true },
});
const Model = mongoose.model("login_details", LoginSchema);
// Registeration Phase
function registration() {
app.post("/register/", async(req, res) => {
const model = new Model({
email: req.body.email,
password: req.body.password,
});
const result = await model.save();
console.log(result);
res.send(model);
});
}
// Headers
const express = require("express");
const app = express();
const mongoose = require("mongoose");
app.use(express.json());
app.use(express.urlencoded({ extend: true }));
//
Issues with your code
1- You don't need to use new Model({}) to query
2- You're using .find() which returns an array, use findOne() instead
3- You're attempting to check if a mongoose model (with _id) equals a query without the _id which won't work
4- Use return at the end of your function (won't affect the functionality here but just as good practice not to encounter errors like cannot set headers after they're sent)
possible solution
function login() {
app.post("/login/", async (req, res) => {
const cursor = await Model.findOne({
email: req.body.email,
password: req.body.password,
});
console.log(cursor);
if (cursor) {
console.log(cursor);
return res.send("login successfully");
} else {
return res.send("user does not exist ");
}
});
}
You are using Mongoose in the wrong way. Try this.
const result = await Model.find({
email: req.body.email,
password: req.body.password,
});

http post inside .then()

I want to do a http post inside .then(). I've already it in many diferent ways...nothing worked
I'm trying to create an user and do an http POST after the creation.
'use strict';
module.exports = function(app) {
return function(req, res, next) {
const body = req.body;
// Get the user service and `create` a new user
app.service('users').create({
email: body.email,
password: body.password
}).then('I WANT HTTP POST WITH PARAMS HERE')
// On errors, just call our error middleware
.catch(next);
};
};
I want to send email and password in the POST
You can return a Promise in promise chain. I would use promisified request to do a postAsync here.
var Promise = require('bluebird')
var request = Promise.promisifyAll(require('request'))
app.service('users').create({
email: body.email,
password: body.password
}).then(function(createUserResp) {
return request.postAsync(/**/)
})
}).then(function(resp) {
// do sth
})
.catch(next);
var RP = require('request-promise')
app.service('users').create({
email: body.email,
password: body.password
}).then(function () {
var opt = {
url: 'targetUrl',
formData: {
email: body.email,
password: body.password
//, json: true // if result is in json format
}
}
return RP.post(opt)
}).then(function (postResult) {
})
.catch(next);

Sequelize.js returns error on create instance

I have the problem where my unit test with mocha always return an error when i try to create a new instance and save it to the db.
Model:
//db is a global instance of the sequelize pool connection
var sequelize = require('sequelize');
var users = db.define('users', {
uuid: {
type: sequelize.STRING(36),
allowNull: false,
unique: true,
validate: {
isUUID: 4
}
},
username: {
type: sequelize.STRING(100),
allowNull: false,
unique: 'idxProvUsr'
}
}, {
freezeTableName: true
});
module.exports = users;
Controller:
var usersDB = require('../models/users');
var sequelize = require('sequelize');
var usersCtrl = {
userCreate: function (userData, callback) {
var test = usersDB.build(userData);
test.save()
.then(function (data) {
callback(true, data);
})
.catch(function (error) {
if (error) {
callback(false, error);
}
});
},
};
module.exports = usersCtrl;
Test:
'use strict';
var chai = require('chai');
var uuid = require('node-uuid');
var userCtrl = require('../app/controllers/users');
var userData = {
uuid: null,
username: 'manuerumx'
};
describe('Users Controller', function(){
it('Fails add new User', function(done){
userCtrl.userCreate(userData, function(isOk, response){
chai.expect(isOk).to.equal(false);
done();
});
});
it('Add new User', function(done){
userData.uuid = uuid.v4();
userCtrl.userCreate(userData, function(isOk, response){
chai.expect(isOk).to.equal(true);
done();
});
});
});
The first unit tests is ok. The instance is not added because the uuid field is required.
The second, is the problem. The instance is added to database, but the catch instruction return always the same error:
{ [AssertionError: expected true to equal false]
message: 'expected true to equal false',
showDiff: true,
actual: true,
expected: false }
Already tested with the same results:
usersDB.build(userData).save().then(...).catch(...);
usersDB.create(userData).then(...).catch(...);
What i'm doing wrong? Is because i'm using promises with callbacks?
Is not the isUUID validation, i already try to remove it.
I suppose, the problem is related to async execution. While first test isn't finished, userData.uuid gets value by second. Try to define and pass another user data in second test:
it('Add new User', function(done){
var correctUserData = {
uuid: uuid.v4(),
username: "manuerumx"
};
userCtrl.userCreate(correctUserData, function(isOk, response){
chai.expect(isOk).to.equal(true);
done();
});
});

Mongoose save function doesn't execute

I am trying to save my model into the my db in MongoDB. This code actually works if I were to go through this code path when running the node server, however when I try to use mocha to test saving the model it doesn't get saved anymore. I have verified that the connection to mongodb is fine. Thia is the output:
before regular save
after regular save
Any tips or suggestions would be greatly appreciated. thanks!
This is the test I am running.
var app = require('./helpers/app');
var User = require('../models/user');
var supertest = require('supertest');
var should = require('should');
var mongoose = require('mongoose');
var MongoUrl = require('./../config.js').mongoUri
var clearDB = require('mocha-mongoose')(MongoUrl);
var testuser = {
username:"admin1",
password:"password",
email:"test#gmail.com",
firstname:"testfirst",
lastname:"testlast",
phonenumber:"4151231234"
};
describe("Routing", function() {
describe("Creating an account", function() {
//To run before each test. DB Clean up is implicitly done after each test.
beforeEach(function(done) {
if (mongoose.connection.db) {
return done();
}
mongoose.connect(dbURI, done);
});
it('User: Creating an account2', function(done){
var newUser = new User({
username: "testusername",
email: "test1#gmail.com",
password: "password",
phoneNumber: "12312312",
firstname: "testfirst",
lastname: "testlast"
});
console.log("before regular save");
newUser.save(function(err){
if(err){
console.log("testerror: " + err);
}
console.log("in regular save");
});
console.log("after regular save");
User.find({}, function(err, docs){
if (err) return done(err);
console.log(docs);
docs.length.should.equal(1);
done();
});
});
});
});
Model#save is an async function so you have to wait until it calls its callback before you can expect to be able to find the saved doc with a Model.find call.
So put the find check inside the save callback:
it('User: Creating an account2', function(done){
var newUser = new User({
username: "testusername",
email: "test1#gmail.com",
password: "password",
phoneNumber: "12312312",
firstname: "testfirst",
lastname: "testlast"
});
console.log("before regular save");
newUser.save(function(err){
if(err){
console.log("testerror: " + err);
return done(err);
}
console.log("in regular save");
console.log("after regular save");
User.find({}, function(err, docs){
if (err) return done(err);
console.log(docs);
docs.length.should.equal(1);
done();
});
});
});

What's wrong with my mocha test?

I have written this code in express.js and mongoose
routes.js
var mongoose = require('mongoose'),
logger = require('../logger');
mongoose.connection.on('error', function(){
logger.info('Mongoose connection error' + error);
});
exports.getitems = function(req, res) {
mongoose.connect('mongodb://localhost/abhitest', {auto_reconnect: true, native_parser: true}, function(err){
if (err) logger.error("Error " + err);
});
var Schema = mongoose.Schema;
var User = new Schema({
username : {type: String, required: true},
email : {type: String, required: true}
}, {collection: 'User'});
var UserModel = mongoose.model('User', User, 'User');
UserModel.find({}, function(err, users){
if (!err) {
logger.info('found ' + users);
res.json(200, users);
} else {
logger.error(err);
res.json(404, 'did not find anything');
}
});
};
app.js
var mongoose = require('mongoose'),
express = require('express'),
app = express(),
routes = require('./routes'),
http = require('http');
app.get('/', routes.getitems);
http.createServer(app).listen(3000);
module.exports = app;
When I execute this from the browser. I can see that it returns results correctly from my mongo db.
But when I write this mocha test case for the same code
var app = require('../app'),
request = require('supertest'),
assert = require('assert'),
_ = require('underscore');
describe('when the test runs', function() {
it ('should insert 3 records in mongo db', function(done){
request(app)
.get('/')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res){
if (err) console.log(err);
else {
console.log(res.text);
var items = JSON.parse(res.text);
for(var i = 0; i < items.length; i++) {
var item = items[i];
assert(_.has(item, 'username'));
assert(_.has(item, 'email'));
console.log(item.username);
console.log(item.email);
}
}
});
done();
});
});
The test case output is just
․
1 passing (18ms)
So I am very sure that it doesn't even go inside the end method and it doesn't print anything inside the end method.
I can see that the call goes to the server but it never establishes the connection with mongo. it just hangs as readyState of 2.
So somehow when the test is executing via mocha... it never connects to mongo and is hung on connecting. but when the code is executed via npm start... everything works fine.
What is going wrong with mocha test case?
Your done() call needs to be made from within the request callback:
describe('when the test runs', function() {
it ('should insert 3 records in mongo db', function(done){
request(app)
.get('/')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res){
if (err) console.log(err);
else {
console.log(res.text);
var items = JSON.parse(res.text);
for(var i = 0; i < items.length; i++) {
var item = items[i];
assert(_.has(item, 'username'));
assert(_.has(item, 'email'));
console.log(item.username);
console.log(item.email);
}
}
return done();
});
});
});
As it is currently, you call done() before your request is finished.

Resources