mock_httpclient.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. 'use strict';
  2. const mm = require('mm');
  3. const extend = require('extend2');
  4. const is = require('is-type-of');
  5. module.exports = function(app) {
  6. /**
  7. * mock httpclient
  8. * @function mockHttpclient
  9. * @param {String} mockUrl - url
  10. * @param {String|Array} mockMethod - http method
  11. * @param {Object} mockResult - you data
  12. * - data - buffer / string / json
  13. * - status - http status
  14. * - headers - response header
  15. * @return {Context} this
  16. */
  17. return function mockHttpclient(mockUrl, mockMethod, mockResult) {
  18. if (!mockResult) {
  19. // app.mockHttpclient(mockUrl, mockResult)
  20. mockResult = mockMethod;
  21. mockMethod = '*';
  22. }
  23. if (!Array.isArray(mockMethod)) mockMethod = [ mockMethod ];
  24. mockMethod = mockMethod.map(method => (method || 'GET').toUpperCase());
  25. const httpclient = app.httpclient;
  26. const rawRequest = httpclient.request;
  27. mm(httpclient, 'requestThunk', _request);
  28. mm(httpclient, 'request', _request);
  29. mm(httpclient, 'curl', _request);
  30. return app;
  31. function matchMethod(method) {
  32. return mockMethod.some(m => m === '*' || m === method);
  33. }
  34. function matchUrl(url) {
  35. if (url === mockUrl) return true;
  36. if (mockUrl instanceof RegExp && url.match(mockUrl)) return true;
  37. return false;
  38. }
  39. function normalizeResult(result) {
  40. if (is.string(result)) {
  41. result = { data: result };
  42. }
  43. if (!result.status) {
  44. result.status = 200;
  45. }
  46. result.data = result.data || '';
  47. if (Buffer.isBuffer(result.data)) {
  48. // do nothing
  49. } else if (typeof result.data === 'object') {
  50. // json
  51. result.data = Buffer.from(JSON.stringify(result.data));
  52. } else if (typeof result.data === 'string') {
  53. // string
  54. result.data = Buffer.from(result.data);
  55. } else {
  56. throw new Error('`mockResult.data` must be buffer, string or json');
  57. }
  58. if (!result.res) {
  59. result.res = {
  60. status: result.status,
  61. };
  62. }
  63. result.responseSize = result.responseSize || 0;
  64. if (result.data) {
  65. result.responseSize = result.data.length;
  66. }
  67. result.headers = result.headers || {};
  68. return result;
  69. }
  70. // support generator rather than callback and promise
  71. function _request(url, opt) {
  72. opt = opt || {};
  73. opt.method = (opt.method || 'GET').toUpperCase();
  74. opt.headers = opt.headers || {};
  75. if (matchUrl(url) && matchMethod(opt.method)) {
  76. const mockRequestResult = is.function(mockResult) ? mockResult(url, opt) : mockResult;
  77. const result = extend(true, {}, normalizeResult(mockRequestResult));
  78. const response = {
  79. status: result.status,
  80. statusCode: result.status,
  81. headers: result.headers,
  82. size: result.responseSize,
  83. aborted: false,
  84. rt: 1,
  85. keepAliveSocket: result.keepAliveSocket || false,
  86. };
  87. httpclient.emit('request', {
  88. reqId: Date.now(),
  89. url,
  90. args: opt,
  91. ctx: opt.ctx,
  92. });
  93. httpclient.emit('response', {
  94. error: null,
  95. ctx: opt.ctx,
  96. req: {
  97. url,
  98. options: opt,
  99. size: result.requestSize,
  100. },
  101. res: response,
  102. });
  103. if (opt.dataType === 'json') {
  104. try {
  105. result.data = JSON.parse(result.data);
  106. } catch (err) {
  107. err.name = 'JSONResponseFormatError';
  108. throw err;
  109. }
  110. } else if (opt.dataType === 'text') {
  111. result.data = result.data.toString();
  112. }
  113. return Promise.resolve(result);
  114. }
  115. return rawRequest.call(httpclient, url, opt);
  116. }
  117. };
  118. };