spooks
v2.0.0
Published
Easily create unit test spies and mock objects.
Downloads
5,358
Maintainers
Readme
spooks.js
Easily create JavaScript unit test spies and mock objects.
Installation
If you're using npm:
npm install spooks
Or if you just want the git repo:
git clone [email protected]:philbooth/spooks.js.git
If you're into other package managers, it is also available from Bower, Component and Jam.
Usage
Loading the library
If you are running in Node.js,
Browserify
or another CommonJS-style environment,
you can require
spooks like so:
var spooks = require('spooks');
It also the supports the AMD-style format preferred by Require.js.
If you are including spooks.js
with an HTML <script>
tag,
or neither of the above environments
are detected,
it will export the interface globally
as spooks
.
Calling the exported functions
Four functions are exported:
spooks.fn
,
spooks.obj
,
spooks.ctor
and spooks.mode
.
spooks.fn (options)
Returns a spy function,
based on the properties of the options
argument:
options.name
must be a string identifying the function, to be used when fetching the count of, arguments to or context for calls to the returned spy function. Normally you want this to match the actual name of the function, although it doesn't have to (for example, you may need to avoid name clashes with other properties on thelog
object).options.log
must be an object that will be used to store the count of calls made to the spy, any arguments passed to it and thethis
context for each call. These are stored on thecounts[name]
,args[name]
andthese[name]
properties oflog
respectively.options.chain
is an optional boolean which can be used to indicate that the returned spy function should support chaining (i.e. return it's ownthis
when invoked).options.results
is an optional array of values to be returned by the spy function. The arrays are iterated through repeatedly, allowing different values to be returned with each successive call. Result values may also be updated dynamically, after the spy has been created. It is ignored ifchain
istrue
.options.callback
is an optional funcion that will called when the spy function is invoked. This is especially useful when testing asynchronous code.
Example
// Create the spy function.
var log = {}, originalSetTimeout = setTimeout;
setTimeout = spooks.fn({
name: 'setTimeout',
log: log
});
// Perform some test setup.
...
// Assert that the spy was called as expected.
assert.strictEqual(log.counts.setTimeout, 1);
assert.lengthOf(log.args.setTimeout[0], 2);
assert.isFunction(log.args.setTimeout[0][0]);
assert.strictEqual(log.args.setTimeout[0][1], 1000);
// Reinstate the original function.
setTimeout = originalSetTimeout;
spooks.obj (options)
Returns a mock object,
containing spy methods
based on the properties of the options
argument:
options.archetype
must be an object that will be used as a template on which to base the mock object. Properties from this object will be mocked.options.mode
is an optional mode constant, as returned by the functionspooks.mode
, that indicates precisely which properties from the archetype should be mocked. See the documentation forspooks.mode
, for more information about modes.options.log
must be an object that will be used to store counts of spy method calls, any arguments passed to those methods and thethis
context for each call, on thecounts
,args
andthese
properties respectively.options.spook
is an optional object that can be used as a base mock, to be augmented with spy methods. If it is not specified, a fresh mock will be returned instead.options.chains
is an optional object containing boolean flags that indicate whether spy methods should support chaining. The flags are keyed by method name.options.results
is an optional object containing containing arrays of result values that will be returned from spy methods. The arrays are keyed by method name and may be updated dynamically, after the mock object has been created.options.callbacks
is an optional object containing functions that will be called when the spy methods are invoked. This is especially useful when testing asynchronous code.
Example
// Create the mock object.
var log = {},
el1 = spooks.obj({
archetype: jQuery('body'),
log: log
}),
el2 = spooks.obj({
archetype: el1,
log: log
});
$ = spooks.fn({
name: 'jQuery',
log: log,
results: [ el1, el2 ]
});
spooks.obj({
archetype: jQuery,
log: log,
spook: $
});
// Perform some test setup.
...
// Assert that the spies were called as expected.
assert.strictEqual(log.counts.jQuery, 2);
assert.strictEqual(log.counts.hide, 2);
assert.strictEqual(log.these.hide[0], el1);
assert.strictEqual(log.these.hide[1], el2);
assert.strictEqual(log.counts.ajax, 1);
assert.strictEqual(log.these.ajax[0], $);
assert.lengthOf(log.args.ajax[0], 2);
assert.strictEqual(log.args.ajax[0][0], '/users/1.json');
assert.isObject(log.args.ajax[0][1]);
// Reinstate the original object.
$ = jQuery;
spooks.ctor (options)
Returns a spy constructor,
which itself returns mock instances
that contain spy methods
based on the properties of the options
argument:
options.name
must be a string identifying the constructor, to be used when fetching the count of, arguments to or context for calls to the returned spy constructor. You probably want this to match the actual name of the constructor, although it doesn't have to (for example, you may need to avoid name clashes with other properties on thelog
object).options.log
must be an object that will be used to store the count of calls made to the constructor and the methods on objects it constructs, any arguments passed in those calls and thethis
context for them. These are stored on thecounts[name]
,args[name]
andthese[name]
properties oflog
respectively.options.archetype
must be an object containing properties that define how to construct the mock instances that will be returned by the constructor. It must have either the propertyinstance
, an object that will be used as the template for mock instances, or the propertyctor
, a function that returns the template (usually this would be the original constructor that is being mocked). Ifctor
is specified, the array propertyargs
may also be set to specify any arguments which must be passed to that function.options.mode
is an optional mode constant, as returned by the functionspooks.mode
, that indicates precisely which properties from the archetype should be mocked. See the documentation forspooks.mode
, for more information about modes.options.chains
is an optional object containing boolean flags that indicate whether spy methods of the mock instances should support chaining. The flags are keyed by method name.options.results
is an optional object containing containing arrays of result values that will be returned from spy methods of the mock instances. The arrays are keyed by method name and may be updated dynamically, after the mock object has been created.options.callbacks
is an optional object containing functions that will be called when the spy methods of the mock instances are invoked. This is especially useful when testing asynchronous code.
Example
// Create the spy constructor.
var log = {}, originalTask = Task;
Task = spooks.ctor({
name: 'Task',
log: log,
archetype: {
ctor: Task
},
results:
isDone: [ false ]
}
});
// Perform some test setup.
...
// Assert that the spies were called as expected.
assert.strictEqual(log.counts.Task, 1);
assert.lengthOf(log.args.Task[0], 0);
assert.strictEqual(log.counts.isDone, 1);
// Reinstate the original object.
Task = originalTask;
spooks.mode (modes)
Returns a mode constant that can be used to modify the mocking behaviour of other functions in the library.
The default mode, assumed by every function in the absence of these constants, is to mock only the archetype's own function properties. That is to say, any properties of the archetype which are not functions or are inherited from the archetype's prototype chain will not be mocked.
modes
must be a string
containing a mode
or comma-separated list of desired modes,
combined in any order.
Valid modes are 'wide'
, 'deep'
and 'heavy'
:
wide
indicates that mock objects will be assigned copies of the archetype's value properties (strings, numbers, booleans) in addition to its functions.deep
indicates that mock objects will be given a deep-cloned copy of any object properties on the archetype.heavy
indicates that mock objects will be given copies of properties from the archetype's prototype chain.
All combinations of these modes are valid. Any modes not recognised will cause an exception to be thrown.
Development
Dependencies
The build environment relies on
Node.js,
JSHint,
Mocha,
Chai and
UglifyJS.
Assuming that you already have Node.js and NPM set up,
you just need to run npm install
to install all of the dependencies
as listed in package.json
.
Unit tests
The unit tests are in test/spooks.js
.
You can run them with the command npm test
.
To run the tests inside a web browser,
open test/spooks.html
.