Mocha Unit Test Error Handling from Library - javascript

I have the following code below that basically gets a user from a database. The code below is using Dynamoose but I'm assuming there is something similar in many other libraries and packages.
User.get(searchid, function(err, user) {
if (err) {
console.log(err);
return res.send('error');
} else {
//DO LOGIC
}
});
I have written unit tests to handle all the logic inside the else statement above. But I'm trying to figure out if there is a way to write unit tests to handle the if (err) section of the code. Basically I want to write unit tests to make sure that if there is an error it returns the correct stuff tho I would be up for any suggestions of other tests I should write. How can I write tests in this case and cover this code with unit tests?

You should mock User.get to make it execute the callback directly, with the parameters you want.
To do that, you may have multiple possibility depending on your test setup.
I use rewire https://github.com/jhnns/rewire
If your code look like :
//myCode.js
var User = require('./model/User');
module.exports = function(){
User.get(searchid, function(err, user) {
if (err) {
console.log(err);
return res.send('error');
} else {
//DO LOGIC
}
});
}
Basicaly your test look like :
var myCode = rewire("../lib/myCode.js");
...
var UserMock = {
get: function (searchid, cb) {
cb(new Error(), null);
}
};
myCode.__set__("User", UserMock);
myCode.myFunctionCallingUserGet(function (err, data) {
// Test that you send error.
});

Related

Make SQLite errors specific and not just SQLITE_ERROR in express/node.js

So basically I have a similar block written in Express:
var sqlite3 = require('sqlite3');
const data = {};
const db = new sqlite3.Database("sqlite/test.db");
db.run("INSERT INTO [Employees]([Name]) VALUES(?)", [name], function (err) {
if (err) { //this is the error block
data.error = err.code;
data.status = 0;
}
else { //this is the success block
data.data = { Name: name, Id: this.lastID };
data.status = 1;
}
db.close();
res.send(data);
});
This does what it looks like, just a simple insert statement and its callback. The update, select and delete operations are literally all the same.
But whenever I get errors (syntax error, missing fields, missing tables, yada yada), I always just get {errNo: 0, code: "SQLITE_ERROR"} in my err argument, which is annoyingly unspecific and unhelpful.
Is there a way to fix the error handling and make it not insanity inducing?
This is the closest thing I found to documentation on the error object. You probably want to look at err.message.

Should testing, Javascript webservice API

I am testing my REST API with should.
At the moment i have tested my methods to work as intended via the browser, and console testing.
My test cases are turning out to work just fine when testing with should, on the GET methods from my API.
Are there any way to test the delete and post methods in should, og would i be better of to use another testing enviroment ?
Following is a snippet from my API
router.delete('/deleteProfile/:id', function (req, res) {
var toDelete = req.params.id;
dataLayer.deleteProfile(toDelete, function (err, result) {
if(err) res.status(500).send('Person + ' + toDelete+ ' not deleted')
else{
console.log(result);
res.json(result);
}
});
Following is a snippet of my test :
it("Should delete the user With the userName FrækFyr91", function (done) {
http.get("http://localhost:"+testPort+"/profileApi/deleteProfile/FrækFyr91",function(res){
res.setEncoding("utf8");//response data is now a string
res.on("data",function(chunk){
var n = JSON.parse(chunk);
n.length.should.equal(4);
done();
});
})
});
I know the http.delete wont work.
Any suggestions ?
Rather than using http, I'd recommend using one of the specialized REST client libs, like restler, which are specifically designed to communicate with RESTful routes.
You might also consider using chai for your testing assertions as it provides very comprehensive BDD-style assertions.
So instead of your:
http.get(endpointUrl,function(res){
res.on('data',...);
});
I'd use:
var mocha=require('mocha'),
should=require('chai').should(),
client=require('restler');
describe('deletions',function(){
it('should delete something',function(done){
client.del(deleteEndpointUrl).on('complete',function(result){
// if the request failed, result will be an Error
if(result instanceof Error) {
return done(result); // return error
}
// test result here
result.should.be.an.object; // chai.should extends objects with assertions
// etc.
done();
});
});
});

NodeJS - waterline best way to do 4 consecutive collections counts

I want to create a dashboard where I'll be showing simple stats like count of users, count of comments etc.
I am counting my collections using something like
User.count(function(err, num){
if (err)
userCount=-1;
else
userCount = num;
Comment.count(function(err, num){
if (err)
commentCount=-1;
else
commentCount = num;
SomethingElse.count(...)
})
})
which is a bit ugly I think. Is there any other way to do it without nesting 4 counts?
You can take advantage of a module like async to do you want in a more readable way. The module is globalized by Sails by default, meaning it's available in all of your custom code. Using async.auto, you would rewrite the above as:
async.auto({
user: function(cb) {User.count.exec(cb);},
comment: function(cb) {Comment.count.exec(cb);},
somethingElse: function(cb) {SomethingElse.count.exec(cb);},
anotherThing: function(cb) {AnotherThing.count.exec(cb);}
},
// The above 4 methods will run in parallel, and if any encounters an error
// it will short-circuit to the function below. Otherwise the function
// below will run when all 4 are finished, with "results" containing the
// data that was sent to each of their callbacks.
function(err, results) {
if (err) {return res.serverError(err);}
// results.user contains the user count, results.comment contains
// comments count, etc.
return res.json(results);
}
);

How do I run an asynchronous 'find' in a loop while incrementing the find parameter so I can generate unique custom id's?

I'm new to mongoose/mongodb and I am trying to do some sort of error handling with my document save.
I am trying to create a stub id to store into the db for easier data retrieval later on (and also to put into the url bar so people can send links to my website to that particular page more easily -- like jsfiddle or codepen).
Basically I want to search for a document with a page_id and if it exists, I want to regenerate that page_id and search until it gets to one that's unused like this:
while(!done){
Model.findOne({'page_id': some_hex}, function (err, doc) {
if(doc){
some_hex = generate_hex();
}
else
{
done = true;
}
});
}
model.page_id = some_hex;
model.save();
However, since mongoose is asynchronous, the while loop will pretty much run indefinitely while the find works in the background until it finds something. This will kill the resources on the server.
I'm looking for an efficient way to retry save() when it fails (with a change to page_id). Or to try and find an unused page_id. I have page_id marked as unique:true in my schema.
Retrying should be performed asynchronously:
var tryToSave = function(doc, callback) {
var instance = new Model(doc);
instance.page_id = generate_hex();
instance.save(function(err) {
if (err)
if (err.code === 11000) { // 'duplicate key error'
// retry
return tryToSave(doc, callback);
} else {
// another error
return callback(err);
}
}
// it worked!
callback(null, instance);
});
};
// And somewhere else:
tryToSave(doc, function(err, instance) {
if (err) ...; // handle errors
...
});

Flattening out nested callback

I have frustrating problem with learning to work with callback style of programming in Node.js. I have a query to a MongoDB database. If I pass in a function to execute on the result it works but I'd rather flatten it out and have it return the value. Any help or direction on how to do this correctly is appreciated. Here's my code:
var getLots = function(response){
db.open(function(err, db){
db.collection('lots', function(err, collection){
collection.find(function(err, cursor){
cursor.toArray(function(err, items){
response(items);
})
})
})
})
}
I want something more like this:
lots = function(){
console.log("Getting lots")
return db.open(openCollection(err, db));
}
openCollection = function(err, db){
console.log("Connected to lots");
return (db.collection('lots',findLots(err, collection))
);
}
findLots = function(err, collection){
console.log("querying 2");
return collection.find(getLots(err, cursor));
}
getLots = function(err, cursor) {
console.log("Getting lots");
return cursor.toArray();
}
Where the final set of data would bubble back up through the function calls.
The problem is that I get an error from Node.js saying that err is not defined or that the collection is not defined. For some reason when I nest the callbacks the correct object is getting passed down. When I try going to this flattened style it complains that things are not defined. I don't know how to get it to pass the necessary objects.
What you need is one of the many control flow libraries available for node via npm and catalogued on the Node.js wiki. My specific recommendation is caolan/async, and you would use the async.waterfall function to accomplish this type of flow where each async operation must be executed in order and each requires the results from the previous operation.
Pseudocode example:
function getLots(db, callback) {
db.collection("lots", callback);
}
function findLots(collection, callback) {
collection.find(callback);
}
function toArray(cursor, callback) {
cursor.toArray(callback);
}
async.waterfall([db.open, getLots, find, toArray], function (err, items) {
//items is the array of results
//Do whatever you need here
response(items);
});
async is a good flow control library. Frame.js offers some specific advantages like better debugging, and better arrangement for synchronous function execution. (though it is not currently in npm like async is)
Here is what it would look like in Frame:
Frame(function(next){
db.open(next);
});
Frame(function(next, err, db){
db.collection('lots', next);
});
Frame(function(next, err, collection){
collection.find(next);
});
Frame(function(next, err, cursor){
cursor.toArray(next);
});
Frame(function(next, err, items){
response(items);
next();
});
Frame.init();

Categories

Resources