(function(window){ var isNode = typeof process !== 'undefined' && process.toString() === '[object process]'; var RouteRecognizer = isNode ? require('route-recognizer')['default'] : window.RouteRecognizer; var FakeXMLHttpRequest = isNode ? require('./bower_components/FakeXMLHttpRequest/fake_xml_http_request') : window.FakeXMLHttpRequest; function Pretender(maps){ maps = maps || function(){}; // Herein we keep track of RouteRecognizer instances // keyed by HTTP method. Feel free to add more as needed. this.registry = { GET: new RouteRecognizer(), PUT: new RouteRecognizer(), POST: new RouteRecognizer(), DELETE: new RouteRecognizer(), PATCH: new RouteRecognizer(), HEAD: new RouteRecognizer() }; this.handlers = []; this.handledRequests = []; this.unhandledRequests = []; // reference the native XMLHttpRequest object so // it can be restored later this._nativeXMLHttpRequest = window.XMLHttpRequest; // capture xhr requests, channeling them into // the route map. window.XMLHttpRequest = interceptor(this); // trigger the route map DSL. maps.call(this); } function interceptor(pretender) { function FakeRequest(){ // super() FakeXMLHttpRequest.call(this); } // extend var proto = new FakeXMLHttpRequest(); proto.send = function send(){ FakeXMLHttpRequest.prototype.send.apply(this, arguments); pretender.handleRequest(this); }; FakeRequest.prototype = proto; return FakeRequest; } function verbify(verb){ return function(path, handler){ this.register(verb, path, handler); }; } Pretender.prototype = { get: verbify('GET'), post: verbify('POST'), put: verbify('PUT'), 'delete': verbify('DELETE'), patch: verbify('PATCH'), head: verbify('HEAD'), register: function register(verb, path, handler){ handler.numberOfCalls = 0; this.handlers.push(handler); var registry = this.registry[verb]; registry.add([{path: path, handler: handler}]); }, handleRequest: function handleRequest(request){ var verb = request.method.toUpperCase(); var path = request.url; var handler = this._handlerFor(verb, path, request); if (handler) { handler.handler.numberOfCalls++; this.handledRequests.push(request); try { var statusHeadersAndBody = handler.handler(request), status = statusHeadersAndBody[0], headers = statusHeadersAndBody[1], body = this.prepareBody(statusHeadersAndBody[2]); request.respond(status, headers, body); this.handledRequest(verb, path, request); } catch (error) { this.erroredRequest(verb, path, request, error); } } else { this.unhandledRequests.push(request); this.unhandledRequest(verb, path, request); } }, prepareBody: function(body){ return body; }, handledRequest: function(verb, path, request){/* no-op */}, unhandledRequest: function(verb, path, request) { throw new Error("Pretender intercepted "+verb+" "+path+" but no handler was defined for this type of request"); }, erroredRequest: function(verb, path, request, error){ error.message = "Pretender intercepted "+verb+" "+path+" but encountered an error: " + error.message; throw error; }, _handlerFor: function(verb, path, request){ var registry = this.registry[verb]; var matches = registry.recognize(path); var match = matches ? matches[0] : null; if (match) { request.params = match.params; request.queryParams = matches.queryParams; } return match; }, shutdown: function shutdown(){ window.XMLHttpRequest = this._nativeXMLHttpRequest; } }; if (isNode) { module.exports = Pretender; } else { window.Pretender = Pretender; } })(window);