Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

mm

node-modules85.7kMIT4.0.2TypeScript support: included

mock mate, mock http request, fs access and so on.

mm, muk, mock, test

readme

mm, mock mate

NPM version Node.js CI Test coverage npm download Node.js Version

An simple but flexible mock(or say stub) package, mock mate.

Install

npm install mm --save-dev

Usage

import fs from 'node:fs';
import { mm } from 'mm';

mm(fs, 'readFileSync', function(filename) {
  return filename + ' content';
});

console.log(fs.readFileSync('《九评 Java》'));
// => 《九评 Java》 content

restore();
console.log(fs.readFileSync('《九评 Java》'));
// => throw `Error: ENOENT, no such file or directory '《九评 Java》`

Support spy

If mocked property is a function, it will be spied, every time it called, mm will modify .called, .calledArguments and .lastCalledArguments. For example:

import { mm } from 'mm';

const target = {
  async add(a, b) {
    return a + b;
  },
};

mm.data(target, 'add', 3);

assert.equal(await target.add(1, 1), 3);
assert.equal(target.add.called, 1);
assert.deepEqual(target.add.calledArguments, [[ 1, 1 ]]);
assert.deepEqual(target.add.lastCalledArguments, [ 1, 1 ]);

assert.equal(await target.add(2, 2), 3);
assert.equal(target.add.called, 2);
assert.deepEqual(target.add.calledArguments, [[ 1, 1 ], [ 2, 2 ]]);
assert.deepEqual(target.add.lastCalledArguments, [ 2, 2 ]);

If you only need spy and don't need mock, you can use mm.spy method directly:

import { mm } from 'mm';

const target = {
  async add(a, b) {
    await this.foo();
    return a + b;
  },
  async foo() { /* */ },
};

mm.spy(target, 'add');
assert.equal(await target.add(1, 1), 2);
assert.equal(target.add.called, 1);
assert.deepEqual(target.add.calledArguments, [[ 1, 1 ]]);
assert.deepEqual(target.add.lastCalledArguments, [ 1, 1 ]);

assert.equal(await target.add(2, 2), 4);
assert.equal(target.add.called, 2);
assert.deepEqual(target.add.calledArguments, [[ 1, 1 ], [ 2, 2 ]]);
assert.deepEqual(target.add.lastCalledArguments, [ 2, 2 ]);

API

.error(module, propertyName, errerMessage, errorProperties)

import fs from 'node:fs';
import { mm } from 'mm';

mm.error(fs, 'readFile', 'mock fs.readFile return error');

fs.readFile('/etc/hosts', 'utf8', function (err, content) {
  // err.name === 'MockError'
  // err.message === 'mock fs.readFile return error'
  console.log(err);

  mm.restore(); // remove all mock effects.

  fs.readFile('/etc/hosts', 'utf8', function (err, content) {
    console.log(err); // => null
    console.log(content); // => your hosts
  });
});

.errorOnce(module, propertyName, errerMessage, errorProperties)

Just like mm.error(), but only mock error once.

import fs from 'node:fs';
import { mm } from 'mm';

mm.errorOnce(fs, 'readFile', 'mock fs.readFile return error');

fs.readFile('/etc/hosts', 'utf8', function (err, content) {
  // err.name === 'MockError'
  // err.message === 'mock fs.readFile return error'
  console.log(err);

  fs.readFile('/etc/hosts', 'utf8', function (err, content) {
    console.log(err); // => null
    console.log(content); // => your hosts
  });
});

.data(module, propertyName, secondCallbackArg)

mm.data(fs, 'readFile', Buffer.from('some content'));

// equals

fs.readFile = function (...args, callback) {
  callback(null, Buffer.from('some content'))
};

.dataWithAsyncDispose(module, propertyName, promiseResolveArg)

Support Symbol.asyncDispose

mm.dataWithAsyncDispose(locker, 'tryLock', {
  locked: true,
});

// equals

locker.tryLock = async () => {
  return {
    locked: true,
    [Symbol.asyncDispose](): async () => {
      // do nothing
    },
  };
}

Run test with await using should work:

mm.dataWithAsyncDispose(locker, 'tryLock', {
  locked: true,
});

await using lock = await locker.tryLock('foo-key');
assert.equal(lock.locked, true);

.empty(module, propertyName)

mm.empty(mysql, 'query');

// equals

mysql.query = function (...args, callback) {
  callback();
}

.datas(module, propertyName, argsArray)

mm.datas(urllib, 'request', [Buffer.from('data'), {headers: { foo: 'bar' }}]);

// equals

urllib.request = function (...args, callback) {
  callback(null, Buffer.from('data'), {headers: { foo: 'bar' }});
}

.syncError(module, propertyName, errerMessage, errorProperties)

var { mm } = require('mm');
var fs = require('fs');

mm.syncError(fs, 'readFileSync', 'mock fs.readFile return error', {code: 'ENOENT'});

// equals

fs.readFileSync = function (...args) {
  var err = new Error('mock fs.readFile return error');
  err.code = 'ENOENT';
  throw err;
};

.syncData(module, propertyName, value)

mm.syncData(fs, 'readFileSync', Buffer.from('some content'));

// equals

fs.readFileSync = function (...args) {
  return Buffer.from('some content');
};

.syncEmpty

mm.syncEmpty(fs, 'readFileSync');

// equals

fs.readFileSync = function (...args) {
  return;
}

.restore()

// restore all mock properties
mm.restore();

.http.request(mockUrl, mockResData, mockResHeaders) and .https.request(mockUrl, mockResData, mockResHeaders)

var { mm } = require('mm');
var http = require('http');

var mockURL = '/foo';
var mockResData = 'mock data';
var mockResHeaders = { server: 'mock server' };
mm.http.request(mockURL, mockResData, mockResHeaders);
mm.https.request(mockURL, mockResData, mockResHeaders);

// http
http.get({
  path: '/foo'
}, function (res) {
  console.log(res.headers); // should be mock headers
  var body = '';
  res.on('data', function (chunk) {
    body += chunk.toString();
  });
  res.on('end', function () {
    console.log(body); // should equal 'mock data'
  });
});

// https
https.get({
  path: '/foo'
}, function (res) {
  console.log(res.headers); // should be mock headers
  var body = '';
  res.on('data', function (chunk) {
    body += chunk.toString();
  });
  res.on('end', function () {
    console.log(body); // should equal 'mock data'
  });
});

.http.requestError(mockUrl, reqError, resError) and .https.requestError(mockUrl, reqError, resError)

var { mm } = require('mm');
var http = require('http');

var mockURL = '/foo';
var reqError = null;
var resError = 'mock res error';
mm.http.requestError(mockURL, reqError, resError);

var req = http.get({
  path: '/foo'
}, function (res) {
  console.log(res.statusCode, res.headers); // 200 but never emit `end` event
  res.on('end', fucntion () {
    console.log('never show this message');
  });
});
req.on('error', function (err) {
  console.log(err); // should return mock err: err.name === 'MockHttpResponseError'
});

.classMethod(instance, method, mockMethod)

class Foo {
  async fetch() {
    return 1;
  }
}

const foo = new Foo();
const foo1 = new Foo();

mm.classMethod(foo, 'fetch', async () => {
  return 3;
});
assert(await foo.fetch() === 3);
assert(await foo1.fetch() === 3);

License

MIT

Contributors

Contributors

Made with contributors-img.

changelog

Changelog

4.0.2 (2025-01-02)

Bug Fixes

  • allow call mm.restore on normal export (#63) (18f4f7c)

4.0.1 (2024-12-21)

Bug Fixes

4.0.0 (2024-12-20)

⚠ BREAKING CHANGES

  • drop Node.js < 18.19.0 support

part of https://github.com/eggjs/egg/issues/3644

https://github.com/eggjs/egg/issues/5257

Features

  • support cjs and esm both by tshy (#61) (f1eadcc)

3.4.0 (2023-12-09)

Features

  • support mock.dataWithAsyncDispose() (#59) (7581288)

3.3.0 (2023-05-16)

Features

3.2.4 (2023-05-16)

Bug Fixes

3.2.3 (2023-05-12)

Bug Fixes

3.2.2 (2023-04-02)

Bug Fixes

  • spy statistics is not reset after restore (#55) (97dcf42)

3.2.1 / 2022-11-20

fixes

3.2.0 / 2020-03-24

features

3.1.0 / 2020-03-13

features

3.0.3 / 2020-03-12

fixes

3.0.2 / 2020-03-01

fixes

3.0.1 / 2020-03-01

fixes

3.0.0 / 2020-03-01

features

others

2.5.0 / 2019-03-06

features

others

2.4.1 / 2018-08-27

fixes

2.4.0 / 2018-08-08

others

2.3.0 / 2018-08-07

features

2.2.2 / 2018-07-12

fixes

2.2.1 / 2018-07-11

fixes

2.2.0 / 2017-09-07

features

others

2.1.1 / 2017-09-06

fixes

others

2.1.0 / 2017-01-25

  • deps: use muk-prop instead of muk (#30)

2.0.1 / 2017-01-22

  • fix: Only restore the http/https request when used.

2.0.0 / 2016-07-31

  • feat: upgrade dependencies (#29)

1.5.1 / 2016-07-21

  • fix: keep status code (#28)

1.5.0 / 2016-06-13

  • feat: export isMocked (#27)

1.4.0 / 2016-06-12

  • deps: upgrade muk (#26)
  • feat: remove EventEmitter from 'event' module

1.3.5 / 2015-09-29

  • fix: should support mock multi env

1.3.4 / 2015-09-24

  • test: use codecov.io
  • feat: support mock process.env.KEY

1.3.3 / 2015-09-17

  • deps: upgrade muk to 0.4.0 to support mock getter

1.3.2 / 2015-09-17

  • fix: deps muk 0.3.2

1.3.1 / 2015-08-31

  • hotfix: fix mm.error in es6

1.3.0 / 2015-08-22

  • readme: add sync methods and error properties
  • feat: mock error support props
  • chore: use npm scripts

1.2.0 / 2015-08-16

  • feat(sync): add sync mock methods

1.1.0 / 2015-05-08

  • feat: support promise

1.0.1 / 2014-10-30

  • still thunkify the methods

1.0.0 / 2014-10-30

  • docs(readme): add badges
  • feat(error): support mock error on generator function
  • feat(data): support mock generator function

0.2.1 / 2014-03-14

  • if coveralls crash, dont break the test pass
  • fix http request mock not work on 0.11.12 and no more test on 0.8.x

0.2.0 / 2014-02-21

  • support thunkify cnpm/cnpmjs.org#196

0.1.8 / 2013-12-27

  • fix Node 0.11 broken. (@alsotang)
  • fix test cases

0.1.7 / 2013-11-20

  • http.request mock support mm.http.request({host: $host, url: $url})
  • add npm image

0.1.6 / 2013-07-04

0.1.5 / 2013-07-03

  • hot fixed #5 mock same method twices restore fails bug
  • add test for fs.readFileSync. fixed #5
  • support coveralls

0.1.4 / 2013-05-21

  • use blanket instead of jscover
  • fixed spawn test fail on node 0.6
  • support emtpy error

0.1.3 / 2013-05-05

  • Merge pull request #3 from dead-horse/support-spawn
  • do not emit when null
  • add support for spawn

0.1.2 / 2013-04-20

  • fix mm.datas
  • update travis

0.1.1 / 2013-04-15

  • update muk to 0.3.0+

0.1.0 / 2012-12-01

  • fixed restore not effect on http(s)

0.0.9 / 2012-11-28

  • add request() mock statusCode

0.0.8 / 2012-11-27

  • add mm.datas(), mm.data(), mm.empty() mock methods

0.0.7 / 2012-11-26

  • try to find callback in arguments
  • fixed CERT_HAS_EXPIRED with rejectUnauthorized = false

0.0.6 / 2012-11-21

  • fix http.request() twice bug; add res.setEncoding method

0.0.5 / 2012-11-21

  • fixed #1 support mm.https.request mock helpers

0.0.4 / 2012-11-13

  • add mm() just like muk() does

0.0.3 / 2012-11-06

  • add req.abort() for mock request object

0.0.2 / 2012-11-06

  • when mock response error, must emit req error not res error event.
  • replace logo

0.0.1 / 2012-11-04

  • add mock http.request() and http.requestError()
  • add mm.error() impl
  • Release 0.0.1