|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- "use strict";
-
- var fakeXhr = require("../fake-xhr");
- var push = [].push;
- var log = require("./log");
- var configureLogError = require("../configure-logger");
- var pathToRegexp = require("path-to-regexp");
-
- var supportsArrayBuffer = typeof ArrayBuffer !== "undefined";
-
- function responseArray(handler) {
- var response = handler;
-
- if (Object.prototype.toString.call(handler) !== "[object Array]") {
- response = [200, {}, handler];
- }
-
- if (typeof response[2] !== "string") {
- if (!supportsArrayBuffer) {
- throw new TypeError(
- `Fake server response body should be a string, but was ${typeof response[2]}`
- );
- } else if (!(response[2] instanceof ArrayBuffer)) {
- throw new TypeError(
- `Fake server response body should be a string or ArrayBuffer, but was ${typeof response[2]}`
- );
- }
- }
-
- return response;
- }
-
- function getDefaultWindowLocation() {
- var winloc = {
- hostname: "localhost",
- port: process.env.PORT || 80,
- protocol: "http:"
- };
- winloc.host =
- winloc.hostname +
- (String(winloc.port) === "80" ? "" : `:${winloc.port}`);
- return winloc;
- }
-
- function getWindowLocation() {
- if (typeof window === "undefined") {
- // Fallback
- return getDefaultWindowLocation();
- }
-
- if (typeof window.location !== "undefined") {
- // Browsers place location on window
- return window.location;
- }
-
- if (
- typeof window.window !== "undefined" &&
- typeof window.window.location !== "undefined"
- ) {
- // React Native on Android places location on window.window
- return window.window.location;
- }
-
- return getDefaultWindowLocation();
- }
-
- function matchOne(response, reqMethod, reqUrl) {
- var rmeth = response.method;
- var matchMethod = !rmeth || rmeth.toLowerCase() === reqMethod.toLowerCase();
- var url = response.url;
- var matchUrl =
- !url ||
- url === reqUrl ||
- (typeof url.test === "function" && url.test(reqUrl)) ||
- (typeof url === "function" && url(reqUrl) === true);
-
- return matchMethod && matchUrl;
- }
-
- function match(response, request) {
- var wloc = getWindowLocation();
-
- var rCurrLoc = new RegExp(`^${wloc.protocol}//${wloc.host}/`);
-
- var requestUrl = request.url;
-
- if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
- requestUrl = requestUrl.replace(rCurrLoc, "/");
- }
-
- if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
- if (typeof response.response === "function") {
- var ru = response.url;
- var args = [request].concat(
- ru && typeof ru.exec === "function"
- ? ru.exec(requestUrl).slice(1)
- : []
- );
- return response.response.apply(response, args);
- }
-
- return true;
- }
-
- return false;
- }
-
- function incrementRequestCount() {
- var count = ++this.requestCount;
-
- this.requested = true;
-
- this.requestedOnce = count === 1;
- this.requestedTwice = count === 2;
- this.requestedThrice = count === 3;
-
- this.firstRequest = this.getRequest(0);
- this.secondRequest = this.getRequest(1);
- this.thirdRequest = this.getRequest(2);
-
- this.lastRequest = this.getRequest(count - 1);
- }
-
- var fakeServer = {
- create: function(config) {
- var server = Object.create(this);
- server.configure(config);
- this.xhr = fakeXhr.useFakeXMLHttpRequest();
- server.requests = [];
- server.requestCount = 0;
- server.queue = [];
- server.responses = [];
-
- this.xhr.onCreate = function(xhrObj) {
- xhrObj.unsafeHeadersEnabled = function() {
- return !(server.unsafeHeadersEnabled === false);
- };
- server.addRequest(xhrObj);
- };
-
- return server;
- },
-
- configure: function(config) {
- var self = this;
- var allowlist = {
- autoRespond: true,
- autoRespondAfter: true,
- respondImmediately: true,
- fakeHTTPMethods: true,
- logger: true,
- unsafeHeadersEnabled: true
- };
-
- // eslint-disable-next-line no-param-reassign
- config = config || {};
-
- Object.keys(config).forEach(function(setting) {
- if (setting in allowlist) {
- self[setting] = config[setting];
- }
- });
-
- self.logError = configureLogError(config);
- },
-
- addRequest: function addRequest(xhrObj) {
- var server = this;
- push.call(this.requests, xhrObj);
-
- incrementRequestCount.call(this);
-
- xhrObj.onSend = function() {
- server.handleRequest(this);
-
- if (server.respondImmediately) {
- server.respond();
- } else if (server.autoRespond && !server.responding) {
- setTimeout(function() {
- server.responding = false;
- server.respond();
- }, server.autoRespondAfter || 10);
-
- server.responding = true;
- }
- };
- },
-
- getHTTPMethod: function getHTTPMethod(request) {
- if (this.fakeHTTPMethods && /post/i.test(request.method)) {
- var matches = (request.requestBody || "").match(
- /_method=([^\b;]+)/
- );
- return matches ? matches[1] : request.method;
- }
-
- return request.method;
- },
-
- handleRequest: function handleRequest(xhr) {
- if (xhr.async) {
- push.call(this.queue, xhr);
- } else {
- this.processRequest(xhr);
- }
- },
-
- logger: function() {
- // no-op; override via configure()
- },
-
- logError: configureLogError({}),
-
- log: log,
-
- respondWith: function respondWith(method, url, body) {
- if (arguments.length === 1 && typeof method !== "function") {
- this.response = responseArray(method);
- return;
- }
-
- if (arguments.length === 1) {
- // eslint-disable-next-line no-param-reassign
- body = method;
- // eslint-disable-next-line no-param-reassign
- url = method = null;
- }
-
- if (arguments.length === 2) {
- // eslint-disable-next-line no-param-reassign
- body = url;
- // eslint-disable-next-line no-param-reassign
- url = method;
- // eslint-disable-next-line no-param-reassign
- method = null;
- }
-
- // Escape port number to prevent "named" parameters in 'path-to-regexp' module
- if (typeof url === "string" && url !== "" && /:[0-9]+\//.test(url)) {
- var m = url.match(/^(https?:\/\/.*?):([0-9]+\/.*)$/);
- // eslint-disable-next-line no-param-reassign
- url = `${m[1]}\\:${m[2]}`;
- }
-
- push.call(this.responses, {
- method: method,
- url:
- typeof url === "string" && url !== "" ? pathToRegexp(url) : url,
- response: typeof body === "function" ? body : responseArray(body)
- });
- },
-
- respond: function respond() {
- if (arguments.length > 0) {
- this.respondWith.apply(this, arguments);
- }
-
- var queue = this.queue || [];
- var requests = queue.splice(0, queue.length);
- var self = this;
-
- requests.forEach(function(request) {
- self.processRequest(request);
- });
- },
-
- respondAll: function respondAll() {
- if (this.respondImmediately) {
- return;
- }
-
- this.queue = this.requests.slice(0);
-
- var request;
- while ((request = this.queue.shift())) {
- this.processRequest(request);
- }
- },
-
- processRequest: function processRequest(request) {
- try {
- if (request.aborted) {
- return;
- }
-
- var response = this.response || [404, {}, ""];
-
- if (this.responses) {
- for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
- if (match.call(this, this.responses[i], request)) {
- response = this.responses[i].response;
- break;
- }
- }
- }
-
- if (request.readyState !== 4) {
- this.log(response, request);
-
- request.respond(response[0], response[1], response[2]);
- }
- } catch (e) {
- this.logError("Fake server request processing", e);
- }
- },
-
- restore: function restore() {
- return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
- },
-
- getRequest: function getRequest(index) {
- return this.requests[index] || null;
- },
-
- reset: function reset() {
- this.resetBehavior();
- this.resetHistory();
- },
-
- resetBehavior: function resetBehavior() {
- this.responses.length = this.queue.length = 0;
- },
-
- resetHistory: function resetHistory() {
- this.requests.length = this.requestCount = 0;
-
- this.requestedOnce = this.requestedTwice = this.requestedThrice = this.requested = false;
-
- this.firstRequest = this.secondRequest = this.thirdRequest = this.lastRequest = null;
- }
- };
-
- module.exports = fakeServer;
|