4

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.

0x9BD0
  • 1,542
  • 18
  • 41

2 Answers2

1

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);

        });
   });
});
lukaszfiszer
  • 2,591
  • 1
  • 19
  • 13
  • I still get the error. It makes sens for the end function! I will integrate it in the final solution... – 0x9BD0 Nov 08 '14 at 16:53
1

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.

Charlie Dalsass
  • 1,986
  • 18
  • 23