129 lines
3.7 KiB
JavaScript
129 lines
3.7 KiB
JavaScript
|
(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);
|