@moxyjs/moxy
v1.2.0
Published
Mock everything with Proxy
Readme
Highlight
- One simple but powerful API
- Mock any
function,objectandclass - Mock methods
- Mock getters and setters
- Mock any property chain optionally
- Configurable & pluginable
Index: Install - Usage - API - Advanced Topic
Install
with npm:
npm install @moxyjs/moxyor yarn:
yarn add @moxyjs/moxyUse with Jest
Add the setup file in your jest config like:
module.exports = {
// ...
setupFiles: [
'<rootDir>/node_modules/@moxyjs/moxy/lib/extends/jest.js',
],
};Usage
import moxy from '@moxyjs/moxy';
const spy = moxy(/* anything to mock */);
spy(); // an empty function by defaultMock a function
const hello = moxy(() => 'world');
hello('foo'); // 'world'
hello.mock.fake(() => 'bar')
hello('foo'); // 'bar'
hello.mock.fakeReturnValue('baz')
hello('foo'); // 'baz'
expect(hello).toHaveBeenCalledTimes(3);
expect(hello).toHaveBeenCalledWith('foo');Fake once
const hello = moxy(() => 'world');
hello.mock.fakeReturnValue('foo');
hello.mock.fakeOnce(() => 'bar');
hello.mock.fakeReturnValueOnce('baz');
hello(); // 'bar'
hello(); // 'baz'
hello(); // 'foo'Mock an object
const duck = moxy({
say: () => 'quack',
swim: true,
});
duck.say('foo'); // 'quack'
duck.swim; // true
duck.say.mock.fakeReturnValue('meow')
duck.say('foo'); // 'meow'
duck.mock.getter('swim').mockReturnValue(false)
duck.swim; // false
expect(duck.say.mock).toHaveBeenCalledWith('foo');Mock a class
const Cat = moxy(class Cat {
say() {
return 'meow';
},
});
const cat = new Cat('orange');
cat.say('foo'); // 'meow'
// the instance is mocked
cat.say.mock.fakeReturnValue('purr');
cat.say('foo'); // 'purr'
// fake class implementation
Cat.mock.fakeReturnValue(class NyanCat {
say() {
return 'nyan~nyan~nyan~';
},
});
const cat2 = new Cat('rainbow');
cat2.say('foo'); // 'nyan~nyan~nyan~'
expect(Cat.mock).toHaveBeenCalledTimes(2);
expect(Cat.mock).toHaveBeenCalledWith('rainbow');
expect(cat.say.mock).toHaveBeenCalledTimes(3);API
moxy(value, options)
Return the mocked value
- value -
object|function, the obejct to be mocked, default tofunction(){}. - options -
object, the mock options, default to{}accessKey-string, the key to accessMockobject, default to'mock'mockReturn: true-boolean, whether to mock returned value, default tofalsemockNewInstance-boolean, whether to mock constructing call, default totrue,mockMethod:boolean, whether to mock methods, default totrue,recordGetter-boolean, whether to record getter calls, default tofalse,recordSetter-boolean, whether to record setter calls, default totrue,middlewares-function[], middleware functions, default tonull,includeProperties-(string|symbol)[], mock matched methods and properties, default tonullexcludeProperties-(string|symbol)[], exclude matched methods and properties, default tonull
Mock
The mocking operator class
getCalls()- return the functionCallarraygetter(key)- return the getterMockof a propertysetter(key)- return the setterMockof a propertykey-string|symbol- the property name
fake(impl)- fake function callfakeOnce(impl)- fake function call onceimpl-function, the faked implementation
fakeReturnValue(value)- fake returned valuefakeReturnValueOnce(value)- fake returned valuevalue-any, the faked value
wrap(wrapFn)- wrap function call behaviorwrapOnce(wrapFn)- wrap function call behavior oncewrapFn-(originalImpl) => fakedImpl, receive the original implementation and return the faked one
proxify(source)- return a mockedProxyof the source which is controlled by itself
Call
A function call record
args-any[], the function call augumentsresult-any, the returned value or the thrown error.instance-any, the bound object, i.e.thisisThrown-boolean, whether the call is thrownisConstructor-boolean, whether it's a constructing call withnew
isMoxy(value)
Check whether a value is moxied. Return a boolean. For example:
import moxy, { isMoxy } from '@moxyjs/moxy';
isMoxy({}); // false
isMoxy(moxy()); // true- value -
any, the value to check
factory(options)
Create a moxy function with new default options. For example:
import { factory } from '@moxyjs/moxy';
const moxy = factory({
recordGetter: true,
mockReturn: true,
});
const foo = moxy();
const bar = moxy();- options -
object, the same as options ofmoxy
Advanced Topic
Mock an object deeply
Any property chain matched by includeProperties is mocked deeply. The property name is checked using micromatch.
const obj = moxy(
{
foo: {
bar: {
baz: {
hello: () => 'world'
},
},
},
},
{ includeProperties: ['foo', 'b*'] },
);
obj.foo.bar.baz.hello(); // 'world'
obj.foo.bar.baz.hello.mock.fakeReturnValue('there');
obj.foo.bar.baz.hello(); // 'there'Use one Mock to mock many instances
This is useful to mock all instances of a class:
import moxy, { Mock, trackNewInstances } from '@moxyjs/moxy';
const fooMock = new Mock();
const Foo = moxy(
class Foo {
bar() {
return 'baz';
}
}
);
Foo.mock.wrap(trackNewInstances(fooMock));
new Foo().bar(); // 'baz'
fooMock.getter('bar').fakeReturnValue('zaq');
new Foo().bar(); // 'zaq'Or to mock a curried function:
import moxy, { trackCurriedFunction } from '@moxyjs/moxy';
const curriedFn = moxy(
() => () => () => '🍛'
);
curriedFn.mock.wrap(trackCurriedFunction());
curriedFn('foo')('bar')('baz'); // '🍛'
expect(mock).toHaveBeenNthCalledWith(1, 'foo');
expect(mock).toHaveBeenNthCalledWith(2, 'bar');
expect(mock).toHaveBeenNthCalledWith(3, 'baz');Proxy Handle Middleware
You can define the underlying proxy handler with the middlewares option. For example:
const foo = moxy({ bar: 'baz' }, {
middlewares: [
(handler) => ({
...handler,
deleteProperty(target, prop) {
target[prop] = 'deleted';
},
})
],
});
delete foo.bar;
foo.bar; // 'deleted'