Skip to content

Commit

Permalink
feat: [BREAKING] don't allow to mock async function to normal function (
Browse files Browse the repository at this point in the history
#46)

drop node support 4, 6, now support node version >= 8
  • Loading branch information
fengmk2 committed Feb 29, 2020
1 parent eec0876 commit d8d9aa3
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 86 deletions.
9 changes: 5 additions & 4 deletions .travis.yml
@@ -1,13 +1,14 @@
sudo: false
language: node_js
node_js:
- '4'
- '6'
- '8'
- '10'
- '11'
- '12'
- '13'
before_install:
- npm i npminstall -g
install:
- npm i npminstall && npminstall
- npminstall
script:
- npm run ci
after_script:
Expand Down
12 changes: 5 additions & 7 deletions azure-pipelines.template.yml
Expand Up @@ -10,17 +10,15 @@ jobs:
vmImage: ${{ parameters.vmImage }}
strategy:
matrix:
node_4:
node_version: 4
node_6:
node_version: 6
node_8:
node_version: 8
node_10:
node_version: 10
node_11:
node_version: 11
maxParallel: 5
node_12:
node_version: 12
node_13:
node_version: 13
maxParallel: 4
steps:
- task: NodeTool@0
inputs:
Expand Down
19 changes: 14 additions & 5 deletions lib/es6.js
Expand Up @@ -7,18 +7,27 @@ const mm = require('./mm');
const mockDatas = mm.datas;
// support generator
mm.datas = function(mod, method, datas, timeout) {
if (!is.generatorFunction(mod[method])) {
const isGeneratorFunction = is.generatorFunction(mod[method]);
const isAsyncFunction = is.asyncFunction(mod[method]);
if (!isGeneratorFunction && !isAsyncFunction) {
return mockDatas.call(mm, mod, method, datas, timeout);
}

if (timeout) {
timeout = parseInt(timeout, 10);
}
timeout = timeout || 0;
mm(mod, method, function* () {
yield sleep(timeout);
return datas;
});
if (isGeneratorFunction) {
mm(mod, method, function* () {
yield sleep(timeout);
return datas;
});
} else {
mm(mod, method, async function() {
await sleep(timeout);
return datas;
});
}
return this;
};

Expand Down
9 changes: 8 additions & 1 deletion lib/mm.js
@@ -1,6 +1,7 @@
'use strict';

const EventEmitter = require('events');
const is = require('is-type-of');
const muk = require('muk-prop');
const http = require('http');
const https = require('https');
Expand All @@ -9,7 +10,13 @@ const thenify = require('thenify').withCallback;
const Readable = require('stream').Readable;
const Duplex = require('stream').Duplex;

const mock = module.exports = function mock() {
const mock = module.exports = function mock(target, property, value) {
if (typeof target[property] === 'function' && typeof value === 'function') {
// don't mock async function to normal function
if (is.asyncFunction(target[property]) && !is.asyncFunction(value)) {
throw TypeError('Can\'t mock async function to normal function');
}
}
return muk.apply(null, arguments);
};

Expand Down
32 changes: 16 additions & 16 deletions package.json
Expand Up @@ -15,26 +15,26 @@
"autod": "autod -w --prefix '^'"
},
"dependencies": {
"is-type-of": "^1.0.0",
"ko-sleep": "^1.0.2",
"muk-prop": "^1.0.0",
"thenify": "^3.2.1"
"is-type-of": "^1.2.1",
"ko-sleep": "^1.0.3",
"muk-prop": "^1.2.1",
"thenify": "^3.3.0"
},
"devDependencies": {
"autod": "^2.8.0",
"autod": "^3.1.0",
"chunkstream": "^0.0.1",
"co": "^4.6.0",
"egg-bin": "^1.10.3",
"egg-ci": "^1.9.1",
"enable": "^3.3.0",
"eslint": "^3.18.0",
"eslint-config-egg": "^3.2.0",
"egg-bin": "^1.11.1",
"egg-ci": "^1.13.1",
"enable": "^3.4.0",
"eslint": "^6.8.0",
"eslint-config-egg": "^8.0.1",
"node-patch": "*",
"pedding": "^1.1.0",
"should": "^11.2.1",
"should": "^13.2.3",
"thunkify-wrap": "^1.0.4",
"urllib": "^2.21.2",
"uuid": "^3.1.0"
"urllib": "^2.34.2",
"uuid": "^3.4.0"
},
"homepage": "http://github.com/node-modules/mm",
"repository": {
Expand All @@ -48,12 +48,12 @@
"test"
],
"engines": {
"node": ">=4.0.0"
"node": ">=8.0.0"
},
"ci": {
"type": "travis, azure-pipelines",
"version": "4, 6, 8, 10, 11"
"version": "8, 10, 12, 13"
},
"author": "fengmk2 <fengmk2@gmail.com> (http://fengmk2.com)",
"author": "fengmk2 <fengmk2@gmail.com> (https://fengmk2.com)",
"license": "MIT"
}
52 changes: 52 additions & 0 deletions test/async-await.js
@@ -0,0 +1,52 @@
'use strict';

const mm = require('..');

describe('test/async-await.test.js', () => {
const foo = {
async request() {
return 'yes';
},
};

afterEach(mm.restore);

describe('mm()', () => {
it('should mock async function', async () => {
let datas;
mm(foo, 'request', async () => {
return 'no';
});
datas = await foo.request();
datas.should.equal('no');

mm.restore();
datas = await foo.request();
datas.should.equal('yes');
});

it('should mock async function to normal throw type error', async () => {
try {
mm(foo, 'request', () => {
return 'no';
});
throw new Error('should not run this');
} catch (err) {
err.message.should.equal('Can\'t mock async function to normal function');
}
});
});

describe('datas(), data()', () => {
it('should mock async function', async () => {
let datas;
mm.datas(foo, 'request', 'no');
datas = await foo.request();
datas.should.equal('no');

mm.restore();
datas = await foo.request();
datas.should.equal('yes');
});
});
});
109 changes: 56 additions & 53 deletions test/mm.test.js
Expand Up @@ -461,31 +461,31 @@ describe('test/mm.test.js', () => {
});

it.skip('should mock ' + modName + '.request({url: "/bar/foo"}) with stream 500ms response delay',
function(done) {
const mockResData = new ChunkStream([ 'mock data with regex url', '哈哈' ]);
const mockResHeaders = { server: 'mock server' };
mm[modName].request({ url: '/bar/foo' }, mockResData, mockResHeaders, 500);
function(done) {
const mockResData = new ChunkStream([ 'mock data with regex url', '哈哈' ]);
const mockResHeaders = { server: 'mock server' };
mm[modName].request({ url: '/bar/foo' }, mockResData, mockResHeaders, 500);

const start = Date.now();
mod.get({
host: 'npmjs.org',
path: '/bar/foo',
}, function(res) {
res.headers.should.eql(mockResHeaders);
res.setEncoding('utf8');
let body = '';
res.on('data', function(chunk) {
chunk.should.be.a.String;
body += chunk;
});
res.on('end', function() {
const use = Date.now() - start;
body.should.equal([ 'mock data with regex url', '哈哈' ].join(''));
use.should.above(490);
done();
const start = Date.now();
mod.get({
host: 'npmjs.org',
path: '/bar/foo',
}, function(res) {
res.headers.should.eql(mockResHeaders);
res.setEncoding('utf8');
let body = '';
res.on('data', function(chunk) {
chunk.should.be.a.String;
body += chunk;
});
res.on('end', function() {
const use = Date.now() - start;
body.should.equal([ 'mock data with regex url', '哈哈' ].join(''));
use.should.above(490);
done();
});
});
});
});

it('should mock ' + modName + '.request({url: "/bar/foo"}) pipe res work', done => {
const mockResData = fs.createReadStream(__filename);
Expand All @@ -510,37 +510,37 @@ describe('test/mm.test.js', () => {
});

it('should mock ' + modName + '.request({url: "/bar/foo"}) with fs readstream no response delay',
function(done) {
const mockResData = fs.createReadStream(__filename);
const mockResHeaders = { server: 'mock server', statusCode: 201 };
mm[modName].request('', mockResData, mockResHeaders);
const length = 5;
done = pedding(length, done);
for (let i = 0; i < length; i++) {
mod.get({
host: 'npmjs.org',
path: '/bar/foo',
}, onResponse);
}
function onResponse(res) {
res.statusCode.should.equal(201);
res.headers.should.eql({ server: 'mock server' });
res.setEncoding('utf8');
let body = '';
res.on('data', function(chunk) {
console.log('data emit: chunk size: %d', chunk.length);
chunk.should.be.a.String;
body += chunk;
});
res.on('end', function() {
console.log('end emit: body size: %d', body.length);
const content = fs.readFileSync(__filename, 'utf8');
body.length.should.equal(body.length);
body.should.equal(content);
done();
});
}
});
function(done) {
const mockResData = fs.createReadStream(__filename);
const mockResHeaders = { server: 'mock server', statusCode: 201 };
mm[modName].request('', mockResData, mockResHeaders);
const length = 5;
done = pedding(length, done);
for (let i = 0; i < length; i++) {
mod.get({
host: 'npmjs.org',
path: '/bar/foo',
}, onResponse);
}
function onResponse(res) {
res.statusCode.should.equal(201);
res.headers.should.eql({ server: 'mock server' });
res.setEncoding('utf8');
let body = '';
res.on('data', function(chunk) {
console.log('data emit: chunk size: %d', chunk.length);
chunk.should.be.a.String;
body += chunk;
});
res.on('end', function() {
console.log('end emit: body size: %d', body.length);
const content = fs.readFileSync(__filename, 'utf8');
body.length.should.equal(body.length);
body.should.equal(content);
done();
});
}
});

it('should mock ' + modName + '.request({host: "cnodejs.org"}) 500ms response delay', function(done) {
const mockResData = [ 'mock data with regex url', '哈哈' ];
Expand Down Expand Up @@ -960,3 +960,6 @@ if (enable.generator) {
require('./es6');
require('./thunk');
}
if (enable.asyncArrowFunction) {
require('./async-await');
}

0 comments on commit d8d9aa3

Please sign in to comment.