In an application built with Node.js (CompoundJS + PassportJS), how can the Mocha tests be run on the controllers that are locked down and require login? I have tried using Superagent but am not having much luck and to use it the server needs to be running to run the tests. I've gotten very close with this method, but don't want to have to have the server running to run unit tests.
I also tried including passport and using request.login
method, I ended up at a point where I kept getting the error passport.initialize()
middleware not in use.
I am trying to stick with the generated CompoundJS tests which were working great until the authentication got involved. The default CompoundJS tests run an init.js
file which would be nice to handle the authentication in and somehow make available to each controller test:
require('should');
global.getApp = function(done) {
var app = require('compound').createServer()
app.renderedViews = [];
app.flashedMessages = {};
// Monkeypatch app#render so that it exposes the rendered view files
app._render = app.render;
app.render = function(viewName, opts, fn) {
app.renderedViews.push(viewName);
// Deep-copy flash messages
var flashes = opts.request.session.flash;
for (var type in flashes) {
app.flashedMessages[type] = [];
for (var i in flashes[type]) {
app.flashedMessages[type].push(flashes[type][i]);
}
}
return app._render.apply(this, arguments);
}
// Check whether a view has been rendered
app.didRender = function(viewRegex) {
var didRender = false;
app.renderedViews.forEach(function(renderedView) {
if (renderedView.match(viewRegex)) {
didRender = true;
}
});
return didRender;
}
// Check whether a flash has been called
app.didFlash = function(type) {
return !!(app.flashedMessages[type]);
}
return app;
};
controllers/users_controller_test.js
var app,
compound,
request = require('supertest'),
sinon = require('sinon');
/**
* TODO: User CREATION and EDITs should be tested, with PASSPORT
* functionality.
*/
function UserStub() {
return {
displayName: '',
email: ''
};
}
describe('UserController', function() {
beforeEach(function(done) {
app = getApp();
compound = app.compound;
compound.on('ready', function() {
done();
});
});
/**
* GET /users
* Should render users/index.ejs
*/
it('should render "index" template on GET /users', function(done) {
request(app)
.get('/users')
.end(function(err, res) {
res.statusCode.should.equal(200);
app.didRender(/users\/index\.ejs$/i).should.be.true;
done();
});
});
/*
* GET /users/:id
* Should render users/index.ejs
*/
it('should access User#find and render "show" template on GET /users/:id',
function(done) {
var User = app.models.User;
// Mock User#find
User.find = sinon.spy(function(id, callback) {
callback(null, new User);
});
request(app)
.get('/users/42')
.end(function(err, res) {
res.statusCode.should.equal(200);
User.find.calledWith('42').should.be.true;
app.didRender(/users\/show\.ejs$/i).should.be.true;
done();
});
});
});
These all fail with either AssertionError: expected 403 to equal 200
or AssertionError: expected false to be true
I used a combination of mocking passport.initialize, a test helper, and a listener on the compound configure event.
This provided two things:
beforeEach
code across controller tests.In test/init.js I added the method to mock passport.initialize**:
** Found it at:
http://hackerpreneurialism.com/post/48344246498/node-js-testing-mocking-authenticated-passport-js
Then I added a helpers.js file to be called in each controller:
This will be called in the
beforeEach
of each controller: