mocha-stirrer
Advanced tools
Comparing version 0.1.4 to 0.1.5
@@ -1,4 +0,7 @@ | ||
var debug = require("debug")("mocha-stirrer:cupBlender"), | ||
var nodeUtil = require("util"), | ||
path = require("path"), | ||
debug = require("debug")("mocha-stirrer:cupBlender"), | ||
sinon = require("sinon"), | ||
pourer = require("./pourer"), | ||
CupStirrer = require("./CupStirrer"), | ||
Mocker = require("./RequireMocker"), | ||
@@ -12,112 +15,70 @@ utils = require("./utils"); | ||
var cupBody = (function () { | ||
// ******************** The CUP ******************** | ||
function Cup(conf) { | ||
/** | ||
* | ||
* @param befores is either a function or an array of functions | ||
*/ | ||
function _stirBefores(befores) { | ||
var sbConf = conf.sandbox || void 0; | ||
var sb = sinon.sandbox.create(sbConf); | ||
var stirFn = function () { | ||
debug("stirring in the registered befores - " + this.name); | ||
this.name = conf.name || Date.now(); | ||
this.sb = sb; | ||
this.pars = {}; | ||
this.required = {}; | ||
this._isHooked = false; | ||
this._conf = conf; | ||
this._mocker = new Mocker(sb); | ||
this._befores = []; | ||
this._afters = []; | ||
this._modules = {}; | ||
this._hooks = {}; | ||
this._mocha ={}; | ||
this._stubAliases = {}; | ||
if (utils.isFunc(befores)) { | ||
befores = [befores]; | ||
} | ||
_registerMochaHooks(this, conf); | ||
} | ||
this._befores = this._befores.concat(befores); | ||
}.bind(this); | ||
nodeUtil.inherits(Cup, CupStirrer); | ||
if (befores) { | ||
before(stirFn); | ||
} | ||
} | ||
Cup.prototype.brew = function () { | ||
/** | ||
* | ||
* @param afters is either a function or an array of functions | ||
*/ | ||
function _stirAfters(afters) { | ||
var hooked = _doHooks(this); | ||
var stirFn = function () { | ||
debug("stirring in the registered afters - " + this.name); | ||
debug("start was called on cup - " + this.name); | ||
if (utils.isFunc(afters)) { | ||
afters = [afters]; | ||
} | ||
this._afters = this._afters.concat(afters); | ||
}.bind(this); | ||
this._isHooked = hooked ? true : this._isHooked; | ||
return hooked; | ||
}; | ||
if (afters) { | ||
before(stirFn); | ||
} | ||
} | ||
Cup.prototype.start = Cup.prototype.brew; //start is alias for brew for those that dont get it | ||
function _stirPars(pars) { | ||
Cup.prototype.require = function (reqPath, options) { | ||
debug("cup require called with path = " + reqPath + " - " + this.name); | ||
return fakeRequire(module.parent.parent, this, reqPath, options); | ||
}; | ||
if (pars) { | ||
before(function () { | ||
debug("stirring in the registered pars - " + this.name); | ||
pars = utils.isFunc(pars) ? pars() : pars; | ||
this.pars = utils.merge(pars, this.pars); //add new pars to the pars map | ||
}.bind(this)); | ||
} | ||
} | ||
Cup.prototype.restir = function () { | ||
debug("cup restir called - " + this.name); | ||
restir(this); | ||
}; | ||
function _stir(conf) { | ||
_stirPars.call(this, conf.pars); | ||
_stirBefores.call(this, conf.befores); | ||
_stirAfters.call(this, conf.afters); | ||
} | ||
Cup.prototype.reset = Cup.prototype.restir; //reset is alias for restir for those that dont get it | ||
function _start() { | ||
return _doHooks(this); | ||
Cup.prototype.getStub = function (name) { | ||
var stub = this.stubs[name]; | ||
if (!stub) { | ||
name = this._stubAliases[name]; //try the aliases for | ||
stub = this.stubs[name]; | ||
} | ||
return { | ||
start: function () { | ||
debug("start was called on cup - " + this.name); | ||
return _start.call(this); | ||
}, | ||
return stub; | ||
}; | ||
require: function (path, options) { | ||
debug("cup require called with path = " + path + " - " + this.name); | ||
return fakeRequire(module.parent.parent, this, path, options); | ||
}, | ||
stir: function (conf) { | ||
debug("cup stir called - " + this.name); | ||
_stir.call(this, conf); | ||
}, | ||
restir: function () { | ||
debug("cup restir called - " + this.name); | ||
restir(this); | ||
}, | ||
reset: function () { //alias for restir | ||
this.restir(); | ||
} | ||
}; | ||
})(); | ||
// ******************** API METHODS ******************** | ||
function blend(conf) { | ||
var name = conf.name || Date.now(); | ||
var sbConf = conf.sandbox || void 0; | ||
var sb = sinon.sandbox.create(sbConf); | ||
conf = conf || {}; | ||
var cup = { | ||
name: name, | ||
sb: sb, | ||
pars: {}, | ||
_conf: conf, | ||
_mocker: new Mocker(sb), | ||
_befores: [], | ||
_afters: [], | ||
_hooks: {} | ||
}; | ||
var cup = new Cup(conf); | ||
_setHooks(cup, conf); | ||
utils.merge(cupBody, cup); | ||
pourer.attach(cup); | ||
@@ -140,5 +101,16 @@ cup.stir(conf); //stir in any befores/afters/pars that were passed from the configuration | ||
cup.mocks = {}; | ||
cup.pars = {}; | ||
cup._stubAliases = {}; | ||
} | ||
///** | ||
// * clears everything (besides the name) from the cup, including the parameters that it stored | ||
// * @param cup | ||
// */ | ||
//function clear(cup){ | ||
// restir(cup); | ||
// | ||
// cup.pars = {}; | ||
//} | ||
function fakeRequire(parent, cup, requirePath, options) { | ||
@@ -148,3 +120,3 @@ | ||
_enrichCupStubsFromMocker(cup); | ||
_enrichStubsFromMocker(cup); | ||
@@ -159,2 +131,10 @@ return reqModule; | ||
// ******************** PRIVATE METHODS ******************** | ||
function _registerMochaHooks(cup, conf){ | ||
conf.globals.mochaHooksNames.forEach(function (mochaFn){ | ||
cup._mocha[mochaFn] = conf.globals.mochaHooks[mochaFn]; | ||
}); | ||
} | ||
function _doHooks(cup) { | ||
@@ -167,3 +147,3 @@ | ||
_doBefore(cup, conf); | ||
_doBefore(cup); | ||
_doBeforeEach(cup, conf); | ||
@@ -179,3 +159,3 @@ _doAfter(cup, conf); | ||
function _doBefore(cup, conf) { | ||
function _doBefore(cup) { | ||
@@ -191,3 +171,3 @@ var name = "stirrer before - " + cup.name; | ||
if (utils.isAsync(cupBefore)) { | ||
before(name, function (done) { | ||
cup._mocha.before(name, function (done) { | ||
runit(done); | ||
@@ -197,3 +177,3 @@ }); | ||
else { | ||
before(name, function () { | ||
cup._mocha.before(name, function () { | ||
runit(); | ||
@@ -212,2 +192,3 @@ }); | ||
if (conf.transformForEach) { //config asked for transforming pars before each test | ||
debug("transform for each is turned on for cup: " + cup.name); | ||
_transformPars(cup, conf); | ||
@@ -220,3 +201,3 @@ } | ||
if (utils.isAsync(cupBeforeEach)) { | ||
beforeEach(name, function (done) { | ||
cup._mocha.beforeEach(name, function (done) { | ||
runit(done); | ||
@@ -226,3 +207,3 @@ }); | ||
else { | ||
beforeEach(name, function () { | ||
cup._mocha.beforeEach(name, function () { | ||
runit(); | ||
@@ -238,3 +219,3 @@ }); | ||
after(name, function (done) { | ||
cup._mocha.after(name, function (done) { | ||
@@ -267,3 +248,3 @@ function finishAfter() { | ||
if (utils.isAsync(cupAfterEach)) { | ||
afterEach(name, function (done) { | ||
cup._mocha.afterEach(name, function (done) { | ||
cupAfterEach.call(cup, done); | ||
@@ -273,3 +254,3 @@ }); | ||
else { | ||
afterEach(name, function () { | ||
cup._mocha.afterEach(name, function () { | ||
cupAfterEach.call(cup); | ||
@@ -387,6 +368,32 @@ }); | ||
function _enrichCupStubsFromMocker(cup) { | ||
//todo: implement !!!! | ||
function _enrichStubsFromMocker(cup) { | ||
cup.stubs = cup.stubs || {}; | ||
var mockerStubs = cup._mocker.getStubs(); | ||
Object.keys(mockerStubs).forEach(function (key) { | ||
if (!cup.stubs[key]) { | ||
cup.stubs[key] = mockerStubs[key]; //copy over ref to stub from the mocker | ||
_addStubAliases(cup, key); | ||
} | ||
}); | ||
} | ||
function _addStubAliases(cup, fullPath) { | ||
var aliases = cup._stubAliases; | ||
if (fullPath.indexOf(path.sep) === 0) { | ||
var levels = utils.getLeveledFileName(fullPath); | ||
levels.forEach(function(name){ | ||
aliases[name] = fullPath; | ||
}); | ||
} | ||
} | ||
function _setHooks(cup, conf) { | ||
@@ -393,0 +400,0 @@ |
@@ -46,2 +46,7 @@ var debug = require("debug")("mocha-stirrer:pourer"), | ||
if(!cup._isHooked){ | ||
debug("cup isnt started (hooked) !!! - " + cup.name); | ||
return done(new Error("stirrer - cup isn't initialized correctly. if you used delay parameter, make sure you called start() on the cup instance")); | ||
} | ||
var isAsync = type !== TEST_TYPES.SKIP && | ||
@@ -69,3 +74,3 @@ type !== TEST_TYPES.WRAP && | ||
_runTestByType(testFn, testName, type, pourOwnTestFn); | ||
_runTestByType(cup, testFn, testName, type, pourOwnTestFn); | ||
} | ||
@@ -91,3 +96,3 @@ | ||
function _runTestByType(testFn, testName, type, pourOwnTestFn){ | ||
function _runTestByType(cup, testFn, testName, type, pourOwnTestFn){ | ||
@@ -97,9 +102,9 @@ if (utils.isFunc(testFn)) { | ||
case TEST_TYPES.ONLY: | ||
it.only(testName, pourOwnTestFn); | ||
cup._mocha.it.only(testName, pourOwnTestFn); | ||
break; | ||
case TEST_TYPES.SKIP: | ||
it.skip(testName, pourOwnTestFn); | ||
cup._mocha.it.skip(testName, pourOwnTestFn); | ||
break; | ||
case TEST_TYPES.NORMAL: | ||
it(testName, pourOwnTestFn); | ||
cup._mocha.it(testName, pourOwnTestFn); | ||
break; | ||
@@ -112,3 +117,3 @@ case TEST_TYPES.WRAP: | ||
else { | ||
it(testName); //define a pending test | ||
cup._mocha.it(testName); //define a pending test | ||
} | ||
@@ -115,0 +120,0 @@ } |
@@ -14,3 +14,3 @@ var Module = require("module"), | ||
this._isSandbox = _setupRestore(this, this._sinon); | ||
this._stubs = Object.create(null); //internal stubs cache | ||
_clearStubs(this); //this._stubs = Object.create(null); //internal stubs cache | ||
this._modules = []; | ||
@@ -26,2 +26,4 @@ } | ||
* - dontStub: an array of paths that are required by the module (test-subject) to not stub | ||
* - setup: object map containing the require path of stubbed dependency and a matching function. the function signature is: fn(stub) | ||
* - setupContext: the context to pass into the setup method(s) | ||
* @returns the stubbed module | ||
@@ -50,3 +52,3 @@ */ | ||
var orgRequire = Module.prototype.require, | ||
requirePathResolved = resolvePath(requirePath, parent); //resolve the path as if we required from the parent | ||
requirePathResolved = this.getResolvedPath(requirePath, parent); //resolve the path as if we required from the parent | ||
@@ -67,3 +69,3 @@ _overrideRequire(this, orgRequire, requirePathResolved, options); | ||
* - restore the stubs created by calls to require | ||
* - remove the stubs from node's module cache | ||
* - remove the stubbed modules from node's module cache | ||
* - clear the internal cache | ||
@@ -75,2 +77,10 @@ */ | ||
RequireMocker.prototype.getStubs = function () { | ||
return this._stubs; | ||
}; | ||
RequireMocker.prototype.getResolvedPath = function (reqPath, parent) { | ||
return resolvePath(reqPath, parent); | ||
}; | ||
//********************************* PRIVATE METHODS ********************************* | ||
@@ -269,3 +279,7 @@ | ||
function _clearStubs(mocker) { | ||
delete mocker._stubs; | ||
if (mocker._stubs) { | ||
delete mocker._stubs; | ||
} | ||
mocker._stubs = Object.create(null); | ||
@@ -289,3 +303,3 @@ } | ||
debug("running setup function for: " + resolvedPath); | ||
setupFn(stub); | ||
setupFn.call(options.setupContext, stub); | ||
} | ||
@@ -292,0 +306,0 @@ } |
@@ -0,1 +1,3 @@ | ||
var path = require("path"); | ||
var utils = (function () { | ||
@@ -62,3 +64,3 @@ "use strict"; | ||
if (!justFns || justFns === true && isFunc(prop)) { | ||
if (!justFns || (justFns === true && isFunc(prop))) { | ||
dest[key] = prop; //copy over the functions for this instance of stirrer | ||
@@ -124,2 +126,21 @@ } | ||
function getLeveledFileName(fileName, lCount) { | ||
var levels = new Array((lCount || 3)); | ||
var resolved = path.resolve(fileName); | ||
var bareName = path.basename(resolved).replace(new RegExp("\\" + path.extname(resolved) + "$"), ""); | ||
var dir = path.dirname(resolved); | ||
var levelName = path.join(path.basename(dir), bareName); | ||
levels[0] = levelName; | ||
for (var i = 1; i < levels.length; i += 1) { | ||
dir = path.dirname(dir); | ||
levelName = path.join(path.basename(dir), levelName); | ||
levels[i] = levelName; | ||
} | ||
return levels; | ||
} | ||
return { | ||
@@ -133,3 +154,4 @@ isFunc: isFunc, | ||
runSeries: runSeries, | ||
clone: clone | ||
clone: clone, | ||
getLeveledFileName: getLeveledFileName | ||
}; | ||
@@ -136,0 +158,0 @@ })(); |
@@ -40,3 +40,31 @@ | ||
[2K[0G [32m ✓[0m[90m should throw for not object/array types [0m | ||
[0m test merge[0m | ||
[2K[0G [32m ✓[0m[90m should merge from obj1 to obj2, not affecting obj1 [0m | ||
[2K[0G [32m ✓[0m[90m should merge from obj1 to undefined [0m | ||
[2K[0G [32m ✓[0m[90m should merge only functions when passing the flag, no functions [0m | ||
[2K[0G [32m ✓[0m[90m should merge only functions when passing the flag [0m | ||
[2K[0G [32m ✓[0m[90m should return a new object if dest is undefined [0m | ||
[2K[0G [32m ✓[0m[90m should not affect destination if src is undefined [0m | ||
[0m test leveled name[0m | ||
[2K[0G [32m ✓[0m[90m should create levels successfully [0m | ||
[2K[0G [32m ✓[0m[90m should create levels successfully with default level 3 [0m | ||
[0m cupStirrer tests[0m | ||
[2K[0G [32m ✓[0m[90m stir should cope with empty conf object [0m | ||
[0m test stir with before/after as single function[0m | ||
[2K[0G [32m ✓[0m[90m stir should add everything in config [0m | ||
[2K[0G [32m ✓[0m[90m stir should cope with undefined as conf [0m | ||
[0m test stir with requires[0m | ||
[2K[0G [32m ✓[0m[90m require should be called and modules stored in required property [0m | ||
[0m pourer tests[0m | ||
[0m check that pour is attached and can be used[0m | ||
[2K[0G [32m ✓[0m[90m pour should be executed successfully [0m | ||
[0m cupBlender tests[0m | ||
[0m test mock require and stubs enriching[0m | ||
[2K[0G [32m ✓[0m[90m should fake require module and enrich cup with stubs [0m | ||
[0m test mock require using requires in stir[0m | ||
[2K[0G [32m ✓[0m[90m should fake require module and enrich cup with stubs by stirring in requires [0m | ||
[0m stirrer basics tests[0m | ||
@@ -51,6 +79,7 @@ [0m test no mocha hooks - error[0m | ||
[2K[0G [32m ✓[0m[90m pour test should work even with grind run without parameters [0m | ||
[0m test unknown spy string (not empty)[0m | ||
[36m - need to test[0m | ||
[0m test unknown stub string (not empty)[0m | ||
[36m - need to test[0m | ||
[0m test unknown spy or stub string (not empty)[0m | ||
[0m test unknown spy string (not empty)[0m | ||
[2K[0G [32m ✓[0m[90m unknown spy string should fail [0m | ||
[0m test unknown stub string (not empty)[0m | ||
[2K[0G [32m ✓[0m[90m unknown stub string should fail [0m | ||
[0m test context and pars[0m | ||
@@ -83,2 +112,4 @@ [2K[0G [32m ✓[0m[90m test that the context of the test functions is correct [0m | ||
[2K[0G [32m ✓[0m[90m this is my test [0m | ||
[0m test correct order of calls - with Each[0m | ||
[36m - need to test each[0m | ||
[0m test correct order of calls - with async pour[0m | ||
@@ -98,2 +129,4 @@ [0m first test context[0m | ||
[36m - this is a pending test using pour[0m | ||
[0m test correct order with only[0m | ||
[2K[0G [32m ✓[0m[90m pour.only should be reached [0m | ||
[0m test correct order with stirring in befores in different context[0m | ||
@@ -109,3 +142,5 @@ [0m first context[0m | ||
[0m test start causes cup fakes to be initialized on demand[0m | ||
[2K[0G [32m ✓[0m[90m fakes should not be initialized [0m | ||
[2K[0G [32m ✓[0m[90m fakes should be initialized [0m | ||
[0m test delay without start should fail[0m | ||
[2K[0G [32m ✓[0m[90m expect an error when pour test is executed [0m | ||
@@ -126,3 +161,3 @@ [0m stirrer tests[0m | ||
[0m use stirrer cup with test function[0m | ||
[2K[0G [32m ✓[0m[90m stirrer test - 1427663752193 [0m | ||
[2K[0G [32m ✓[0m[90m stirrer test - 1428653437402 [0m | ||
[0m use stirrer cup with stubbed object and spied object[0m | ||
@@ -149,7 +184,12 @@ [2K[0G [32m ✓[0m[90m test faked objects [0m | ||
[0m testing mock require with stub setup[0m | ||
[2K[0G [32m ✓[0m[90m should mock require and setup stub successfully [0m[33m(60ms)[0m | ||
[2K[0G [32m ✓[0m[90m should mock require and setup stub successfully [0m | ||
[0m testing mock require using stirrer method with stub setup[0m | ||
[2K[0G [32m ✓[0m[90m should mock require and setup stub successfully [0m[33m(38ms)[0m | ||
[2K[0G [32m ✓[0m[90m should mock require and setup stub successfully [0m | ||
[0m use stirrer cup with requires (mocker)[0m | ||
[36m - need to implement & test[0m | ||
[0m pass requires in grind conf[0m | ||
[2K[0G [32m ✓[0m[90m fake require should be set up correctly [0m | ||
[0m pass requires in grind conf with options[0m | ||
[2K[0G [32m ✓[0m[90m fake require should be set up correctly with setup [0m | ||
[0m pass requires to stir method[0m | ||
[2K[0G [32m ✓[0m[90m fake require should be set up correctly with setup [0m | ||
@@ -165,7 +205,7 @@ [0m testing auto mocking for require with standalone mocker[0m | ||
[0m testing mock require with stub setup - standalone[0m | ||
[2K[0G [32m ✓[0m[90m should mock require and setup stub successfully - standalone [0m[33m(46ms)[0m | ||
[2K[0G [32m ✓[0m[90m should mock require and setup stub successfully - standalone [0m | ||
[92m [0m[32m 86 passing[0m[90m (283ms)[0m | ||
[36m [0m[36m 5 pending[0m | ||
[92m [0m[32m 108 passing[0m[90m (414ms)[0m | ||
[36m [0m[36m 3 pending[0m | ||
{ | ||
"name": "mocha-stirrer", | ||
"version": "0.1.4", | ||
"version": "0.1.5", | ||
"description": "Easily mock and set up tests for Mocha and Sinon then test, then reuse", | ||
"main": "./lib/stirrer.js", | ||
"main": "./lib/index.js", | ||
"scripts": { | ||
@@ -7,0 +7,0 @@ "test": "grunt build --verbose" |
368
readme.md
@@ -9,2 +9,4 @@ [](https://coveralls.io/r/yoavniran/mocha-stirrer?branch=master) | ||
> **This document is still a work in progress with several sections still missing. I'm on it!** | ||
* [Introduction](#introSection) | ||
@@ -22,3 +24,3 @@ * [Example](#firstExampleSection) | ||
A useful utility for using sinon in a friendlier way that allows you to describe the objects and functions you wish | ||
A useful utility for testing with mocha and sinon in a friendlier way that allows you to describe the objects and functions you wish | ||
to spy/stub/mock. Stirrer gives you a way to declare your setup upfront and re-use it between tests so you can write | ||
@@ -29,5 +31,5 @@ them once and then run every test. | ||
The aim of this utility is to allow you to write as little as set up code as possible focusing on the test cases themselves. | ||
The aim of this tool is to allow you to write as little as set up code as possible focusing on the test cases themselves. | ||
The **[`RequireMocker`](#requireMockerSection)** that is part of this package is a strong tool that can be used on its own | ||
The **`RequireMocker`** that is part of this package is a strong tool that can be used on its own | ||
or as part of the stirrer functionality. Read more about it [below](#requireMockerSection). | ||
@@ -42,6 +44,6 @@ | ||
Below is a full example showing how Stirrer can be used to set up ([grind](#grindSection)) a test and then run a test ([pour](#pourSection))) | ||
Below is an example showing how Stirrer can be used to set up ([grind](#grindSection)) a test and then run a test ([pour](#pourSection)) | ||
using the fakes set up and verification defined: | ||
Jump [here](#docsSection) for the full API documentation | ||
Jump [here](#apiSection) for the full API documentation | ||
@@ -109,4 +111,6 @@ ```js | ||
Creates a **[Cup](#cupSection)** instance. | ||
Creates a new **[Cup](#cupSection)** instance. | ||
A cup can be used between tests | ||
<a name="stirrerGrindConfParSection"/> | ||
@@ -117,3 +121,3 @@ _conf_ is an object that configures the cup instance. The following properties can be passed in: | ||
* `pars` - (optional) object map or function that returns an object map. Makes it easy to use values between tests | ||
* `pars` - (optional) object map (key/val) or function that returns an object map. Makes it easy to use values between tests | ||
@@ -123,5 +127,5 @@ * `spies` - (optional) object map or function returning an object map. Used to create [sinon spies](http://sinonjs.org/docs/#spies-api), | ||
1. An array with 2 the first element referencing an object, second is the property name | ||
2. A function to spy | ||
3. A special EMPTY string (_stirrer.EMPTY_) to receive an anonymous spy | ||
1. An array with 2 the first element referencing an object, second is the property name | ||
2. A function to spy | ||
3. A special EMPTY string (_stirrer.EMPTY_) to receive an anonymous spy | ||
@@ -131,6 +135,6 @@ * `stubs` - (optional) object map or function returning an object map. Used to create [sinon stubs](http://sinonjs.org/docs/#stubs-api), | ||
1. An array with 2 or 3 elements, the first element referencing an object, second is the property name | ||
1. An array with 2 or 3 elements, the first element referencing an object, second is the property name | ||
and the third and optional is a function. See sinon API for details | ||
2. An object to be stubbed by sinon | ||
3. A special EMPTY string (_stirrer.EMPTY_) to receive an empty stub | ||
2. An object to be stubbed by sinon | ||
3. A special EMPTY string (_stirrer.EMPTY_) to receive an empty stub | ||
@@ -140,6 +144,6 @@ * `mocks` - (optional) object map or function returning an object map. Used to create [sinon mocks](http://sinonjs.org/docs/#mocks-api), | ||
* `delay` - (optional, default: false) When true, cup instance will be created but not setup. meaning non of the fakes | ||
will be defined. [start](#cupStartSection) method must be called in order for setup to occur. | ||
* `delay` - (optional, default: false) When true, cup instance will be created but not set up. meaning non of the fakes | ||
will be defined. The [brew](#cupStartSection) method must be called in order for setup to occur. | ||
see the [Stirring section](#stirringSection) for further details on the order of how things are set up and run. | ||
Note that you shouldn't use delay=true when also passing a test function as fakes wont be initialized. | ||
Note that you shouldn't use delay=true when also passing a test function as fakes wont be initialieed. | ||
setting `setupImmediate` to true overrides this parameters so delay will be ignored | ||
@@ -152,13 +156,21 @@ | ||
* `before` - (optional) a function that will be called before ([mocha hooks](http://mochajs.org/#hooks)) tests are run within a describe/context block | ||
receives a reference to the cup (first argument) and a reference to the done callback. Very similarly to Mocha, if you define a | ||
second parameter Stirrer will assume you need it and you will have to call _done();_ in your method or your test will fail | ||
receives a reference to the cup as the context (this) and a reference to the done callback as a parameter. Very similarly to Mocha, if you define a | ||
the parameter Stirrer will assume you need it and you will have to call _done();_ in your method or your test will fail | ||
with a timeout error | ||
* `after` - (optional) a function that will be called after ([mocha hooks](http://mochajs.org/#hooks)) tests ran within a describe/context block | ||
receives a reference to the cup (first argument) and a reference to the done callback. Very similarly to Mocha, if you define a | ||
second parameter Stirrer will assume you need it and you will have to call _done();_ in your method or your test will fail | ||
* `after` - (optional) a function that will be called after ([mocha hooks](http://mochajs.org/#hooks)) tests ran within a describe/context block | ||
receives a reference to the cup as the context (this) and a reference to the done callback as a parameter. Very similarly to Mocha, if you define a | ||
the parameter Stirrer will assume you need it and you will have to call _done();_ in your method or your test will fail | ||
with a timeout error | ||
* `beforeEach` - (optional) | ||
* `beforeEach` - (optional) a function that will be called before ([mocha hooks](http://mochajs.org/#hooks)) each test within a describe/context block | ||
receives a reference to the cup as the context (this) and a reference to the done callback as a parameter. Very similarly to Mocha, if you define a | ||
the parameter Stirrer will assume you need it and you will have to call _done();_ in your method or your test will fail | ||
with a timeout error | ||
* `afterEach` - (optional) a function that will be called after ([mocha hooks](http://mochajs.org/#hooks)) each test within a describe/context block | ||
receives a reference to the cup as the context (this) and a reference to the done callback as a parameter. Very similarly to Mocha, if you define a | ||
the parameter Stirrer will assume you need it and you will have to call _done();_ in your method or your test will fail | ||
with a timeout error | ||
* `sandbox` - (optional) an object with properties to configure the internal [sinon sandbox](http://sinonjs.org/docs/#sandbox) object Stirrer creates. | ||
@@ -174,11 +186,23 @@ | ||
* `dontRestir` - (optional, default: false) (see [restir](#restirSection)) will prevent the cup from being "restirred" (reset) in the | ||
after or afterEach hook | ||
after hook. This means that when the mocha context(describe) finishes, non of the fakes will be restored so you will need to do the restoring manually. | ||
* `requires` - (optional) | ||
> not implemented yet | ||
requires is either an array or a function (returning array). Each element in the array should either be: | ||
* `befores` - (optional) | ||
1) string with the path of the module to require | ||
2) an object: {path: "", options: {}) - options is optional (for options details see [below](#requireMockerRequireOptions)) | ||
* `afters` - (optional) | ||
This will fake require the modules according to the provided path and make them available on the 'required' property of the cup. Additional requires can be passed into the `cup` using its [stir](#cupStirMethodSection) method. | ||
* `befores` - (optional) Can either be a function or an array of functions. The signature of these functions is: fn(next). `next` is a function that must be called otherwise tests will not run. | ||
Each of the registered methods will be executed in sequence right before a test(pour) is run. | ||
Additional befores can be passed into the `cup` using its [stir](#cupStirMethodSection) method. | ||
Any registered before functions are removed when the cup is [restirred](#restirSection) (reset) | ||
* `afters` - (optional) Can either be a function or an array of functions. The signature of these functions is: fn(next). `next` is a function that must be called otherwise tests will not finish running. | ||
Each of the registered methods will be executed in sequence right after a test(pour) is run. | ||
Additional afters can be passed into the `cup` using its [stir](#cupStirMethodSection) method | ||
Any registered afters functions are removed when the cup is [restirred](#restirSection) (reset) | ||
<a name="stirrerGrindtestFnParSection"/> | ||
@@ -195,8 +219,42 @@ _testFn_ | ||
### require(cup) | ||
Clears the cup's fakes(spies/stubs/mocks) and restores them using the internal sinon sandbox object. | ||
All registered afters/befores are removed together with all references to spies/stubs/mocks and stub aliases. | ||
### Mocker | ||
The cup's restir method is called internally automatically when the mocha context/describe ends in which the grind method was called or if delay was used, | ||
from the ending context in which [brew](#cupStartSection) was called. See the [Stirring section](#stirringSection) below for a more detailed explanation. | ||
<a name="requireSection"> | ||
### require(cup, requirePath, options) | ||
* `cup`- the cup instance to use as the sandbox and add the stubs to | ||
* `requirePath` - the module to require. Use the same path as you would use for a normal require. so relative to the current module | ||
* `options` - see the options details in the RequireMocker section, [require method details](#requireMockerRequireSection) | ||
_The default context for the setup methods (if you use them) will be the cup instance. To change it simply pass a different setupContext_ | ||
### RequireMocker | ||
This is the RequireMocker type discussed below. You can new it up and use it on its own. See the [section](#requireMockerSection) below for details. | ||
### EMPTY | ||
When grinding a new cup you can specify what you wish to stub or spy. In case you want an anonymous stub/spy ala "_**sinon.stub();**_" you can use this special property as the value of the stub or spy. This way: | ||
```js | ||
var stirrer = require("mocha-stirrer"); | ||
var cup = stirrer.grind({ | ||
stubs: { | ||
"emptyStub": stirrer.EMPTY //will create an anonymous stub | ||
}, | ||
spies: { | ||
"emptySpy": stirrer.EMPTY //will create an anonymous spy | ||
}, | ||
before: function () { | ||
cup.stubs.emptyStub.returns("foo"); //here we use our anonymous stub | ||
} | ||
}); | ||
``` | ||
___ | ||
@@ -207,2 +265,4 @@ | ||
A cup is created by calling the [grind](#grindSection) method: | ||
```js | ||
@@ -215,21 +275,44 @@ | ||
<a name="cupStirMethodSection"/> | ||
### stir(conf) | ||
Add information to the cup that can be used by following tests. the new information is added on top of any other data | ||
already passed using the grind method or previously calling stir. | ||
`pars` - | ||
**conf** - object that can consist of any combination of the following properties: | ||
`befores` - array of methods or a single method to be executed before each test. whether a series of before methods is passed | ||
in an array or if its a single method, each method receives a '_next_' function reference as a parameter which it must call. | ||
Failing to call next() will cause timeouts as the flow will not progress | ||
* `pars` - object map (key/val) or function that returns an object map | ||
* `befores` - array of methods or a single method to be executed before each test. Each method passed receives a '_next_' function reference as a parameter which it must call. Failing to call _next()_ will cause timeouts as the flow will not progress | ||
`afters` - array of methods or a single method to be executed after each test. whether a series of before methods is passed | ||
in an array or if its a single method, each method receives a '_next_' function reference as a parameter which it must call. | ||
Failing to call next() will cause timeouts as the flow will not progress | ||
```js | ||
var cup = stirrer.grind(...); | ||
cup.stir({ | ||
befores: function (next) { //can pass one function or an array of functions | ||
//do something here | ||
//... | ||
next(); //dont forget to call next | ||
} | ||
}); | ||
``` | ||
* `afters` array of methods or a single method to be executed after each test. Each method receives a '_next_' function reference as a parameter which it must call. Failing to call next() will cause timeouts as the flow will not progress. | ||
* `requires` - array of elements or a function returning array of elements, each element in the array should either be: | ||
* string with the path of the module to require or, | ||
* an object: {path: "", options: {}) - options is optional | ||
<a name="pourSection"/> | ||
###pour | ||
### pour(name, fn) | ||
> Alias: test | ||
* `name` - (mandatory) name for the test | ||
* `fn` - (optional) function to be executed as the test | ||
the Pour method mimics Mocha's '_it_' function and supports it's different flavors: | ||
@@ -272,3 +355,3 @@ | ||
done(); //make sure tal call done so Mocha doesnt timeout | ||
done(); //make sure to call done so Mocha doesnt timeout | ||
}); | ||
@@ -278,3 +361,3 @@ | ||
If you want to use Mocha's '_it_' you can call pour like this: | ||
If you want to use Mocha's '_it_' on your own you can call pour like this: | ||
@@ -294,38 +377,173 @@ ```js | ||
<a name="cupStartSection"/> | ||
### start() | ||
### brew() | ||
> Alias: start | ||
If delay=true was used when grinding the cup then you will need to manually start the cup by calling this method. | ||
This will initialize the cup. A good time to use delay and manual start is when you have the cup grinding code at the top of a module | ||
or in a shared util class. Then you wouldn't want the cup to be started immediately but rather in the right context/describe. | ||
```js | ||
//we may define a cup at the top of our test module with the delay flag, like this: | ||
var delayedCup = stirrer.grind({ | ||
name: "delayed cup test", | ||
delay: true, //cup will not be started immediately | ||
spies: { | ||
"pathSpy": [path, "join"] | ||
}, | ||
stubs: { | ||
"readdirSyncStub": [fs, "readdir"] | ||
}, | ||
pars: { | ||
readErr: "oh no!" | ||
}, | ||
before: function () { | ||
this.stubs.readdirSyncStub.callsArgWithAsync(1, this.pars.readErr); | ||
}, | ||
after: function () { | ||
expect(this.spies.pathSpy).to.have.been.called(); | ||
expect(this.stubs.readdirSyncStub).to.have.been.called(); | ||
} | ||
}); | ||
//then when in the right context we can start the cup, like this: | ||
describe("start causes cup fakes to be initialized on demand", function () { | ||
delayedCup.start(); //on demand start | ||
delayedCup.pour("fakes should not be initialized", function (done) { | ||
var result = this.spies.pathSpy("a", "b"); | ||
expect(result).to.equal("a/b"); | ||
this.stubs.readdirSyncStub("bla", function (err) { | ||
expect(err).to.equal(delayedCup.pars.readErr); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
``` | ||
### restir() | ||
leaves the configuration intact | ||
> Alias: reset | ||
### require(path, setupFn, options) | ||
see the [restir global method details](#restirSection) | ||
<a name="cupRequireSection"/> | ||
### require(reqPath, options) | ||
see the [require global method details](#requireSection) | ||
### getStub(name) | ||
* `name`- is the way to identify the stub you wish to get. | ||
Normally, you declare objects to stub using the grind method. The key you use is the name that will be used to store the stub on the cup instance. so if you did: | ||
```js | ||
var cup = stirrer.grind({ | ||
stubs: { | ||
myStub: someObj.someFn | ||
} | ||
}); | ||
``` | ||
then you will be able to access the stub by using: | ||
```js | ||
cup.stubs.myStub.returns(...); | ||
``` | ||
However, if you used the fake reuqire mechanism by calling require on the cup instance. The dependencies of the module you fake require will also be available on the cup.stubs property. But they will be stored using the fully resolved path which is inconvenient to use at best and most likely different per environment. | ||
Thats where getStub comes in as it lets you use an alias or shortcut to get to the stub you want. | ||
See the following example, if you had the following structure: | ||
* test.js | ||
* testObjects/ | ||
* foo.js | ||
* sub/ | ||
* bar.js | ||
_testObjects/foo.js_ requires _testObjects/sub/bar.js_. In _test.js_ you fake require _foo.js_ and you wish to set up a stubbed method from _bar.js_. You can easily do this by using the cup's getStub method and passing it "sub/bar" or even "testObjects/sub/bar". both of these will return the stubbed bar module. | ||
Here is the above explanation in the form of a code example: | ||
```js | ||
describe("pass requires in grind conf", function () { | ||
var cup = stirrer.grind({ | ||
requires: [ | ||
"./testObjects/foo" //foo will be fake required | ||
], | ||
before: function () { | ||
this.getStub("sub/bar").prototype.useDep.returns("this works!"); //foo depends on bar.js and we get to it and set it upusing alias: "sub/bar" | ||
} | ||
}); | ||
cup.pour("fake require should be set up correctly", function () { | ||
var foo = cup.required["./testObjects/foo"]; //we can get to foo using the required property | ||
expect(foo).to.exist(); | ||
expect(foo.useSubDep("")).to.equal("this works!"); //stub returns what we told it to return | ||
}); | ||
}); | ||
``` | ||
### name : String | ||
The name of the instance. can be passed initially to the grind method. | ||
### sb : Sinon.Sandbox | ||
The instance of sinon sandbox used by the cup. This enables the cup restir method to restore all fakes created by the cup automatically. | ||
### pars : Object | ||
Calling grind on stirrer creates an instance of _cup_. You can reuse a cup instance between tests easily using the _pour_ method. | ||
All of the parameters (key/val) passed to the cup either during grinding or using the stir method | ||
### spies : Object | ||
```js | ||
The spies created by the cup. Spies are created according to the map passed to the cup during the grinding | ||
var cup = stirrer.grind({}); | ||
### stubs : Object | ||
describe("my test", function(){ | ||
The stubs created by the cup. Stubs are created according to the map passed to the cup during the grinding | ||
cup.pour(function(){ | ||
### mocks : Object | ||
it("should do something", function(){ | ||
The mocks created by the cup. Mocks are created according to the map passed to the cup during the grinding | ||
### required : Object | ||
All of the modules (key/val) that were fake required (using the [Require Mocker](#requireMockerSection)) by passing requires either during grinding or the stir method | ||
The key used is the same one used to identify the module by its path. | ||
```js | ||
cup.stir({ | ||
requires: ["./testObjects/foo"] //define the module to fake require | ||
}); | ||
cup.pour("should be able to test with my faked module", function(){ | ||
var fakeFoo = cup.required["./testObjects/foo"]; //the module is now available using the cup's required property | ||
}); | ||
}); | ||
}); | ||
``` | ||
--- | ||
<a name="requireMockerSection" /> | ||
@@ -337,2 +555,32 @@ ## Require Mocker | ||
A typical use of the Mocker is through the [cup.require](#cupRequireSection) method. However, | ||
it is possible to use it directly by using the _RequireMocker_ property of mocha-stirrer. | ||
Here's an example (taken from this [test module](https://github.com/yoavniran/mocha-stirrer/blob/master/test/RequireMocker.standalone.test.js#L55)) - | ||
```js | ||
var Mocker = require("mocha-stirrer").RequireMocker; | ||
var mocker = new Mocker(sinon); //pass sinon or a sinon sandbox to the mocker | ||
var foo = mocker.require("./testObjects/foo", { | ||
dontStub: ["fs"] | ||
}); | ||
expect(foo).to.exist(); | ||
expect(foo.bar()).to.equal("foo"); | ||
expect(foo.wat("a", "b")).to.not.exist(); //internally path should be stubbed and not set up to return anything | ||
expect(foo.useSub()).to.not.exist(); | ||
expect(foo.useSubDep("world")).to.not.exist(); | ||
expect(foo.useFuncDep()).to.not.exist(); | ||
var Bar = require("./testObjects/sub/bar"); | ||
expect(Bar.prototype.useDep).to.have.been.calledWith("world"); | ||
mocker.restore(); //make sure to clean up by restoring the stubs | ||
``` | ||
You can define a setup function that will be called with the stubbed object as an argument, then you will be able to define | ||
@@ -347,6 +595,20 @@ behaviors on its stubs easily. | ||
<a name="requireMockerRequireSection"/> | ||
### require(parent, requirePath, options) | ||
* `parent` - the parent module that is making the mock require - this is normally the test module | ||
* `requirePath` - the module to require, relative to the test module (parent) | ||
* <a name="requireMockerRequireOptions"/> `options` - additional setup options: | ||
* dontStub: an array of paths that are required by the module or by its dependencies to not stub | ||
* setup: object map containing the require path of stubbed dependency and a matching function. the function signature is: fn(stub) | ||
* setupContext: the context to pass into the setup method(s) | ||
--- | ||
<a name="stirringSection"/> | ||
## Stirring | ||
To understand this section you should have a good grip of the order of execution of things in Mocha in conjunction with its hooks. | ||
More details about stirring and order of calls | ||
Internally, the mocha hooks (mainly the `before` hook) are used extensively to set up the fakes and your own befores/afters/etc. | ||
To use Mocha-Stirrer successfully you should have a good grip of the order of execution of things in Mocha in conjunction with its hooks... | ||
> this section isnt complete yet |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
167784
26
1039
595