Skip to content

Commit

Permalink
feat: add app.agent.mockHttpclient() for agent (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
limerickgds authored and dead-horse committed Aug 30, 2018
1 parent a29977e commit 283eef3
Show file tree
Hide file tree
Showing 5 changed files with 428 additions and 102 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,16 @@ app.mockHttpclient(/\/users\/[a-z]$/i, {
});
```

You can alse mock agent.httpclient

```js
app.agent.mockHttpclient('https://eggjs.org', {
data: {
name: 'egg',
},
});
```

## Bootstrap

We also provide a bootstrap file for applications' unit test to reduce duplicated code:
Expand Down
30 changes: 30 additions & 0 deletions app/extend/agent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';
const mm = require('mm');
const mockHttpclient = require('../../lib/mock_httpclient');

module.exports = {

/**
* mock httpclient
* @method Agent#mockHttpclient
* @return {Context} this
*/
mockHttpclient(...args) {
if (!this._mockHttpclient) {
this._mockHttpclient = mockHttpclient(this);
}
return this._mockHttpclient(...args);
},

/**
* @see mm#restore
* @method Agent#mockRestore
*/
mockRestore: mm.restore,

/**
* @see mm
* @method Agent#mm
*/
mm,
};
108 changes: 6 additions & 102 deletions app/extend/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const fs = require('fs');
const merge = require('merge-descriptors');
const is = require('is-type-of');
const assert = require('assert');
const extend = require('extend2');
const mockHttpclient = require('../../lib/mock_httpclient');
const supertestRequest = require('../../lib/supertest');

const ORIGIN_TYPES = Symbol('egg-mock:originTypes');
Expand Down Expand Up @@ -253,110 +253,13 @@ module.exports = {
/**
* mock httpclient
* @method App#mockHttpclient
* @param {String} mockUrl - url
* @param {String|Array} mockMethod - http method
* @param {Object} mockResult - you data
* - data - buffer / string / json
* - status - http status
* - headers - response header
* @return {Context} this
*/
mockHttpclient(mockUrl, mockMethod, mockResult) {
if (!mockResult) {
// app.mockHttpclient(mockUrl, mockResult)
mockResult = mockMethod;
mockMethod = '*';
}
if (!Array.isArray(mockMethod)) mockMethod = [ mockMethod ];
mockMethod = mockMethod.map(method => (method || 'GET').toUpperCase());

if (!mockResult.status) {
mockResult.status = 200;
}

mockResult.data = mockResult.data || '';
if (Buffer.isBuffer(mockResult.data)) {
// do nothing
} else if (typeof mockResult.data === 'object') {
// json
mockResult.data = new Buffer(JSON.stringify(mockResult.data));
} else if (typeof mockResult.data === 'string') {
// string
mockResult.data = new Buffer(mockResult.data);
} else {
throw new Error('`mockResult.data` must be buffer, string or json');
}

if (!mockResult.res) {
mockResult.res = {
status: mockResult.status,
};
}
mockResult.responseSize = mockResult.responseSize || 0;
if (mockResult.data) {
mockResult.responseSize = mockResult.data.length;
}
mockResult.headers = mockResult.headers || {};

const httpclient = this.httpclient;
const rawRequest = httpclient.request;

mm(httpclient, 'requestThunk', _request);
mm(httpclient, 'request', _request);
mm(httpclient, 'curl', _request);

return this;

function matchMethod(method) {
return mockMethod.some(m => m === '*' || m === method);
}
function matchUrl(url) {
if (url === mockUrl) return true;
if (mockUrl instanceof RegExp && url.match(mockUrl)) return true;
return false;
}

// support generator rather than callback and promise
function _request(url, opt) {
opt = opt || {};
opt.method = (opt.method || 'GET').toUpperCase();
opt.headers = opt.headers || {};
if (matchUrl(url) && matchMethod(opt.method)) {
const result = extend(true, {}, mockResult);
const response = {
status: result.status,
statusCode: result.status,
headers: result.headers,
size: result.responseSize,
aborted: false,
rt: 1,
keepAliveSocket: result.keepAliveSocket || false,
};

httpclient.emit('response', {
error: null,
ctx: opt.ctx,
req: {
url,
options: opt,
size: result.requestSize,
},
res: response,
});
if (opt.dataType === 'json') {
try {
result.data = JSON.parse(result.data);
} catch (err) {
err.name = 'JSONResponseFormatError';
throw err;
}
} else if (opt.dataType === 'text') {
result.data = result.data.toString();
}
return Promise.resolve(result);
}
return rawRequest.call(httpclient, url, opt);
mockHttpclient(...args) {
if (!this._mockHttpclient) {
this._mockHttpclient = mockHttpclient(this);
}
return this._mockHttpclient(...args);
},

mockUrllib(...args) {
Expand Down Expand Up @@ -447,6 +350,7 @@ module.exports = {
set _backgroundTasks(tasks) {
this[BACKGROUND_TASKS] = tasks;
},

};

function findHeaders(headers, key) {
Expand Down
115 changes: 115 additions & 0 deletions lib/mock_httpclient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
'use strict';
const mm = require('mm');
const extend = require('extend2');

module.exports = function(app) {
/**
* mock httpclient
* @method mockHttpclient
* @param {String} mockUrl - url
* @param {String|Array} mockMethod - http method
* @param {Object} mockResult - you data
* - data - buffer / string / json
* - status - http status
* - headers - response header
* @return {Context} this
*/
return function mockHttpclient(mockUrl, mockMethod, mockResult) {
if (!mockResult) {
// app.mockHttpclient(mockUrl, mockResult)
mockResult = mockMethod;
mockMethod = '*';
}
if (!Array.isArray(mockMethod)) mockMethod = [ mockMethod ];
mockMethod = mockMethod.map(method => (method || 'GET').toUpperCase());

if (!mockResult.status) {
mockResult.status = 200;
}

mockResult.data = mockResult.data || '';
if (Buffer.isBuffer(mockResult.data)) {
// do nothing
} else if (typeof mockResult.data === 'object') {
// json
mockResult.data = new Buffer(JSON.stringify(mockResult.data));
} else if (typeof mockResult.data === 'string') {
// string
mockResult.data = new Buffer(mockResult.data);
} else {
throw new Error('`mockResult.data` must be buffer, string or json');
}

if (!mockResult.res) {
mockResult.res = {
status: mockResult.status,
};
}
mockResult.responseSize = mockResult.responseSize || 0;
if (mockResult.data) {
mockResult.responseSize = mockResult.data.length;
}
mockResult.headers = mockResult.headers || {};

const httpclient = app.httpclient;

const rawRequest = httpclient.request;

mm(httpclient, 'requestThunk', _request);
mm(httpclient, 'request', _request);
mm(httpclient, 'curl', _request);

return app;

function matchMethod(method) {
return mockMethod.some(m => m === '*' || m === method);
}
function matchUrl(url) {
if (url === mockUrl) return true;
if (mockUrl instanceof RegExp && url.match(mockUrl)) return true;
return false;
}

// support generator rather than callback and promise
function _request(url, opt) {
opt = opt || {};
opt.method = (opt.method || 'GET').toUpperCase();
opt.headers = opt.headers || {};
if (matchUrl(url) && matchMethod(opt.method)) {
const result = extend(true, {}, mockResult);
const response = {
status: result.status,
statusCode: result.status,
headers: result.headers,
size: result.responseSize,
aborted: false,
rt: 1,
keepAliveSocket: result.keepAliveSocket || false,
};

httpclient.emit('response', {
error: null,
ctx: opt.ctx,
req: {
url,
options: opt,
size: result.requestSize,
},
res: response,
});
if (opt.dataType === 'json') {
try {
result.data = JSON.parse(result.data);
} catch (err) {
err.name = 'JSONResponseFormatError';
throw err;
}
} else if (opt.dataType === 'text') {
result.data = result.data.toString();
}
return Promise.resolve(result);
}
return rawRequest.call(httpclient, url, opt);
}
};
};
Loading

0 comments on commit 283eef3

Please sign in to comment.