UNPKG

http-request-mock

Version:

Intercept & mock http requests issued by XMLHttpRequest, fetch, nodejs https/http module, axios, jquery, superagent, ky, node-fetch, request, got or any other request libraries by intercepting XMLHttpRequest, fetch and nodejs native requests in low level.

419 lines 15.3 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var utils_1 = require("../common/utils"); var config_1 = require("../config"); var mock_item_1 = __importDefault(require("./mock-item")); var Mocker = /** @class */ (function () { function Mocker(proxyServer) { var _a; if (proxyServer === void 0) { proxyServer = ''; } this.disabled = false; this.log = false; this.proxyServer = ''; this.proxyMode = 'none'; if (Mocker.instance) { return Mocker.instance; } if (/^(matched@localhost:\d+)|(middleware@\/)$/.test(proxyServer)) { _a = proxyServer.split('@'), this.proxyMode = _a[0], this.proxyServer = _a[1]; } Mocker.instance = this; this.log = !(0, utils_1.isNodejs)(); this.mockConfigData = {}; this.groupLog([['[http-request-mock] is %cloaded.', 'color:inherit;font-weight:bold;']]); } Mocker.getInstance = function () { return new Mocker(); }; /** * Set global mock data configuration. * @param {object} mockConfigData */ Mocker.prototype.setMockData = function (mockConfigData) { for (var key in mockConfigData) { this.mock(mockConfigData[key]); } return this; }; /** * Add an mock item to global mock data configuration. * @param {string} key * @param {MockItem} val */ Mocker.prototype.addMockItem = function (key, val) { this.mockConfigData[key] = val; return this; }; /** * Reset global mock data configuration. */ Mocker.prototype.reset = function () { this.mockConfigData = {}; this.sendMsgToProxyServer('reset'); return this; }; /** * Enable mock function temporarily. * Not available in proxy mode. */ Mocker.prototype.enable = function () { this.disabled = false; this.sendMsgToProxyServer('enable'); this.groupLog([['[http-request-mock] is %cenabled.', 'color:green;font-weight:bold;']]); return this; }; /** * Disable mock function temporarily. * Not available in proxy mode. */ Mocker.prototype.disable = function () { this.disabled = true; this.sendMsgToProxyServer('disable'); this.groupLog([['[http-request-mock] is %cdisabled.', 'color:red;font-weight:bold;']]); return this; }; /** * Send a message to proxy server if in a proxy mode. * @param {string} msg */ Mocker.prototype.sendMsgToProxyServer = function (msg) { if (msg === void 0) { msg = ''; } if (!this.proxyServer) { return; } if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') { return; } if (typeof window !== 'undefined' && Object.prototype.toString.call(window) === '[object Window]' && typeof window.fetch === 'function') { window.fetch("http://".concat(this.proxyServer, "/__hrm_msg__/") + encodeURIComponent(msg)); } }; /** * Disable logs function temporarily. * Not available in proxy mode. */ Mocker.prototype.disableLog = function () { this.log = false; this.sendMsgToProxyServer('disableLog'); return this; }; /** * Disable logs function temporarily. * Not available in proxy mode. */ Mocker.prototype.enableLog = function () { this.log = true; this.sendMsgToProxyServer('enableLog'); return this; }; /** * Note: this method is only for a nodejs environment(test environment). * Use a mock file & add it to global mock data configuration. * @param {string} file */ Mocker.prototype.use = function (file) { throw new Error("Can not use mock case: ".concat(file, ", only for a nodejs environment")); }; /** * Check specified mock item & add it to global mock data configuration. * @param {MockItem} mockItem * @returns false | MockItem */ Mocker.prototype.mock = function (mockItemInfo) { if (!(0, utils_1.isObject)(mockItemInfo)) { throw new Error('Invalid mock item, a valid mock item must be an object.'); } var mockItem = new mock_item_1.default(mockItemInfo); if (!mockItem.key) return false; this.addMockItem(mockItem.key, mockItem); return mockItem; }; /** * Make a mock item that matches an HTTP GET request. * @param {RegExp | String} url * @param {unknown} body * @param {MockItemExt} opts { * @param {number} delay * @param {number} status * @param {object} header * @param {object} headers * @param {number} times * } */ Mocker.prototype.get = function (url, body, opts) { if (opts === void 0) { opts = { delay: 0, status: 200, times: Infinity, headers: {} }; } var delay = opts.delay, status = opts.status, times = opts.times, headers = opts.headers; this.mock({ url: url, method: 'GET', body: body, delay: delay, status: status, headers: headers, times: times }); return this; }; /** * Make a mock item that matches an HTTP POST request. * @param {RegExp | String} url * @param {any} body * @param {MockItemExt} opts { * @param {number} delay * @param {number} status * @param {object} header * @param {object} headers * @param {number} times * } */ Mocker.prototype.post = function (url, body, opts) { if (opts === void 0) { opts = { delay: 0, status: 200, times: Infinity, headers: {} }; } var delay = opts.delay, status = opts.status, times = opts.times, headers = opts.headers; this.mock({ url: url, method: 'POST', body: body, delay: delay, status: status, headers: headers, times: times }); return this; }; /** * Make a mock item that matches an HTTP PUT request. * @param {RegExp | String} url * @param {any} body * @param {MockItemExt} opts { * @param {number} delay * @param {number} status * @param {object} header * @param {object} headers * @param {number} times * } */ Mocker.prototype.put = function (url, body, opts) { if (opts === void 0) { opts = { delay: 0, status: 200, times: Infinity, headers: {} }; } var delay = opts.delay, status = opts.status, times = opts.times, headers = opts.headers; this.mock({ url: url, method: 'PUT', body: body, delay: delay, status: status, headers: headers, times: times }); return this; }; /** * Make a mock item that matches an HTTP PATCH request. * @param {RegExp | String} url * @param {any} body * @param {MockItemExt} opts { * @param {number} delay * @param {number} status * @param {object} header * @param {object} headers * @param {number} times * } */ Mocker.prototype.patch = function (url, body, opts) { if (opts === void 0) { opts = { delay: 0, status: 200, times: Infinity, headers: {} }; } var delay = opts.delay, status = opts.status, times = opts.times, headers = opts.headers; this.mock({ url: url, method: 'PATCH', body: body, delay: delay, status: status, headers: headers, times: times }); return this; }; /** * Make a mock item that matches an HTTP DELETE request. * @param {RegExp | String} url * @param {any} body * @param {MockItemExt} opts { * @param {number} delay * @param {number} status * @param {object} header * @param {object} headers * @param {number} times * } */ Mocker.prototype.delete = function (url, body, opts) { if (opts === void 0) { opts = { delay: 0, status: 200, times: Infinity, headers: {} }; } var delay = opts.delay, status = opts.status, times = opts.times, headers = opts.headers; this.mock({ url: url, method: 'DELETE', body: body, delay: delay, status: status, headers: headers, times: times }); return this; }; /** * https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD * Warning: A response to a HEAD method should not have a body. * If it has one anyway, that body must be ignored, any representation * headers that might describe the erroneous body are instead assumed * to describe the response which a similar GET request would have received. * * Make a mock item that matches an HTTP HEAD request. * @param {RegExp | String} url * @param {MockItemExt} opts { * @param {number} delay * @param {number} status * @param {object} header * @param {object} headers * @param {number} times * } */ Mocker.prototype.head = function (url, opts) { if (opts === void 0) { opts = { delay: 0, status: 200, times: Infinity, headers: {} }; } var delay = opts.delay, status = opts.status, times = opts.times, headers = opts.headers; this.mock({ url: url, method: 'HEAD', body: '', delay: delay, status: status, headers: headers, times: times }); return this; }; /** * Make a mock item that matches an HTTP GET, POST, PUT, PATCH, DELETE or HEAD request. * @param {RegExp | String} url * @param {unknown} body * @param {MockItemExt} opts { * @param {number} delay * @param {number} status * @param {object} header * @param {object} headers * @param {number} times * } */ Mocker.prototype.any = function (url, body, opts) { if (opts === void 0) { opts = { delay: 0, status: 200, times: Infinity, headers: {} }; } var delay = opts.delay, status = opts.status, times = opts.times, headers = opts.headers; this.mock({ url: url, method: 'ANY', body: body, delay: delay, status: status, headers: headers, times: times }); return this; }; /** * Check whether the specified request url matches a defined mock item. * If a match is found, return the matched mock item, otherwise a null is returned. * @param {string} reqUrl * @param {string} reqMethod * @return null | MockItem */ Mocker.prototype.matchMockItem = function (reqUrl, reqMethod) { if (this.disabled) { return null; } var requestMethod = (reqMethod || 'GET').toUpperCase(); var items = Object.values(this.mockConfigData).filter(function (_a) { var disable = _a.disable, times = _a.times, method = _a.method; var verb = String(method).toUpperCase(); return disable !== 'YES' && (times === undefined || times > 0) && (verb === 'ANY' || verb === requestMethod); }); for (var i = 0; i < 2; i++) { for (var _i = 0, items_1 = items; _i < items_1.length; _i++) { var info = items_1[_i]; try { if ((info.url instanceof RegExp) && info.url.test(reqUrl)) { return info; } var infoUrl = reqUrl.indexOf('//') === 0 // for the request urls which without http protocol ? String(info.url).replace(/^https?:/ig, '') : String(info.url); // [whole matching] takes precedence over partial matching if (i === 0 && reqUrl === infoUrl) { return info; } // whole matching takes precedence over [partial matching] if (i === 1 && reqUrl.indexOf(infoUrl) !== -1) { return info; } } catch (e) { // ignore match error, normally, user doesn't care it. } } } return null; }; /** * Set group logs * @param {Logs[]} logs * @returns */ Mocker.prototype.groupLog = function (logs) { if (!this.log) return; if (typeof console.groupCollapsed !== 'function') return; if (typeof console.groupEnd !== 'function') return; if (Array.isArray(logs[0])) { console.groupCollapsed.apply(console, logs[0]); } else { console.groupCollapsed(logs[0]); } for (var i = 1; i < logs.length; i++) { if (Array.isArray(logs[i])) { console.log.apply(console, logs[i]); } else { console.log(logs[i]); } } console.groupEnd(); }; Mocker.prototype.sendResponseLog = function (spent, body, requestInfo, mockItem) { var logs = [ [ '[http-request-mock] %s %s %s (%c%s%c)', "".concat((0, utils_1.currentTime)()), requestInfo.method, requestInfo.url, ('color:' + (mockItem.status < 300 ? 'green' : 'red')), mockItem.status, 'color:inherit', ], ['Request: ', requestInfo], ['Response: ', { body: body, spent: spent, headers: __assign(__assign({}, mockItem.headers), { 'x-powered-by': 'http-request-mock' }), status: mockItem.status, statusText: config_1.HTTPStatusCodes[mockItem.status] || '' }], // ['MockItem: ', mockItem] ]; if ((0, utils_1.isNodejs)()) { // less information for nodejs var url = mockItem.url, method = mockItem.method, delay = mockItem.delay, times = mockItem.times, status_1 = mockItem.status, disable = mockItem.disable; logs[3] = ['MockItem:', { url: url, method: method, delay: delay, times: times, status: status_1, disable: disable }]; } else { logs[3] = ['MockItem: ', mockItem]; } this.groupLog(logs); }; return Mocker; }()); exports.default = Mocker; //# sourceMappingURL=mocker.js.map