@4c/fetch-mock
Version:
Mock http requests made using fetch (or isomorphic-fetch)
200 lines (168 loc) • 7.24 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/json/stringify"));
var _typeof2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/typeof"));
var _parseInt2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/parse-int"));
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
var _keys = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/keys"));
var _every = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/every"));
var _some = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/some"));
var _assign = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/assign"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createClass"));
var responseConfigProps = ['body', 'headers', 'throws', 'status', 'redirectUrl'];
var ResponseBuilder =
/*#__PURE__*/
function () {
function ResponseBuilder(options) {
(0, _classCallCheck2["default"])(this, ResponseBuilder);
(0, _assign["default"])(this, options);
}
(0, _createClass2["default"])(ResponseBuilder, [{
key: "exec",
value: function exec() {
this.normalizeResponseConfig();
this.constructFetchOpts();
this.constructResponseBody();
return this.buildObservableResponse(new this.fetchMock.config.Response(this.body, this.options));
}
}, {
key: "sendAsObject",
value: function sendAsObject() {
var _this = this;
if ((0, _some["default"])(responseConfigProps).call(responseConfigProps, function (prop) {
return _this.responseConfig[prop];
})) {
var _context;
if ((0, _every["default"])(_context = (0, _keys["default"])(this.responseConfig)).call(_context, function (key) {
return (0, _includes["default"])(responseConfigProps).call(responseConfigProps, key);
})) {
return false;
} else {
return true;
}
} else {
return true;
}
}
}, {
key: "normalizeResponseConfig",
value: function normalizeResponseConfig() {
// If the response config looks like a status, start to generate a simple response
if (typeof this.responseConfig === 'number') {
this.responseConfig = {
status: this.responseConfig
}; // If the response config is not an object, or is an object that doesn't use
// any reserved properties, assume it is meant to be the body of the response
} else if (typeof this.responseConfig === 'string' || this.sendAsObject()) {
this.responseConfig = {
body: this.responseConfig
};
}
}
}, {
key: "validateStatus",
value: function validateStatus(status) {
if (!status) {
return 200;
}
if (typeof status === 'number' && (0, _parseInt2["default"])(status, 10) !== status && status >= 200 || status < 600) {
return status;
}
throw new TypeError("fetch-mock: Invalid status ".concat(status, " passed on response object.\nTo respond with a JSON object that has status as a property assign the object to body\ne.g. {\"body\": {\"status: \"registered\"}}"));
}
}, {
key: "constructFetchOpts",
value: function constructFetchOpts() {
this.options = this.responseConfig.options || {};
this.options.url = this.responseConfig.redirectUrl || this.url;
this.options.status = this.validateStatus(this.responseConfig.status);
this.options.statusText = this.fetchMock.statusTextMap['' + this.options.status]; // Set up response headers. The empty object is to cope with
// new Headers(undefined) throwing in Chrome
// https://code.google.com/p/chromium/issues/detail?id=335871
this.options.headers = new this.fetchMock.config.Headers(this.responseConfig.headers || {});
}
}, {
key: "getOption",
value: function getOption(name) {
return name in this.route ? this.route[name] : this.fetchMock.config[name];
}
}, {
key: "convertToJson",
value: function convertToJson() {
// convert to json if we need to
if (this.getOption('sendAsJson') && this.responseConfig.body != null && //eslint-disable-line
(0, _typeof2["default"])(this.body) === 'object') {
this.body = (0, _stringify["default"])(this.body);
if (!this.options.headers.has('Content-Type')) {
this.options.headers.set('Content-Type', 'application/json');
}
}
}
}, {
key: "setContentLength",
value: function setContentLength() {
// add a Content-Length header if we need to
if (this.getOption('includeContentLength') && typeof this.body === 'string' && !this.options.headers.has('Content-Length')) {
this.options.headers.set('Content-Length', this.body.length.toString());
}
}
}, {
key: "constructResponseBody",
value: function constructResponseBody() {
// start to construct the body
this.body = this.responseConfig.body;
this.convertToJson();
this.setContentLength(); // On the server we need to manually construct the readable stream for the
// Response object (on the client this done automatically)
if (this.Stream) {
var stream = new this.Stream.Readable();
if (this.body != null) {
//eslint-disable-line
stream.push(this.body, 'utf-8');
}
stream.push(null);
this.body = stream;
}
this.body = this.body;
}
}, {
key: "buildObservableResponse",
value: function buildObservableResponse(response) {
var _this2 = this;
var fetchMock = this.fetchMock; // Using a proxy means we can set properties that may not be writable on
// the original Response. It also means we can track the resolution of
// promises returned by res.json(), res.text() etc
return new Proxy(response, {
get: function get(originalResponse, name) {
if (_this2.responseConfig.redirectUrl) {
if (name === 'url') {
return _this2.responseConfig.redirectUrl;
}
if (name === 'redirected') {
return true;
}
}
if (typeof originalResponse[name] === 'function') {
return new Proxy(originalResponse[name], {
apply: function apply(func, thisArg, args) {
var result = func.apply(response, args);
if (result.then) {
fetchMock._holdingPromises.push(result["catch"](function () {
return null;
}));
}
return result;
}
});
}
return originalResponse[name];
}
});
}
}]);
return ResponseBuilder;
}();
module.exports = function (options) {
return new ResponseBuilder(options).exec();
};