123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- "use strict";
- var fakeXhr = require("../fake-xhr");
- var push = [].push;
- var format = require("./format");
- 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() {
- return { "host": "localhost", "protocol": "http" };
- }
- 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));
- 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 whitelist = {
- "autoRespond": true,
- "autoRespondAfter": true,
- "respondImmediately": true,
- "fakeHTTPMethods": true,
- "logger": true,
- "unsafeHeadersEnabled": true
- };
- config = config || {};
- Object.keys(config).forEach(function (setting) {
- if (setting in whitelist) {
- 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: function log(response, request) {
- var str;
- str = "Request:\n" + format(request) + "\n\n";
- str += "Response:\n" + format(response) + "\n\n";
- if (typeof this.logger === "function") {
- this.logger(str);
- }
- },
- respondWith: function respondWith(method, url, body) {
- if (arguments.length === 1 && typeof method !== "function") {
- this.response = responseArray(method);
- return;
- }
- if (arguments.length === 1) {
- body = method;
- url = method = null;
- }
- if (arguments.length === 2) {
- body = url;
- url = method;
- method = null;
- }
- 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);
- });
- },
- 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;
|