Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/node-modules/mm
An simple but flexible mock(or say stub) package, mock mate
https://github.com/node-modules/mm
Last synced: 3 months ago
JSON representation
An simple but flexible mock(or say stub) package, mock mate
- Host: GitHub
- URL: https://github.com/node-modules/mm
- Owner: node-modules
- License: other
- Created: 2012-11-03T11:14:34.000Z (over 12 years ago)
- Default Branch: master
- Last Pushed: 2023-12-09T04:59:42.000Z (about 1 year ago)
- Last Synced: 2024-04-14T12:21:35.104Z (10 months ago)
- Language: JavaScript
- Homepage:
- Size: 323 KB
- Stars: 158
- Watchers: 18
- Forks: 16
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-nodejs - mm - An simple but flexible mock(or say stub) package, mock mate. ![](https://img.shields.io/github/stars/node-modules/mm.svg?style=social&label=Star) (Repository / Testing)
README
# mm, mock mate
[![NPM version][npm-image]][npm-url]
[![Node.js CI](https://github.com/node-modules/mm/actions/workflows/nodejs.yml/badge.svg)](https://github.com/node-modules/mm/actions/workflows/nodejs.yml)
[![Test coverage][codecov-image]][codecov-url]
[![npm download][download-image]][download-url][npm-image]: https://img.shields.io/npm/v/mm.svg?style=flat-square
[npm-url]: https://npmjs.org/package/mm
[codecov-image]: https://codecov.io/github/node-modules/mm/coverage.svg?branch=master
[codecov-url]: https://codecov.io/github/node-modules/mm?branch=master
[download-image]: https://img.shields.io/npm/dm/mm.svg?style=flat-square
[download-url]: https://npmjs.org/package/mmAn simple but flexible **mock(or say stub)** package, mock mate.
## Install
```bash
npm install mm --save-dev
```## Usage
```js
var mm = require('mm');
var fs = require('fs');mm(fs, 'readFileSync', function(filename) {
return filename + ' content';
});console.log(fs.readFileSync('《九评 Java》'));
// => 《九评 Java》 contentmm.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:
```js
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:
```js
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)
```js
var mm = require('mm');
var fs = require('fs');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.
```js
const mm = require('mm');
const fs = require('fs');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)
```js
mm.data(fs, 'readFile', new Buffer('some content'));// equals
fs.readFile = function (...args, callback) {
callback(null, new Buffer('some content'))
};
```### .dataWithAsyncDispose(module, propertyName, promiseResolveArg)
Support [Symbol.asyncDispose](https://www.totaltypescript.com/typescript-5-2-new-keyword-using)
```js
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:
```js
mm.dataWithAsyncDispose(locker, 'tryLock', {
locked: true,
});await using lock = await locker.tryLock('foo-key');
assert.equal(lock.locked, true);
```### .empty(module, propertyName)
```js
mm.empty(mysql, 'query');// equals
mysql.query = function (...args, callback) {
callback();
}
```### .datas(module, propertyName, argsArray)
```js
mm.datas(urllib, 'request', [new Buffer('data'), {headers: { foo: 'bar' }}]);// equals
urllib.request = function (...args, callback) {
callback(null, new Buffer('data'), {headers: { foo: 'bar' }});
}
```### .syncError(module, propertyName, errerMessage, errorProperties)
```js
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)
```js
mm.syncData(fs, 'readFileSync', new Buffer('some content'));// equals
fs.readFileSync = function (...args) {
return new Buffer('some content');
};
```### .syncEmpty
```js
mm.syncEmpty(fs, 'readFileSync');// equals
fs.readFileSync = function (...args) {
return;
}
```### .restore()
```js
// restore all mock properties
mm.restore();
```### .http.request(mockUrl, mockResData, mockResHeaders) and .https.request(mockUrl, mockResData, mockResHeaders)
```js
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)
```js
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)
```js
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](LICENSE)
## Contributors
|[
fengmk2](https://github.com/fengmk2)
|[
dead-horse](https://github.com/dead-horse)
|[
alsotang](https://github.com/alsotang)
|[
popomore](https://github.com/popomore)
|[
semantic-release-bot](https://github.com/semantic-release-bot)
|[
gemwuu](https://github.com/gemwuu)
|
| :---: | :---: | :---: | :---: | :---: | :---: |
|[
paranoidjk](https://github.com/paranoidjk)
|[
nightink](https://github.com/nightink)
|[
killagu](https://github.com/killagu)
|[
gxkl](https://github.com/gxkl)
|[
iyuq](https://github.com/iyuq)
|[
atian25](https://github.com/atian25)
|
[
xavierchow](https://github.com/xavierchow)
|[
whxaxes](https://github.com/whxaxes)This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Sat Dec 09 2023 11:34:46 GMT+0800`.