diff --git a/index.js b/index.js index 4adb883..2a0501a 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,9 @@ var helpers = require('./lib/helpers'); exports.describe = helpers.describe; exports.it = helpers.it; +exports.call = helpers.call; +exports.before = helpers.before; exports.beforeEach = helpers.beforeEach; +exports.after = helpers.after; +exports.afterEach = helpers.afterEach; exports.TestDataBuilder = require('./lib/test-data-builder'); diff --git a/lib/helpers.js b/lib/helpers.js index 133a13b..faf1bff 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -1,22 +1,51 @@ var _describe = {}; var _it = {}; +var _call = {}; +var _before = {}; var _beforeEach = {}; +var _after = {}; +var _afterEach = {}; var helpers = exports = module.exports = { describe: _describe, it: _it, - beforeEach: _beforeEach + call: _call, + before: _before, + beforeEach: _beforeEach, + after: _after, + afterEach: _afterEach }; var assert = require('assert'); var request = require('supertest'); var expect = require('chai').expect; -_beforeEach.withApp = function(app) { +var _mochaHooks = { + before: before, + beforeEach: beforeEach, + after: after, + afterEach: afterEach +}; + +var apply = function(hooks) { + return function(name, fn) { + hooks.forEach(function(hook) { + helpers[hook][name] = function() { + return fn.apply({ + hook: _mochaHooks[hook], + hookName: hook + }, arguments); + }; + }); + }; +}; + +apply(['before', 'beforeEach']) +('withApp', function(app) { if (app.models.User) { // Speed up the password hashing algorithm app.models.User.settings.saltWorkFactor = 4; } - beforeEach(function() { + this.hook(function() { this.app = app; var _request = this.request = request(app); this.post = _request.post; @@ -24,7 +53,7 @@ _beforeEach.withApp = function(app) { this.put = _request.put; this.del = _request.del; }); -} +}); function mixin(obj, into) { Object.keys(obj).forEach(function(key) { @@ -54,14 +83,14 @@ _describe.instanceMethod = function(methodName, cb) { }); } -_beforeEach.withArgs = function() { +apply(['before', 'beforeEach'])('withArgs', function() { var args = Array.prototype.slice.call(arguments, 0); - beforeEach(function() { + this.hook(function() { this.args = args; }); -} +}); -_beforeEach.givenModel = function(modelName, attrs, optionalHandler) { +apply(['before', 'beforeEach'])('givenModel', function(modelName, attrs, optionalHandler) { var modelKey = modelName; if(typeof attrs === 'function') { @@ -75,7 +104,7 @@ _beforeEach.givenModel = function(modelName, attrs, optionalHandler) { attrs = attrs || {}; - beforeEach(function(done) { + this.hook(function(done) { var test = this; var app = this.app; var model = app.models[modelName]; @@ -108,12 +137,16 @@ _beforeEach.givenModel = function(modelName, attrs, optionalHandler) { }); } -_beforeEach.givenUser = function(attrs, optionalHandler) { +); + +apply(['before', 'beforeEach']) +('givenUser', function(attrs, optionalHandler) { _beforeEach.givenModel('user', attrs, optionalHandler); -} +}); -_beforeEach.givenUserWithRole = function (attrs, role, optionalHandler) { - _beforeEach.givenUser(attrs, function (done) { +apply(['before', 'beforeEach']) +('givenUserWithRole', function (attrs, role, optionalHandler) { + helpers[this.hookName].givenUser(attrs, function (done) { var test = this; test.app.models.Role.create({name: role}, function (err, result) { if(err) { @@ -142,10 +175,11 @@ _beforeEach.givenUserWithRole = function (attrs, role, optionalHandler) { }); if(typeof optionalHandler === 'function') { - beforeEach(optionalHandler); + this.hook(optionalHandler); } - afterEach(function(done) { + var hook = this.hookName.match(/Each$/) ? afterEach : after; + hook(function(done) { var test = this; this.userRole.destroy(function(err) { if(err) return done(err); @@ -158,10 +192,11 @@ _beforeEach.givenUserWithRole = function (attrs, role, optionalHandler) { }); }); }); -} +}); -_beforeEach.givenLoggedInUser = function(credentials, optionalHandler) { - _beforeEach.givenUser(credentials, function(done) { +apply(['before', 'beforeEach']) +('givenLoggedInUser', function(credentials, optionalHandler) { + helpers[this.hookName].givenUser(credentials, function(done) { var test = this; this.user.constructor.login(credentials, function(err, token) { if(err) { @@ -173,7 +208,9 @@ _beforeEach.givenLoggedInUser = function(credentials, optionalHandler) { }); }); - afterEach(function(done) { + var hook = this.hookName.match(/Each$/) ? afterEach : after; + + hook(function(done) { var test = this; this.loggedInAccessToken.destroy(function(err) { if(err) return done(err); @@ -181,10 +218,11 @@ _beforeEach.givenLoggedInUser = function(credentials, optionalHandler) { done(); }); }); -} +}); -_beforeEach.givenLoggedInUserWithRole = function(credentials, role, optionalHandler){ - _beforeEach.givenUserWithRole(credentials, role, function(done) { +apply(['before', 'beforeEach']) +('givenLoggedInUserWithRole', function(credentials, role, optionalHandler){ + helpers[this.hookName].givenUserWithRole(credentials, role, function(done) { var test = this; this.user.constructor.login(credentials, function(err, token) { if(err) { @@ -196,7 +234,9 @@ _beforeEach.givenLoggedInUserWithRole = function(credentials, role, optionalHand }); }); - afterEach(function(done) { + var hook = this.hookName.match(/Each$/) ? afterEach : after; + + hook(function(done) { var test = this; this.loggedInAccessToken.destroy(function(err) { if(err) return done(err); @@ -204,15 +244,33 @@ _beforeEach.givenLoggedInUserWithRole = function(credentials, role, optionalHand done(); }); }); -} +}); -_beforeEach.givenAnUnauthenticatedToken = function(attrs, optionalHandler) { - _beforeEach.givenModel('accessToken', attrs, optionalHandler); -} +apply(['before', 'beforeEach']) +('givenAnUnauthenticatedToken', function(attrs, optionalHandler) { + helpers[this.hookName].givenModel('accessToken', attrs, optionalHandler); +}); -_beforeEach.givenAnAnonymousToken = function(attrs, optionalHandler) { - _beforeEach.givenModel('accessToken', {id: '$anonymous'}, optionalHandler); -} +apply(['before', 'beforeEach']) +('givenAnAnonymousToken', function(attrs, optionalHandler) { + helpers[this.hookName].givenModel('accessToken', {id: '$anonymous'}, optionalHandler); +}); + +_call.before = function(fn) { + fn.call({hook: before}); +}; + +_call.beforeEach = function(fn) { + fn.call({hook: beforeEach}); +}; + +_call.after = function(fn) { + fn.call({hook: after}); +}; + +_call.afterEach = function(fn) { + fn.call({hook: afterEach}); +}; _describe.whenCalledRemotely = function(verb, url, data, cb) { if (cb == undefined) { @@ -226,7 +284,10 @@ _describe.whenCalledRemotely = function(verb, url, data, cb) { } describe(verb.toUpperCase() + ' ' + urlStr, function() { - beforeEach(function(cb) { + + if(!this.hook) this.hook = beforeEach; + + this.hook(function(cb) { if(typeof url === 'function') { this.url = url.call(this); } @@ -268,43 +329,61 @@ _describe.whenCalledRemotely = function(verb, url, data, cb) { _describe.whenLoggedInAsUser = function(credentials, cb) { describe('when logged in as user', function () { - _beforeEach.givenLoggedInUser(credentials); + + if(!this.hook) this.hook = beforeEach; + + this.hook.givenLoggedInUser(credentials); cb(); }); } _describe.whenLoggedInAsUserWithRole = function(credentials, role, cb) { describe('when logged in as user', function () { - _beforeEach.givenLoggedInUser(credentials, role); + + if(!this.hook) this.hook = beforeEach; + + this.hook.givenLoggedInUser(credentials, role); cb(); }); } _describe.whenCalledByUser = function(credentials, verb, url, data, cb) { describe('when called by logged in user', function () { - _beforeEach.givenLoggedInUser(credentials); - _describe.whenCalledRemotely(verb, url, data, cb); + + if(!this.hook) this.hook = beforeEach; + + this.hook.givenLoggedInUser(credentials); + _describe.whenCalledRemotely.call(this, verb, url, data, cb); }); } _describe.whenCalledByUserWithRole = function (credentials, role, verb, url, data, cb) { describe('when called by logged in user with role ' + role, function () { - _beforeEach.givenLoggedInUserWithRole(credentials, role); - _describe.whenCalledRemotely(verb, url, data, cb); + + if(!this.hook) this.hook = beforeEach; + + this.hook.givenLoggedInUserWithRole(credentials, role); + _describe.whenCalledRemotely.call(this, verb, url, data, cb); }); } _describe.whenCalledAnonymously = function(verb, url, data, cb) { describe('when called anonymously', function () { - _beforeEach.givenAnAnonymousToken(); - _describe.whenCalledRemotely(verb, url, data, cb); + + if(!this.hook) this.hook = beforeEach; + + this.hook.givenAnAnonymousToken(); + _describe.whenCalledRemotely.call(this, verb, url, data, cb); }); } _describe.whenCalledUnauthenticated = function(verb, url, data, cb) { describe('when called with unauthenticated token', function () { - _beforeEach.givenAnAnonymousToken(); - _describe.whenCalledRemotely(verb, url, data, cb); + + if(!this.hook) this.hook = beforeEach; + + this.hook.givenAnAnonymousToken(); + _describe.whenCalledRemotely.call(this, verb, url, data, cb); }); } @@ -336,56 +415,56 @@ _it.shouldNotBeFound = function() { _it.shouldBeAllowedWhenCalledAnonymously = function(verb, url, data) { - _describe.whenCalledAnonymously(verb, url, data, function() { + _describe.whenCalledAnonymously.call(this, verb, url, data, function() { _it.shouldBeAllowed(); }); } _it.shouldBeDeniedWhenCalledAnonymously = function(verb, url) { - _describe.whenCalledAnonymously(verb, url, function() { + _describe.whenCalledAnonymously.call(this, verb, url, function() { _it.shouldBeDenied(); }); } _it.shouldBeAllowedWhenCalledUnauthenticated = function(verb, url, data) { - _describe.whenCalledUnauthenticated(verb, url, data, function() { + _describe.whenCalledUnauthenticated.call(this, verb, url, data, function() { _it.shouldBeAllowed(); }); } _it.shouldBeDeniedWhenCalledUnauthenticated = function(verb, url) { - _describe.whenCalledUnauthenticated(verb, url, function() { + _describe.whenCalledUnauthenticated.call(this, verb, url, function() { _it.shouldBeDenied(); }); } _it.shouldBeAllowedWhenCalledByUser = function(credentials, verb, url, data) { - _describe.whenCalledByUser(credentials, verb, url, data, function() { + _describe.whenCalledByUser.call(this, credentials, verb, url, data, function() { _it.shouldBeAllowed(); }); } _it.shouldBeDeniedWhenCalledByUser = function(credentials, verb, url) { - _describe.whenCalledByUser(credentials, verb, url, function() { + _describe.whenCalledByUser.call(this, credentials, verb, url, function() { _it.shouldBeDenied(); }); } _it.shouldBeAllowedWhenCalledByUserWithRole = function(credentials, role, verb, url, data) { - _describe.whenCalledByUserWithRole(credentials, role, verb, url, data, function() { + _describe.whenCalledByUserWithRole.call(this, credentials, role, verb, url, data, function() { _it.shouldBeAllowed(); }); } _it.shouldBeDeniedWhenCalledByUserWithRole = function(credentials, role, verb, url) { - _describe.whenCalledByUserWithRole(credentials, role, verb, url, function() { + _describe.whenCalledByUserWithRole.call(this, credentials, role, verb, url, function() { _it.shouldBeDenied(); }); } diff --git a/test/test.js b/test/test.js index fbcb5b4..d638e1c 100644 --- a/test/test.js +++ b/test/test.js @@ -41,6 +41,20 @@ describe('helpers', function () { }); }); + describe('helpers.before', function() { + ['withArgs', + 'givenModel', + 'givenUser', + 'givenLoggedInUser', + 'givenAnUnauthenticatedToken', + 'givenAnAnonymousToken'] + .forEach(function(func) { + it('should have a helper method named ' + func, function () { + assert.equal(typeof helpers.before[func], 'function'); + }); + }); + }); + describe('helpers.beforeEach', function() { ['withArgs', 'givenModel', @@ -66,9 +80,11 @@ describe('helpers', function () { describe('whenCalledRemotely', function() { helpers.describe.staticMethod('create', function() { helpers.beforeEach.withArgs({foo: 'bar'}); - helpers.describe.whenCalledRemotely('POST', '/xxx-test-models', function() { - it('should call the method over rest', function () { - assert.equal(this.res.statusCode, 200); + helpers.call.before(function() { + helpers.describe.whenCalledRemotely('POST', '/xxx-test-models', function() { + it('should call the method over rest', function () { + assert.equal(this.res.statusCode, 200); + }); }); }); });