Node Express testing mock res.status(status).json(obj) - node.js

I get the following error when trying to test my method:
TypeError: Cannot call method 'json' of undefined
Below is my code, i'd get the same error for 'status' if i remove res.status from the test method.
How do i define 'json' so i dont get an exception thrown at:
res.status(404).json(error);
when testing this function.
stores.js
{ //the get function declared above (removed to ease of reading)
// using a queryBuilder
var query = Stores.find();
query.sort('storeName');
query.exec(function (err, results) {
if (err)
res.send(err);
if (_.isEmpty(results)) {
var error = {
message: "No Results",
errorKey: "XXX"
}
res.status(404).json(error);
return;
}
return res.json(results);
});
}
storesTest.js
it('should on get call of stores, return a error', function () {
var mockFind = {
sort: function(sortOrder) {
return this;
},
exec: function (callback) {
callback('Error');
}
};
Stores.get.should.be.a["function"];
// Set up variables
var req,res;
req = {query: function(){}};
res = {
send: function(){},
json: function(err){
console.log("\n : " + err);
},
status: function(responseStatus) {
assert.equal(responseStatus, 404);
}
};
StoresModel.find = sinon.stub().returns(mockFind);
Stores.get(req,res);

The status method happens to be a chainable method. The convention for chainable methods is to always return this at the end. In your tests, you mock up the res.status method but forgot to return this;.
res = {
send: function(){ },
json: function(err){
console.log("\n : " + err);
},
status: function(responseStatus) {
assert.equal(responseStatus, 404);
// This next line makes it chainable
return this;
}
}

Related

node.js API respond not terminated "can't sent headers after they are sent."

The first request works fine, but after another request I got this Error Message. My logic does not double request, but it looks like, that each route isn't called seperately.
So the first request to /api/user works fine. After a refresh I got the error Can't set headers after they are sent.
res.end() doesn't produce any error.
res.send() and res.json() and res.header('Content-Type', 'application/json'); res.end(); will produce errors on a refresh.
In another API res.json() works fine, but there is no use of classes/functions nor EventEmitter. Maybe the problem is there?
routes.js
route.get("/", function(req, res) {
user.on('error', function(err) {
res.status(400).send({code: 900, message: err, data: null});
});
user.on('success', function(result) {
res.status(200).send({code: 200, message: 'OK', data: result});
});
user.getAll();
});
user.js
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var initialize = require(global.__base + "/config");
var db = initialize.db();
function User() {
var self = this;
this.get = get;
function _checkForErrors(error, rows, reason) {
if (error) {
self.emit('error', error);
return true;
} else if (reason) {
self.emit('failure', reason);
return true;
}
return false;
}
function _getData(error, rows) {
if (_checkForErrors(error, rows)) {
return false;
} else {
self.emit('success', rows);
return true;
}
}
function getAll() {
db.query("SELECT * FROM patient", _getData);
}
}
util.inherits(User, EventEmitter);
module.exports = User;
db init
module.exports = {
globalModules: function() { /*foo*/ },
db: function() {
var mysql = require('mysql');
var db = mysql.createPool({
host: 'localhost',
user: 'root',
password: '',
database: 'node_docx'
});
return db;
}
};
you need to return the response, to terminate the process:
route.get("/", function(req, res) {
user.on('error', function(err) {
return res.status(400).send({code: 900, message: err, data: null});
});
user.on('success', function(result) {
return res.status(200).send({code: 200, message: 'OK', data: result});
});
user.getAll();
});
finally I ended up to create a BaseModel which handles the response... every model (like User) will now inherit from this one.
var basemodel = BaseModel.prototype;
function BaseModel() {
self = this;
};
basemodel.sendResponse = function(res, obj) {
if (!res.getHeader('Content-Type')) {
res.header('Content-Type', 'application/json');
}
obj.on('error', function(err) {
return res.status(400).end(JSON.stringify({code: 901, message: err, data: null}));
});
obj.on('failure', function(fail) {
return res.status(400).end(JSON.stringify({code: 902, message: fail, data: null}));
});
obj.on('success', function(result) {
return res.status(200).end(JSON.stringify({code: 200, message: 'OK', data: result}));
});
};

Sinon mocking with Sequelize

I have the following nodejs function using Sequelize:
var processDatabase = function (dbConnection, schema, recordsets) {
var myLogTable = dbConnection.define(schema.tableName, schema.myLogSchema, schema.myLogSchemaIndex);
myLogTable.sync({
force: false,
freezeTableName: true,
logging: console.log
}).then(function () {
console.log('Table synced...');
for (k = 0; k < recordsets.length; k++) {
var query = "Some query";
dbConnection.query(
query, {
type: dbConnection.QueryTypes.SELECT
}
)
.then(function (results) {
console.log('MYSQL Selection Done');
})
.catch(function (err) {
console.log('MYSQL Error: ' + err.message);
});
}
}).catch(function (err) {
console.log('MYSQL Sync Error: ' + err.message);
});
};
I am new to mocking and do not especially know how to test the catch part.
This is my unit test which I can come up with, but I do not know how a call to sync can go to the catch part:
describe('when call processDatabase', function () {
it('should process successfully when sync fails', function (done) {
seqConnection.define = function (tableName, schema, schemaIndex) {
return mockMyLogModel;
};
processProfilesNotMapped(seqConnection, {
tableName: 'SomeTable',
myLogSchema: myLogSchema,
myLogSchemaIndex: myLogSchemaIndex
}, []);
done();
})
});
How would I write my mocking so that I can test both catch and also then so that they can be covered?
You need to defer an exception in your mock, since "sync" is using promises. You can use q library or any other. This way when you execute the sync function it will go to the catch section
Example using q:
describe('when call processDatabase', function () {
it('should process successfully when sync fails', function (done) {
seqConnection.define = function (tableName, schema, schemaIndex) {
const mock = {
sync: function(){
const deferred = q.defer();
deferred.reject(new Error('Some error'));
return deferred.promise;
}
}
return mock;
};
expect(
function(){
cmdManager.execute("getProfileDummy","hosar#gmail.com")
}
).to.throw(Error);
processProfilesNotMapped(seqConnection, {
tableName: 'SomeTable',
myLogSchema: myLogSchema,
myLogSchemaIndex: myLogSchemaIndex
}, []);
done();
})
});

Stubbing a mongoose exec method using Bluebird and sinon in node.js

I have a service layer that calls a database layer where a query is run. I am trying to stub the data layer returning a value but I keep getting this error
TypeError: User.find(...).exec is not a function.
I am using the bluebird module and am also using sinon for stubbing
//Service Layer
var dbLayer = require('../dbLayer');
exports.getUsers = function (req, res) {
dbLayer.GetUsersThatNeedToBeApproved(req.body.domain)
.then(function (data) {
res.json(data);
})
.catch(function(error){
routesLogger.logError(req.session.user.role, "getUsers", error);
res.status(400).send({error: StatusCodes.DBERROR});
});
};
//DB Layer
module.exports.GetUsersThatNeedToBeApproved = function (domain) {
return new Promise.resolve(User.find({$and: [{'domain.upgradeRequest': true}, {'domain.access': constants.ACCESSPRIVATE}, {'domain.name': domain}]}).exec())
.then(function (data) {
return data;
}).catch(function (error) {
routesLogger.logError("userDAL", "GetUsersThatNeedToBeApproved", error);
return error;
});
This is my test case
describe("Suite to get users in portal that need to be approved",function(){
var request = null;
var response = httpMocks.createResponse();
it("Should get a list of all users that need to be approved for a specific domain",function(done){
request = {
session: {
user: {
domain:{
name:'domain'
},
email: 'testUser#test.com',
role: 'Admin'
}
}
};
var expectedFindResponse = [
{
email: "test#xxx.com",
role: "T",
domain:{
upgradeRequest:true,
access:'private',
name:'domain'
}
},
{
"email": "test1#xxx.com",
"role": "T",
domain:{
upgradeRequest:true,
access:'private',
name:'domain'
}
}
];
var find = sinon.stub(mongoose.Model, "find").returns(Promise.resolve(expectedFindResponse));
admin.getUsers(request, response);
var responseData = response._getData();
});
});

Howto test logic inside a callback function with Jasmine and NodeJs to test a Mongoose controller

In the function below I'm retrieving an entity by id from a Mongo DB using Mongoose.
var Recipe = require('models/recipe').model;
exports.findById = function(req, res) {
Recipe.findById(req.params.id, function(err, docs) {
if (err) {
console.error(err);
res.status(500).send(err);
}
res.json(docs);
});
}
I would like to use Jasmine to test if I return a 500 when an error has been raised and I want to test if I put the JSON entity on the reponse when everything was successful.
I solved it by creating a closure containing the callback function, the advantage is that it's also reusable:
exports.jsonCallback = function(res) {
return function(err, docs) {
if (err) {
console.error(err);
res.status(500).send(err);
}
res.json(docs);
}
};
This allowed me to mock the response in a Jasmine test for the closure:
var resMock = {
status : function(status) {
return {
send : function() {}
}
},
json : function(json) {}
};
var mongooseCallback = require('controllers/callbacks/mongooseCallback').jsonCallback(resMock);
describe("when a json callback has been called", function() {
it("should return status 500 when an error has been raised", function() {
var returnStatusMock = { send : function() {}};
var errorMessage = "errorMessage";
spyOn(resMock, 'status').and.returnValue(returnStatusMock);
spyOn(returnStatusMock, 'send');
mongooseCallback(errorMessage, null);
expect(resMock.status).toHaveBeenCalledWith(500);
expect(returnStatusMock.send).toHaveBeenCalledWith(errorMessage);
});
it("should return the corresponding document in a json format", function() {
spyOn(resMock, 'json');
var jsonString = "{ 'name' : 'value' }";
mongooseCallback(null, jsonString);
expect(resMock.json).toHaveBeenCalledWith(jsonString);
});
});

Trouble to synchronise promises in Node.js using Q

I am currently doing an API in Node.JS with the framework Sails.js. I am using promises for the first time and I have some troubles to sync my promises like I want.
My main function is the following :
createCard: function(req, res) {
checkIfUserHasStripeAccount(req.user)
.then(addCreditCardToStripeAccount())
.then(function cardCreated() {
res.send(200, {
msg: 'Card created'
});
})
.catch(function handleError(err) {
res.send(err.httpCode, err.msg);
})
},
Obviously I can't add a credit card to a stripe account if the user doesn't have one.
The function checkIfUserHasStripeAccount() checks if the account exists and if not, create it.
Here is the code for this part :
function checkIfUserHasStripeAccount(user) {
var deferred = q.defer();
if (!user.idStripe) {
createStripeAccountToUser(user)
.then(function(savedUser) {
deferred.resolve(savedUser);
})
.catch(function(err) {
deferred.reject(err);
})
} else {
deferred.resolve(user);
}
return deferred.promise;
}
function createStripeAccountToUser(user) {
var deferred = q.defer();
var jsonUserToCreate = {
description: user.firstname + ' ' + user.surname,
email: user.email
};
stripe.customers.create(jsonUserToCreate, function(err, customer) {
if (err) {
deferred.reject({
httpCode: 500,
msg: 'some error'
});
} else {
user.idStripe = customer.id;
user.save(function(err, savedUser) {
if (err) {
deferred.reject({
httpCode: 500,
msg: 'some error'
});
}
deferred.resolve(savedUser);
});
}
});
return deferred.promise;
}
The problem is that the .then(addCreditCardToStripeAccount()) is executed before checkIfUserHasStripeAccount() is finished.
I can't figure out why. I thought the .then(addCreditCardToStripeAccount()) would only be executed if it received a reject or resolve.
You are correct in your line of thought.
The problem is that you are invoking your function instead of referencing it:
.then(addCreditCardToStripeAccount())
should be:
.then(addCreditCardToStripeAccount)
I expect this to work:
createCard: function (req, res) {
checkIfUserHasStripeAccount(req.user)
.then(addCreditCardToStripeAccount)
.then(function cardCreated(){
res.send(200, {msg: 'Card created'});
})
.catch(function handleError(err) {
res.send(err.httpCode, err.msg);
})
},
For future, note that the () after the function name invokes the function, as order of execution in JS will evaluate it first due to being inside the then's ().
In promise chains, always invoke only the first function. Example:
function first () { /*...*/ } // All return promise.
function second() { /*...*/ }
function third () { /*...*/ }
first() // Invoked
.then(second) // Not invoked. second() will have been bad here.
.then(third);

Resources