Presentation
Joker is a mocking library designed to be used with testing frameworks like mocha.
Features
- Instrument (spy) functions.
- Create fake functions and objects (called "stubs").
- Replace modules or modules functions, preventing the real module requirement if needed.
- List all calls made with instrumented functions / objects / modules, including arguments and results.
Install
Use classical npm install
command:
npm install joker-mocker
Usage
When using Joker, you need to follow this workflow:
-
Require Joker and create a new isntance:
const Joker = require('joker-mocker'); const joker = new Joker();
-
Create spies, stubs or mocks:
const getFruit = () => jocker.stub('getFruit', ['apple', 'banana', 'orange']);
-
Run the tests inside
jocker.test()
callback:const result = jocker.test(() => { assert(getFruit(), 'apple'); assert(getFruit('something useless'), 'banana'); return 'ok'; }); // result === 'ok'
-
If needed, you call review the calls made inside
jocker.test()
callback:const calls = jocker.calls('_stub_', 'getFruit'); // calls === [ // { args: [], result: 'apple' }] // { args: ['something useless'], result: 'banana' }] // ]
Spies
Spies are used to instrument a function:
coonst foo = bar => `${bar || ''}baz`);
const spy = joker.spyFunction('foo', foo);
joker.test(() => spy('bar'));
joker.firstCall('_spy_', 'foo') === { args: ['bar'], result: 'barbaz' });
joker.spyFunction()
takes two arguments:
- A name for the function (which may be used to get the function calls later).
- The function to spy. It returns an updated function, but does not update the initial function (due to technical limitations). Thus, you need to use the returned function. Any call made with the initial function won't be recorded.
Stubs
Stubs are new instrumented functions or objects:
const getFruit = joker.stubFunction('getFruit', ['apple', 'banana', 'orange']);
joker.test(() => getFruit() === 'apple');
joker.firstCall('_stub_', 'getFruit') === { args: [], result: 'apple' });
const myObject = joker.stubObject('myObject', {
stub: true,
}, {
hello: ['hello world'],
});
joker.test(() => {
myObject.stub === true;
myObject.hello() === 'hello world';
});
joker.firstCall('myObject', 'hello') === { args: [], result: 'hello world' });
stubFunction()
joker.stubFunction()
takes two arguments:
- A name for the function (which may be used to get the function calls later).
- An array of results or a functionr eturning a result.
If you supply an array as second parameter, each array value will be returned one by one over calls. If the length of the array is lower than the number of calls, Joker loops back to the start of the array.
const getFruit = joker.stubFunction('getFruit', ['apple', 'banana', 'orange']);
getFruit() === 'apple';
getFruit() === 'banana';
getFruit() === 'orange';
getFruit() === 'apple';
If you supply a function instead, this function will be called to generate result at every call:
const getFruit = joker.stubFunction('getFruit', fruit => fruit);
getFruit('apple') === 'apple';
getFruit('orange') === 'orange';
getFruit() === undefined;
stubObject()
joker.stubObject()
looks like stubFunction()
, except it creates a full object with several properties and functions (if you want so).
Calling stubObject()
is a bit mroe complicated:
- First parameter is a name for the object.
- Second parameter is an object describing properties,
Object.assign()
will be used to assign these properties to the stub object. - Third paramter is an object describing functions. Each key correspond to the function name and each value defines the values returned by the function: either an array or a function, like
stubFunction()
.
const properties = {
prop_1: 1,
prop_2: 2,
prop_3: 3,
};
const functions = {
getFruits: ['apple', 'orange'],
hello: name => `Hello ${name} !`,
};
const obj = joker.stubObject('obj', properties, functions);
obj.prop_1 === 1;
obj.getFruits() === 'apple';
obj.hello('world') === 'hello world !';
Mocks
TODO
Calls
TODO
API
API details are available on https://hiryus-utils.gitlab.io/joker/.
You can also check the unit tests in test
folder.
Security / Disclosure
If you discover any security issue, please do not raise a GitHub / GitLab issue about it. Instead, disclose it confidentially by emailing hiryus.sha@gmail.com.
This way, the problem can be assessed and hopefully fixed prior to being exploited.
Contributions
Merge requests are welcome ! If you want to help, you can find all information in contributing.md.
PS: if you are usure how to do something, feel free to ask or even try anyway. If you do a mistake, nobody will get angry about it. Someone will explain you the problem and how to solve it before it even ends up in the repository.