MagicalMock is a convenience class for simplify creation of mock objects and functions for testing purposes. This package is a port of the python unittest.mock, with additional features for JavaScript.
npm i --save-dev magical-mock
This library relies on heavily on ES6 Proxies, and so either a recent version of Node or the browsers will be required
//given this hypothetical game function
function gameWorld(world) {
if(world.player.meta.logged_in == true) {
return world.greet(player);
}else{
return world.disconnect(player)
}
}
it("Should let the logged in player see the greeeting", function() {
//if you wanted to test this function you might do something like the following
var world = {
player: {
meta: {
logged_in: true
},
name: "Foo"
},
greet: function(player) {
return "hello " + player.name;
},
disconnect: function(player) {
throw Error("logged in player should not disconnect");
}
}
expect(gameWorld(world)).to.equal("hello Foo");
});
//Now with mock we can do better with less code
it("Should let the logged in player see the greeeting", function() {
let world = new Mock();
world.player.meta.logged_in = true;
gameWorld(world);
world.greet.assert_called_once_with(world.player);
world.disconnect.assert_not_called();
A mock object can generate properties when asked for. This makes targeting and replacing deeply nested properties within objects very quick.
let mock = new Mock();
mock.deeply.nested.prop = true
mock.always.returns.a.new.mock = true
mock.a.b.c.d.e.f.g.h = 10
mock.lets.place.a.func = function() { return false};
A boolean value which is set to true if the mock object is used as a function and called.
Examples
let mock = new Mock();
mock.called //false
mock();
mock.called //true
An integer count of the number of times the mock object has been called as a function.
Examples
let mock = new Mock();
mock();
mock();
mock.call_count; //2
A list of the arguments last used when calling the mock object as a function.
Examples
let mock = new Mock();
mock(1,2);
mock.call_args; //[1,2]
A list of argument lists of the arguments used when calling the mock object as a function.
Examples
let mock = new Mock();
mock(1,2);
mock(3,4);
mock.call_args_list; //[[1,2], [3,4]]
Calling a mock object as a function by default returns another mock object. However, by assigning return_value to a value the mock will return that value instead.
Examples
let mock = new Mock();
mock.return_value = 4;
mock() //4
Side_effect allows the function to return successive values, throw errors, or substitute your own function for calling the mock as a function.
Examples
let mock = new Mock();
mock.side_effect = [1,2,Error("Problems occurred")];
mock() //1
mock() //2
mock() //throw Error("Problems occurred")
let mock2 = new Mock();
mock2.side_effect = function(input) {
if(input == 1) {
return "foo";
}else if(input == 2) {
return "bar";
}else{
return "baz";
}
}
mock2(1) //foo
mock2(2) //bar
mock2(3) //baz
let mock3 = new Mock();
mock3.side_effect = RangeError("Mock has gone too far");
mock3() //throws RangeError
Spec allows the mock to be assigned a prototype
Examples
class Foo {};
let mock = new Mock();
mock.spec = Foo;
mock instanceof Foo //true
If you would like to use a mock as a contructor function you can specify what it will create.
Examples
let mock = Mock();
mock.constructs = {x: 1, y: 2};
let result = new mock(); //{x: 1, y: 2}
If you would like to use a mock in a context as an iterator you can specify a value, or series of values, or an error to throw. If a generator function is provided instead then it will use that.
Examples
let mock = new Mock();
mock.yields = [1,2, Error("explosion")]
for(let item of mock) {
console.log(item);
}
//1
//2
//throws Error("foo")
let mock2 = new Mock();
mock2.yields = function* () { yield * [1,2] }
for(let item of mock2) {
console.log(item);
}
//1
//2
Asserts that the arguments were the last arguments used when calling the mock object as a function
Arguments
args
- Variadic arguments matching the replaced function
Examples
let mock = new Mock();
mock(3,4);
mock(1,2);
mock.assert_called_with(1,2) //passes
mock.assert_called_with(3,4) //throws Error
Asserts that the mock was called once and only once with the specified arguments.
Arguments
args
- Variadic arguments matching the replaced function
Examples
let mock = new Mock();
mock(1,2);
mock.assert_called_once_with(1,2); //passes
mock.assert_called_once_with(3,4); //throws Error because args do not match
mock(3,4)
mock.assert_called_once_with(3,4); //throws Error because mock was called more than once
Asserts that the mock was called with specified arguments at least once.
Arguments
args
- Variadic arguments matching the replaced function
Examples
let mock = new Mock();
mock(1,2);
mock(3,4);
mock.assert_any_call(1,2); //passes
mock.assert_any_call(3,4); //passes
mock.assert_any_call(4,5); //throws Error
Asserts that the mock was called with the specified list of argument lists, with the option to ensure the order of calls matched the list or to disregard order.
Arguments
calls
- list of argument listsany_order
- boolean deciding if calls order should be respected
Examples
let mock = new Mock();
mock(1,2);
mock(3,4);
mock(4,5);
mock.assert_has_calls([[3,4],[4,5]]) //passes
mock.assert_has_calls([[1,2],[4,5]]) //throws Error
mock.assert_has_calls([[1,2],[4,5]], true) //passes
Asserts that the mock was not called as a function.
Examples
let mock = new Mock();
mock.assert_not_called(); //passes
mock(1,2);
mock.assert_not_called(); //throws Error