Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test method in controller in sails.js using Mocha + Sinon?

I'm new to testing and trying to understand how to go about testing a fairly simple controller action. The problem that I am encountering is not knowing how to accomplish mocking up the methods that are inside the controller, or even to think about when it is appropriate to do so.

The action creates a pending user in the db of my webapp and returns a join link. It looks like this:

module.exports = {

    create: function(req, res, next) {

        var name,
            invitee = req.allParams();

        if ( _.isEmpty(invitee) || invitee.name === undefined) {
            return res.badRequest('Invalid parameters provided when trying to create a new pending user.');
        }

        // Parse the name into its parts.
        name = invitee.name.split(' ');
        delete invitee.name;
        invitee.firstName = name[0];
        invitee.lastName = name[1];

        // Create the pending user and send response.
        PendingUser.create(invitee, function(err, pending) {
            var link;

            if (err && err.code === 'E_VALIDATION') {
                req.session.flash = { 'err': err };
                return res.status(400).send({'err':err});
            }

            // Generate token & link
            link = 'http://' + req.headers.host + '/join/' + pending.id;

            // Respond with link.
            res.json({'joinLink': link});
       });

    }

}

The test that I have written for this method looks like this:

'use strict';
/**
 * Tests for PendingUserController
 */

var PendingUserController = require('../../api/controllers/PendingUserController.js'),
        sinon = require('sinon'),
        assert = require('assert');

describe('Pending User Tests', function(done) {

    describe('Call the create action with empty user data', function() {
        it('should return 400', function(done) {

            // Mock the req object.
            var xhr = sinon.useFakeXMLHttpRequest();
            xhr.allParams = function() {
                return this.params;
            };
            xhr.badRequest
            xhr.params = generatePendingUser(false, false, false, false);

            var cb = sinon.spy();

            PendingUserController.create(xhr, {
              'cb': cb
            });
            assert.ok(cb.called);
        });
    });
}

function generatePendingUser(hasName, hasEmail, hasAffiliation, hasTitle) {
    var pendingUser = {};

    if (hasName) pendingUser.name = 'Bobbie Brown';
    if (hasEmail) pendingUser.emailAddress = '[email protected]';
    if (hasAffiliation) pendingUser.affiliation = 'Very Exclusive University';
    if (hasTitle) pendingUser.title = "Assistant Professor";

    return pendingUser;
}

My test is still incomplete because of the snag I have hit. As you can see from the test, I've attempted to mock the request object as well as the first method that is called in the controller action req.allParams(). But the second method that is potentially called in the controller is res.badRequest(), which is a function built into the res object within sails.js.

This function I do not know how to mock up. Moreover, thinking about mocking up this function raises all sorts of other questions. Why am I mocking up this function in the first place? The logic of unit testing is, I think, that you test parts of your code in isolation with others, but isn't this going a bit far? It also generates a whole lot of extra work because I would need to simulate the behavior of this function, which may or may not be simple to accomplish.

The code I've written here is based on a couple of proof-of-concept type tutorials (see here, here, and here), but these posts do not deal with the problem in which you have methods on the req and/or res objects in the controller.

What is the right way to approach a solution here? Any insight would be greatly appreciated!

like image 535
fraxture Avatar asked Apr 19 '15 14:04

fraxture


1 Answers

You are trying to test a create action on pending user controller and assert it's response/behavior. What you can do is actually make a request with Supertest to test it.

I am assuming you have already bootstrapped your test with Mocha & should.js.

 var request = require('supertest');

 describe('PendingUsersController', function() {

  describe('#create()', function() {
     it('should create a pending user', function (done) {
       request(sails.hooks.http.app)
         .post('/pendinguser') 
         //User Data
         .send({ name: 'test', emailAdress: '[email protected]', affiliation: 'University of JavaScript', title: 'Software Engineer' })
         .expect(200)
         .end(function (err, res) {
              //true if response contains { message : "Your are pending user."}
              res.body.message.should.be.eql("Your are pending user.");
         });
      });
    });
 });

More on controller testing Sails.js from docs or look at this example project for more.

like image 150
Sabbir Avatar answered Oct 16 '22 02:10

Sabbir