@moxyjs/moxy
TypeScript icon, indicating that this package has built-in type declarations

1.1.0 • Public • Published

MOXY

Mock EVERYTHING with Proxy!

Highlight

  • One simple but powerful API
  • Mock any function, object and class
  • Mock methods
  • Mock getters and setters
  • Mock any property chain optionally
  • Configurable & pluginable

Install

with npm:

npm install @moxyjs/moxy

or yarn:

yarn add @moxyjs/moxy

Use 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 default
Mock 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 to function(){}.
  • options - object, the mock options, default to {}
    • accessKey - string, the key to access Mock object, default to 'mock'
    • mockReturn: true - boolean, whether to mock returned value, default to false
    • mockNewInstance - boolean, whether to mock constructing call, default to true,
    • mockMethod:boolean, whether to mock methods, default to true,
    • recordGetter - boolean, whether to record getter calls, default to false,
    • recordSetter - boolean, whether to record setter calls, default to true,
    • middlewares - function[], middleware functions, default to null,
    • includeProperties - (string|symbol)[], mock matched methods and properties, default to null
    • excludeProperties - (string|symbol)[], exclude matched methods and properties, default to null

Mock

The mocking operator class

  • getCalls() - return the function Call array
  • getter(key) - return the getter Mock of a property
  • setter(key) - return the setter Mock of a property
    • key - string|symbol - the property name
  • fake(impl) - fake function call
  • fakeOnce(impl) - fake function call once
    • impl - function, the faked implementation
  • fakeReturnValue(value) - fake returned value
  • fakeReturnValueOnce(value) - fake returned value
    • value - any, the faked value
  • wrap(wrapFn) - wrap function call behavior
  • wrapOnce(wrapFn) - wrap function call behavior once
    • wrapFn - (originalImpl) => fakedImpl, receive the original implementation and return the faked one
  • proxify(source) - return a mocked Proxy of the source which is controlled by itself

Call

A function call record

  • args - any[], the function call auguments
  • result - any, the returned value or the thrown error.
  • instance - any, the bound object, i.e. this
  • isThrown - boolean, whether the call is thrown
  • isConstructor - boolean, whether it's a constructing call with new

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 of moxy

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'

Readme

Keywords

none

Package Sidebar

Install

npm i @moxyjs/moxy

Weekly Downloads

12

Version

1.1.0

License

MIT

Unpacked Size

112 kB

Total Files

58

Last publish

Collaborators

  • lrills