Mongodb testing in Node - node.js

I have been using Mocha for testing in Node because it seems to be what most people use. I am also using MongoDB to store my data and since my server is a simple API server pretty much all of my methods are just plain database queries which I am trying to test with Mocha.
Now the Issue that I am facing is that (besides the fact that it seems to be quite hard to test async functions in general) I can not seem to find a proper way to test for a mongoDB excpetion.
it('Should not create account', async (done) => {
try {
await createAccountDB(user);
await createAccountDB(user);
} catch (err) {
assert.notEqual(err, null);
console.log(err);
}
finally {
done();
}
});
});
What I am trying here is to create an account for a User (Basically just saving the Object to the db) and then creating the same account again which should result in a duplicate key error.
Now, this doesn't work and as far as I can tell that is because i have defined both async and done. The reason why I did this is, if I don't define async I would need to have a whole bunch of .then and .catches which would make the code look horrible but if I don't include then done() in the finally block, my test seems to never even make it to the catch block.
Is there any way to write tests like these in Mocha which don't make your code look absouletly horrible?

Since you're already using the async/await model you don't necessarily need the done callback for the test case. Certain versions of mocha will warn you when you have more than one means of indicating test completion. Try this:
it('should not create an account', async function() {
try {
await createAccountDB(user);
await createAccountDB(user);
throw new Error('Did not reject a duplicate account');
} catch (err) {
assert.notEqual(err, null);
// any other assertions here
}
});
The error thrown in the try/catch block is very important - without it, the test will still pass even if the error is not thrown.

Related

How can I test that a promise have been waited for (and not just created) using Sinon?

Let's say I have a function:
const someAction = async(): Promise<string> => {
/* do stuff */
};
And I have some code that just needs to run this action, ignoring the result. But I have a bug - I don't want for action to complete:
someAction();
Which, instead, should've been looked like this:
await someAction();
Now, I can check that this action was ran:
const actionStub = sinon.stub(someAction);
expect(actionStub).to.have.been.calledWith();
But what's the most concise way to check that this promise have been waited on?
I understand how to implement this myself, but I suspect it must have already been implemented in sinon or sinon-chai, I just can't find anything.
I can certainly say that nothing like this exists in sinon or sinon-chai.
This is a difficulty inherent to testing any promise-based function where the result isn't used. If the result is used, you know the promise has to be resolved before proceeding with said result. If it is not, things get more complex and kind of outside of the scope of what sinon can do for you with a simple stub.
A naive approach is to stub the action with a fake that sets some variable (local to your test) to track the status. Like so:
let actionComplete = false;
const actionStub = sinon.stub(someAction).callsFake(() => {
return new Promise((resolve) => {
setImmediate(() => {
actionComplete = true;
resolve();
});
});
});
expect(actionStub).to.have.been.calledWith();
expect(actionComplete).to.be.true;
Of course, the problem here is that awaiting any promise, not necessarily this particular one, will pass this test, since the variable will get set on the next step of the event loop, regardless of what caused you to wait for that next step.
For example, you could make this pass with something like this in your code under test:
someAction();
await new Promise((resolve) => {
setImmediate(() => resolve());
});
A more robust approach will be to create two separate tests. One where the promise resolves, and one where the promise rejects. You can test to make sure the rejection causes the containing function to reject with the same error, which would not be possible if that specific promise was not awaited.
const actionStub = sinon.stub(someAction).resolves();
// In one test
expect(actionStub).to.have.been.calledWith();
// In another test
const actionError = new Error('omg bad error');
actionStub.rejects(actionError);
// Assuming your test framework supports returning promises from tests.
return functionUnderTest()
.then(() => {
throw new Error('Promise should have rejected');
}, (err) => {
expect(err).to.equal(actionError);
});
Some assertion libraries and extensions (maybe chai-as-promised) may have a way of cleaning up that use of de-sugared promises there. I didn't want to assume too much about the tools you're using and just tried to make sure the idea gets across.

Using async-await to execute a task AFTER dropping a collection from mongodb database

I am trying to use async await to execute an http request before executing some other code.
More precisely, I would like to drop a collection in my mongodb database, before executing some others tasks. Here's what I did:
app.component.ts:
async deleteRiskRatingData2() {
await this.saveInformationService
.deleteRiskRatingInformation()
.subscribe((data: string) => {
console.log('Deleting risk Rating');
console.log(this.riskRatingTable);
});
console.log('TASKS TO BE EXECUTED AFTER DROPIING COLLECTION');
}
save-information.service.ts
deleteRiskRatingInformation() {
console.log('INIDE deleteRiskRatingInformation INSIDE SAVE-INFORMATION.SERVICE');
return this.http.get(`${this.uri}/dropRiskRatingCollection`);
}
In the backend:
server.js
router.route('/dropRiskRatingCollection').get((req, res) => {
RiskRating.remove({},(err) => {
if (err)
console.log(err);
else
res.json("Risk Rating Collection has been dropped!");
});
});
And this is what happens:
I though my implementation of Async/Await should allow me to execute the:
console.log('TASKS TO BE EXECUTED AFTER DROPPING COLLECTION');
After the dropping of the collection request has been executed. But that didn't happen as you see. And I really don't understand why.
Any idea why is this happening? Is my logic flawed somewhere? And how can I achieve my goal?
Thank you!
async-await work only with Promises. You're try them with Observables. That won't work. Observables have an API that let's you convert them into Promises though. You can call a toPromise method on them in order to do that.
Try this:
async deleteRiskRatingData2() {
const data = await this.saveInformationService.deleteRiskRatingInformation().toPromise();
console.log('Deleting risk Rating');
console.log(this.riskRatingTable);
console.log('TASKS TO BE EXECUTED AFTER DROPIING COLLECTION');
}
NOTE: It's fine if you're trying this just for the sake of testing it. But I think you should not really switch back to promises just to use async-await, to make your code look synchronous.

How to return promise to the router callback in NodeJS/ExpressJS

I am new to nodejs/expressjs and mongodb. I am trying to create an API that exposes data to my mobile app that I am trying to build using Ionic framework.
I have a route setup like this
router.get('/api/jobs', (req, res) => {
JobModel.getAllJobsAsync().then((jobs) => res.json(jobs)); //IS THIS THe CORRECT WAY?
});
I have a function in my model that reads data from Mongodb. I am using the Bluebird promise library to convert my model functions to return promises.
const JobModel = Promise.promisifyAll(require('../models/Job'));
My function in the model
static getAllJobs(cb) {
MongoClient.connectAsync(utils.getConnectionString()).then((db) => {
const jobs = db.collection('jobs');
jobs.find().toArray((err, jobs) => {
if(err) {
return cb(err);
}
return cb(null, jobs);
});
});
}
The promisifyAll(myModule) converts this function to return a promise.
What I am not sure is,
If this is the correct approach for returning data to the route callback function from my model?
Is this efficient?
Using promisifyAll is slow? Since it loops through all functions in the module and creates a copy of the function with Async as suffix that now returns a promise. When does it actually run? This is a more generic question related to node require statements. See next point.
When do all require statements run? When I start the nodejs server? Or when I make a call to the api?
Your basic structure is more-or-less correct, although your use of Promise.promisifyAll seems awkward to me. The basic issue for me (and it's not really a problem - your code looks like it will work) is that you're mixing and matching promise-based and callback-based asynchronous code. Which, as I said, should still work, but I would prefer to stick to one as much as possible.
If your model class is your code (and not some library written by someone else), you could easily rewrite it to use promises directly, instead of writing it for callbacks and then using Promise.promisifyAll to wrap it.
Here's how I would approach the getAllJobs method:
static getAllJobs() {
// connect to the Mongo server
return MongoClient.connectAsync(utils.getConnectionString())
// ...then do something with the collection
.then((db) => {
// get the collection of jobs
const jobs = db.collection('jobs');
// I'm not that familiar with Mongo - I'm going to assume that
// the call to `jobs.find().toArray()` is asynchronous and only
// available in the "callback flavored" form.
// returning a new Promise here (in the `then` block) allows you
// to add the results of the asynchronous call to the chain of
// `then` handlers. The promise will be resolved (or rejected)
// when the results of the `job().find().toArray()` method are
// known
return new Promise((resolve, reject) => {
jobs.find().toArray((err, jobs) => {
if(err) {
reject(err);
}
resolve(jobs);
});
});
});
}
This version of getAllJobs returns a promise which you can chain then and catch handlers to. For example:
JobModel.getAllJobs()
.then((jobs) => {
// this is the object passed into the `resolve` call in the callback
// above. Do something interesting with it, like
res.json(jobs);
})
.catch((err) => {
// this is the error passed into the call to `reject` above
});
Admittedly, this is very similar to the code you have above. The only difference is that I dispensed with the use of Promise.promisifyAll - if you're writing the code yourself & you want to use promises, then do it yourself.
One important note: it's a good idea to include a catch handler. If you don't, your error will be swallowed up and disappear, and you'll be left wondering why your code is not working. Even if you don't think you'll need it, just write a catch handler that dumps it to console.log. You'll be glad you did!

node.js sails.js waterline bluebird .then and .spread

I am trying to figure out how promises work in sails, and have been successful passing data from waterline queries via .then, but have not been able to utilize .spread. I am getting a function not defined error. Any suggestions how the first section of code can be improved to work?
//results in error
Promise.all([Xyz.find(), Abc.find()]).spread(function (someOtherResult, yetAnotherResult) {
console.log(someOtherResult)
}).catch(function (err) {
console.log(err);
})
The following work but would be either trickier to extract data from, or require excessively long nested .then clauses:
Promise.all([Xyz.find(), Abc.find()]).then(function (results) {
console.log(results[0][1]);
console.log(results[0].length);
})
Abc.find().then(function (foundAbcs) {
Promise.all(Xyz.find().then(function (foundXyzs) {
console.log(foundAbcs);
console.log(foundXyzs);
// additional syncranouse logic with Abc and Xyz
}))
})
Okay, very simple mistake, I didn't realize I needed:
var Promise = require('bluebird');
prior to module.exports in sails.js .11, problem solved.

Having trouble understanding how the pre() function in Mongoose is working in this code snippet

I am learning how to make web apps with node.js. I have been following the tutorial provided by Alex Young. I am having trouble understanding how the pre() function works in Mongoose. I have read the Mongoose API documentation and understand that it is a way of "chaining" functions to an existing one, but I do not understand how it is actually working when I look at a code example (see below code snippets).
My question is what is going on in the here? There are three functions involved here (userSaved(), userSaveFailed(), and the password validation function defined in the pre() function). How are these function related to each other in terms of order in which they run? Is the actual saving of the document into the database completed before userSaved() and userSavedFail() are run?
I admit that my lack of understanding understanding may be due to my lack of knowledge on javascript (I come from a PHP background), but I just can't follow what is going on in this code.
Modified save behavior define in models.js :
User.pre('save', function(next) {
if (!validatePresenceOf(this.password)) {
// Through error if password fails validation.
next(new Error('Invalid password'));
}
else {
next();
}
});
Call to save data to database from app.js :
app.post('/users.:format?', function(req, res) {
var user = new User(req.body.user);
function userSaved() {
switch (req.params.format) {
case 'json':
res.send(user.__doc);
break;
default:
req.session.user_id = user.id;
res.redirect('/documents');
}
}
function userSaveFailed() {
res.render('users/new.jade', {
locals: { user: user }
});
}
user.save(userSaved, userSaveFailed);
});
In my opinion,the function followed by "save", is the method which gets executed before the save function is called(as the function name "PRE" imply).
The first function that is ran is user.save() passing in two callbacks, one for if user.save() completes without errors (userSaved) and another if it fails (userSavedFailed)
User.pre('save', function(next) {
if (!validatePresenceOf(this.password)) {
// Through error if password fails validation.
next(new Error('Invalid password'));
}
else {
next();
}
});
This code is running a set of asynchronous functions in parallel, only returning a response once all the functions have completed. In this case it returns by calling a callback function (userSaved or UserSavedFailed). Which is called depends on whether there was an error during the process of any of the functions.
The Async Module also chains functions and allows them to run synchronously or in parallel and may provide some examples of how this is accomplished to help you better understand what's actually happening.

Resources