diff --git a/lib/mock-ajax.js b/lib/mock-ajax.js index 28c2c8d..7bb5615 100644 --- a/lib/mock-ajax.js +++ b/lib/mock-ajax.js @@ -37,13 +37,64 @@ getJasmineRequireObj().ajax = function(jRequire) { $ajax.RequestTracker = jRequire.AjaxRequestTracker(); $ajax.StubTracker = jRequire.AjaxStubTracker(); $ajax.ParamParser = jRequire.AjaxParamParser(); - $ajax.fakeRequest = jRequire.AjaxFakeRequest(); + $ajax.eventBus = jRequire.AjaxEventBus(); + $ajax.fakeRequest = jRequire.AjaxFakeRequest($ajax.eventBus); $ajax.MockAjax = jRequire.MockAjax($ajax); return $ajax.MockAjax; }; -getJasmineRequireObj().AjaxFakeRequest = function() { +getJasmineRequireObj().AjaxEventBus = function() { + function EventBus() { + this.eventList = {}; + } + + function ensureEvent(eventList, name) { + eventList[name] = eventList[name] || []; + return eventList[name]; + } + + function findIndex(list, thing) { + if (list.indexOf) { + return list.indexOf(thing); + } + + for(var i = 0; i < list.length; i++) { + if (thing === list[i]) { + return i; + } + } + + return -1; + } + + EventBus.prototype.addEventListener = function(event, callback) { + ensureEvent(this.eventList, event).push(callback); + }; + + EventBus.prototype.removeEventListener = function(event, callback) { + var index = findIndex(this.eventList[event], callback); + + if (index >= 0) { + this.eventList[event].splice(index, 1); + } + }; + + EventBus.prototype.trigger = function(event) { + var eventListeners = this.eventList[event]; + + if(eventListeners){ + for(var i = 0; i < eventListeners.length; i++){ + eventListeners[i](); + } + } + }; + + return function() { + return new EventBus(); + }; +}; +getJasmineRequireObj().AjaxFakeRequest = function(eventBusFactory) { function extend(destination, source, propertiesToSkip) { propertiesToSkip = propertiesToSkip || []; for (var property in source) { @@ -72,15 +123,13 @@ getJasmineRequireObj().AjaxFakeRequest = function() { } function initializeEvents(xhr) { - return { - 'loadstart': wrapProgressEvent(xhr, 'onloadstart'), - 'load': wrapProgressEvent(xhr, 'onload'), - 'loadend': wrapProgressEvent(xhr, 'onloadend'), - 'progress': wrapProgressEvent(xhr, 'onprogress'), - 'error': wrapProgressEvent(xhr, 'onerror'), - 'abort': wrapProgressEvent(xhr, 'onabort'), - 'timeout': wrapProgressEvent(xhr, 'ontimeout') - }; + xhr.eventBus.addEventListener('loadstart', wrapProgressEvent(xhr, 'onloadstart')); + xhr.eventBus.addEventListener('load', wrapProgressEvent(xhr, 'onload')); + xhr.eventBus.addEventListener('loadend', wrapProgressEvent(xhr, 'onloadend')); + xhr.eventBus.addEventListener('progress', wrapProgressEvent(xhr, 'onprogress')); + xhr.eventBus.addEventListener('error', wrapProgressEvent(xhr, 'onerror')); + xhr.eventBus.addEventListener('abort', wrapProgressEvent(xhr, 'onabort')); + xhr.eventBus.addEventListener('timeout', wrapProgressEvent(xhr, 'ontimeout')); } function unconvertibleResponseTypeMessage(type) { @@ -96,7 +145,8 @@ getJasmineRequireObj().AjaxFakeRequest = function() { function fakeRequest(global, requestTracker, stubTracker, paramParser) { function FakeXMLHttpRequest() { requestTracker.track(this); - this.events = initializeEvents(this); + this.eventBus = eventBusFactory(); + initializeEvents(this); this.requestHeaders = {}; this.overriddenMimeType = null; } @@ -181,9 +231,9 @@ getJasmineRequireObj().AjaxFakeRequest = function() { this.status = 0; this.statusText = "abort"; this.onreadystatechange(); - this.events.progress(); - this.events.abort(); - this.events.loadend(); + this.eventBus.trigger('progress'); + this.eventBus.trigger('abort'); + this.eventBus.trigger('loadend'); }, readyState: 0, @@ -199,22 +249,12 @@ getJasmineRequireObj().AjaxFakeRequest = function() { onreadystatechange: function(isTimeout) { }, - addEventListener: function(event, callback) { - var existingCallback = this.events[event], - self = this; - - this.events[event] = function() { - callback.apply(self, [{}]); - existingCallback(); - }; + addEventListener: function() { + this.eventBus.addEventListener.apply(this.eventBus, arguments); }, removeEventListener: function(event, callback) { - var existingCallback = this.events[event]; - - if(existingCallback){ - delete this.events[event]; - } + this.eventBus.removeEventListener.apply(this.eventBus, arguments); }, status: null, @@ -222,7 +262,7 @@ getJasmineRequireObj().AjaxFakeRequest = function() { send: function(data) { this.params = data; this.readyState = 2; - this.events.loadstart(); + this.eventBus.trigger('loadstart'); this.onreadystatechange(); var stub = stubTracker.findStub(this.url, data, this.method); @@ -312,9 +352,9 @@ getJasmineRequireObj().AjaxFakeRequest = function() { } this.onreadystatechange(); - this.events.progress(); - this.events.load(); - this.events.loadend(); + this.eventBus.trigger('progress'); + this.eventBus.trigger('load'); + this.eventBus.trigger('loadend'); }, responseTimeout: function() { @@ -324,9 +364,9 @@ getJasmineRequireObj().AjaxFakeRequest = function() { this.readyState = 4; jasmine.clock().tick(30000); this.onreadystatechange('timeout'); - this.events.progress(); - this.events.timeout(); - this.events.loadend(); + this.eventBus.trigger('progress'); + this.eventBus.trigger('timeout'); + this.eventBus.trigger('loadend'); }, responseError: function() { @@ -335,9 +375,9 @@ getJasmineRequireObj().AjaxFakeRequest = function() { } this.readyState = 4; this.onreadystatechange(); - this.events.progress(); - this.events.error(); - this.events.loadend(); + this.eventBus.trigger('progress'); + this.eventBus.trigger('error'); + this.eventBus.trigger('loadend'); } }); diff --git a/spec/eventBusSpec.js b/spec/eventBusSpec.js new file mode 100644 index 0000000..da4d074 --- /dev/null +++ b/spec/eventBusSpec.js @@ -0,0 +1,71 @@ +describe('EventBus', function() { + beforeEach(function() { + this.bus = getJasmineRequireObj().AjaxEventBus()(); + }); + + it('calls an event listener', function() { + var callback = jasmine.createSpy('callback'); + + this.bus.addEventListener('foo', callback); + this.bus.trigger('foo'); + + expect(callback).toHaveBeenCalled(); + }); + + it('only triggers callbacks for the specified event', function() { + var fooCallback = jasmine.createSpy('foo'), + barCallback = jasmine.createSpy('bar'); + + this.bus.addEventListener('foo', fooCallback); + this.bus.addEventListener('bar', barCallback); + + this.bus.trigger('foo'); + + expect(fooCallback).toHaveBeenCalled(); + expect(barCallback).not.toHaveBeenCalled(); + }); + + it('calls all the callbacks for the specified event', function() { + var callback1 = jasmine.createSpy('callback'); + var callback2 = jasmine.createSpy('otherCallback'); + + this.bus.addEventListener('foo', callback1); + this.bus.addEventListener('foo', callback2); + + this.bus.trigger('foo'); + + expect(callback1).toHaveBeenCalled(); + expect(callback2).toHaveBeenCalled(); + }); + + it('works if there are no callbacks for the event', function() { + var bus = this.bus; + expect(function() { + bus.trigger('notActuallyThere'); + }).not.toThrow(); + }); + + it('does not call listeners that have been removed', function() { + var callback = jasmine.createSpy('callback'); + + this.bus.addEventListener('foo', callback); + this.bus.removeEventListener('foo', callback); + this.bus.trigger('foo'); + + expect(callback).not.toHaveBeenCalled(); + }); + + it('only removes the specified callback', function() { + var callback1 = jasmine.createSpy('callback'); + var callback2 = jasmine.createSpy('otherCallback'); + + this.bus.addEventListener('foo', callback1); + this.bus.addEventListener('foo', callback2); + this.bus.removeEventListener('foo', callback2); + + this.bus.trigger('foo'); + + expect(callback1).toHaveBeenCalled(); + expect(callback2).not.toHaveBeenCalled(); + }); +}); \ No newline at end of file diff --git a/spec/fakeRequestSpec.js b/spec/fakeRequestSpec.js index f7998c5..19e2a9d 100644 --- a/spec/fakeRequestSpec.js +++ b/spec/fakeRequestSpec.js @@ -4,6 +4,14 @@ describe('FakeRequest', function() { this.stubTracker = { findStub: function() {} }; var parserInstance = this.parserInstance = jasmine.createSpy('parse'); this.paramParser = { findParser: function() { return { parse: parserInstance }; } }; + var eventBus = this.fakeEventBus = { + addEventListener: jasmine.createSpy('addEventListener'), + trigger: jasmine.createSpy('trigger'), + removeEventListener: jasmine.createSpy('removeEventListener') + }; + this.eventBusFactory = function() { + return eventBus; + }; this.fakeGlobal = { XMLHttpRequest: function() { this.extraAttribute = 'my cool attribute'; @@ -11,7 +19,7 @@ describe('FakeRequest', function() { DOMParser: window.DOMParser, ActiveXObject: window.ActiveXObject }; - this.FakeRequest = getJasmineRequireObj().AjaxFakeRequest()(this.fakeGlobal, this.requestTracker, this.stubTracker, this.paramParser); + this.FakeRequest = getJasmineRequireObj().AjaxFakeRequest(this.eventBusFactory)(this.fakeGlobal, this.requestTracker, this.stubTracker, this.paramParser); }); it('extends from the global XMLHttpRequest', function() { @@ -22,7 +30,7 @@ describe('FakeRequest', function() { it('skips XMLHttpRequest attributes that IE does not want copied', function() { // use real window here so it will correctly go red on IE if it breaks - var FakeRequest = getJasmineRequireObj().AjaxFakeRequest()(window, this.requestTracker, this.stubTracker, this.paramParser); + var FakeRequest = getJasmineRequireObj().AjaxFakeRequest(this.eventBusFactory)(window, this.requestTracker, this.stubTracker, this.paramParser); var request = new FakeRequest(); expect(request.responseBody).toBeUndefined(); @@ -197,186 +205,143 @@ describe('FakeRequest', function() { }); }); + it('registers on-style callback with the event bus', function() { + this.request = new this.FakeRequest(); + + expect(this.fakeEventBus.addEventListener).toHaveBeenCalledWith('loadstart', jasmine.any(Function)); + expect(this.fakeEventBus.addEventListener).toHaveBeenCalledWith('progress', jasmine.any(Function)); + expect(this.fakeEventBus.addEventListener).toHaveBeenCalledWith('abort', jasmine.any(Function)); + expect(this.fakeEventBus.addEventListener).toHaveBeenCalledWith('error', jasmine.any(Function)); + expect(this.fakeEventBus.addEventListener).toHaveBeenCalledWith('load', jasmine.any(Function)); + expect(this.fakeEventBus.addEventListener).toHaveBeenCalledWith('timeout', jasmine.any(Function)); + expect(this.fakeEventBus.addEventListener).toHaveBeenCalledWith('loadend', jasmine.any(Function)); + + this.request.onloadstart = jasmine.createSpy('loadstart'); + this.request.onprogress = jasmine.createSpy('progress'); + this.request.onabort = jasmine.createSpy('abort'); + this.request.onerror = jasmine.createSpy('error'); + this.request.onload = jasmine.createSpy('load'); + this.request.ontimeout = jasmine.createSpy('timeout'); + this.request.onloadend = jasmine.createSpy('loadend'); + + var args = this.fakeEventBus.addEventListener.calls.allArgs(); + for (var i = 0; i < args.length; i++) { + var eventName = args[i][0], + busCallback = args[i][1]; + + busCallback(); + expect(this.request['on' + eventName]).toHaveBeenCalled(); + } + }); + + it('delegates addEventListener to the eventBus', function() { + this.request = new this.FakeRequest(); + + this.request.addEventListener('foo', 'bar'); + + expect(this.fakeEventBus.addEventListener).toHaveBeenCalledWith('foo', 'bar'); + }); + + it('delegates removeEventListener to the eventBus', function() { + this.request = new this.FakeRequest(); + + this.request.removeEventListener('foo', 'bar'); + + expect(this.fakeEventBus.removeEventListener).toHaveBeenCalledWith('foo', 'bar'); + }); + describe('triggering progress events', function() { beforeEach(function() { this.request = new this.FakeRequest(); - - spyOn(this.request, 'onloadstart'); - spyOn(this.request, 'onprogress'); - spyOn(this.request, 'onabort'); - spyOn(this.request, 'onerror'); - spyOn(this.request, 'onload'); - spyOn(this.request, 'ontimeout'); - spyOn(this.request, 'onloadend'); - - var spies = {}; - - spies.loadstart1 = jasmine.createSpy('loadstart1'); - spies.loadstart2 = jasmine.createSpy('loadstart2'); - this.request.addEventListener('loadstart', spies.loadstart1); - this.request.addEventListener('loadstart', spies.loadstart2); - - spies.progress1 = jasmine.createSpy('progress1'); - spies.progress2 = jasmine.createSpy('progress2'); - this.request.addEventListener('progress', spies.progress1); - this.request.addEventListener('progress', spies.progress2); - - spies.abort1 = jasmine.createSpy('abort1'); - spies.abort2 = jasmine.createSpy('abort2'); - this.request.addEventListener('abort', spies.abort1); - this.request.addEventListener('abort', spies.abort2); - - spies.error1 = jasmine.createSpy('error1'); - spies.error2 = jasmine.createSpy('error2'); - this.request.addEventListener('error', spies.error1); - this.request.addEventListener('error', spies.error2); - - spies.load1 = jasmine.createSpy('load1'); - spies.load2 = jasmine.createSpy('load2'); - this.request.addEventListener('load', spies.load1); - this.request.addEventListener('load', spies.load2); - - spies.timeout1 = jasmine.createSpy('timeout1'); - spies.timeout2 = jasmine.createSpy('timeout2'); - this.request.addEventListener('timeout', spies.timeout1); - this.request.addEventListener('timeout', spies.timeout2); - - spies.loadend1 = jasmine.createSpy('loadend1'); - spies.loadend2 = jasmine.createSpy('loadend2'); - this.request.addEventListener('loadend', spies.loadend1); - this.request.addEventListener('loadend', spies.loadend2); - - this.resetEvents = function() { - var request = this.request; - var events = ['loadstart', 'progress', 'abort', 'error', 'load', 'timeout', 'loadend']; - for (var index in events) { - var event = events[index]; - request['on' + event].calls.reset(); - spies[event + '1'].calls.reset(); - spies[event + '2'].calls.reset(); - } - }; - - jasmine.addMatchers({ - toHaveTriggeredEvent: function(util) { - return { - compare: function(actual, expected) { - var direct = actual['on' + expected].calls.any(); - var event1 = spies[expected + '1'].calls.any(); - var event2 = spies[expected + '2'].calls.any(); - var pass = direct && event1 && event2; - - var missed = [], triggered = []; - - (direct ? triggered : missed).push('direct'); - (event1 ? triggered : missed).push(expected + '1'); - (event2 ? triggered : missed).push(expected + '2'); - - return { - pass: pass, - message: pass ? - 'Expected XHR not to have triggered ' + expected + ' but ' + triggered.join(', ') + ' triggered' : - 'Expected XHR to have triggered ' + expected + ' but ' + missed.join(', ') + " didn't trigger" - }; - } - }; - } - }); }); it('should not trigger any events to start', function() { this.request.open(); - expect(this.request).not.toHaveTriggeredEvent('loadstart'); - expect(this.request).not.toHaveTriggeredEvent('progress'); - expect(this.request).not.toHaveTriggeredEvent('abort'); - expect(this.request).not.toHaveTriggeredEvent('error'); - expect(this.request).not.toHaveTriggeredEvent('load'); - expect(this.request).not.toHaveTriggeredEvent('timeout'); - expect(this.request).not.toHaveTriggeredEvent('loadend'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalled(); }); it('should trigger loadstart when sent', function() { this.request.open(); this.request.send(); - expect(this.request).toHaveTriggeredEvent('loadstart'); - expect(this.request).not.toHaveTriggeredEvent('progress'); - expect(this.request).not.toHaveTriggeredEvent('abort'); - expect(this.request).not.toHaveTriggeredEvent('error'); - expect(this.request).not.toHaveTriggeredEvent('load'); - expect(this.request).not.toHaveTriggeredEvent('timeout'); - expect(this.request).not.toHaveTriggeredEvent('loadend'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('loadstart'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('progress'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('abort'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('error'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('load'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('timeout'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('loadend'); }); it('should trigger abort, progress, loadend when aborted', function() { this.request.open(); this.request.send(); - this.resetEvents(); + this.fakeEventBus.trigger.calls.reset(); this.request.abort(); - expect(this.request).not.toHaveTriggeredEvent('loadstart'); - expect(this.request).toHaveTriggeredEvent('progress'); - expect(this.request).toHaveTriggeredEvent('abort'); - expect(this.request).not.toHaveTriggeredEvent('error'); - expect(this.request).not.toHaveTriggeredEvent('load'); - expect(this.request).not.toHaveTriggeredEvent('timeout'); - expect(this.request).toHaveTriggeredEvent('loadend'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('loadstart'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('progress'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('abort'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('error'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('load'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('timeout'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('loadend'); }); it('should trigger error, progress, loadend when network error', function() { this.request.open(); this.request.send(); - this.resetEvents(); + this.fakeEventBus.trigger.calls.reset(); this.request.responseError(); - expect(this.request).not.toHaveTriggeredEvent('loadstart'); - expect(this.request).toHaveTriggeredEvent('progress'); - expect(this.request).not.toHaveTriggeredEvent('abort'); - expect(this.request).toHaveTriggeredEvent('error'); - expect(this.request).not.toHaveTriggeredEvent('load'); - expect(this.request).not.toHaveTriggeredEvent('timeout'); - expect(this.request).toHaveTriggeredEvent('loadend'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('loadstart'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('progress'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('abort'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('error'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('load'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('timeout'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('loadend'); }); it('should trigger timeout, progress, loadend when timing out', function() { this.request.open(); this.request.send(); - this.resetEvents(); + this.fakeEventBus.trigger.calls.reset(); jasmine.clock().install(); this.request.responseTimeout(); jasmine.clock().uninstall(); - expect(this.request).not.toHaveTriggeredEvent('loadstart'); - expect(this.request).toHaveTriggeredEvent('progress'); - expect(this.request).not.toHaveTriggeredEvent('abort'); - expect(this.request).not.toHaveTriggeredEvent('error'); - expect(this.request).not.toHaveTriggeredEvent('load'); - expect(this.request).toHaveTriggeredEvent('timeout'); - expect(this.request).toHaveTriggeredEvent('loadend'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('loadstart'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('progress'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('abort'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('error'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('load'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('timeout'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('loadend'); }); it('should trigger load, progress, loadend when responding', function() { this.request.open(); this.request.send(); - this.resetEvents(); + this.fakeEventBus.trigger.calls.reset(); this.request.respondWith({ status: 200 }); - expect(this.request).not.toHaveTriggeredEvent('loadstart'); - expect(this.request).toHaveTriggeredEvent('progress'); - expect(this.request).not.toHaveTriggeredEvent('abort'); - expect(this.request).not.toHaveTriggeredEvent('error'); - expect(this.request).toHaveTriggeredEvent('load'); - expect(this.request).not.toHaveTriggeredEvent('timeout'); - expect(this.request).toHaveTriggeredEvent('loadend'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('loadstart'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('progress'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('abort'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('error'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('load'); + expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('timeout'); + expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('loadend'); }); }); diff --git a/src/eventBus.js b/src/eventBus.js new file mode 100644 index 0000000..29d07a4 --- /dev/null +++ b/src/eventBus.js @@ -0,0 +1,50 @@ +getJasmineRequireObj().AjaxEventBus = function() { + function EventBus() { + this.eventList = {}; + } + + function ensureEvent(eventList, name) { + eventList[name] = eventList[name] || []; + return eventList[name]; + } + + function findIndex(list, thing) { + if (list.indexOf) { + return list.indexOf(thing); + } + + for(var i = 0; i < list.length; i++) { + if (thing === list[i]) { + return i; + } + } + + return -1; + } + + EventBus.prototype.addEventListener = function(event, callback) { + ensureEvent(this.eventList, event).push(callback); + }; + + EventBus.prototype.removeEventListener = function(event, callback) { + var index = findIndex(this.eventList[event], callback); + + if (index >= 0) { + this.eventList[event].splice(index, 1); + } + }; + + EventBus.prototype.trigger = function(event) { + var eventListeners = this.eventList[event]; + + if(eventListeners){ + for(var i = 0; i < eventListeners.length; i++){ + eventListeners[i](); + } + } + }; + + return function() { + return new EventBus(); + }; +}; \ No newline at end of file diff --git a/src/fakeRequest.js b/src/fakeRequest.js index b8b0f59..261460e 100644 --- a/src/fakeRequest.js +++ b/src/fakeRequest.js @@ -1,4 +1,4 @@ -getJasmineRequireObj().AjaxFakeRequest = function() { +getJasmineRequireObj().AjaxFakeRequest = function(eventBusFactory) { function extend(destination, source, propertiesToSkip) { propertiesToSkip = propertiesToSkip || []; for (var property in source) { @@ -27,15 +27,13 @@ getJasmineRequireObj().AjaxFakeRequest = function() { } function initializeEvents(xhr) { - return { - 'loadstart': wrapProgressEvent(xhr, 'onloadstart'), - 'load': wrapProgressEvent(xhr, 'onload'), - 'loadend': wrapProgressEvent(xhr, 'onloadend'), - 'progress': wrapProgressEvent(xhr, 'onprogress'), - 'error': wrapProgressEvent(xhr, 'onerror'), - 'abort': wrapProgressEvent(xhr, 'onabort'), - 'timeout': wrapProgressEvent(xhr, 'ontimeout') - }; + xhr.eventBus.addEventListener('loadstart', wrapProgressEvent(xhr, 'onloadstart')); + xhr.eventBus.addEventListener('load', wrapProgressEvent(xhr, 'onload')); + xhr.eventBus.addEventListener('loadend', wrapProgressEvent(xhr, 'onloadend')); + xhr.eventBus.addEventListener('progress', wrapProgressEvent(xhr, 'onprogress')); + xhr.eventBus.addEventListener('error', wrapProgressEvent(xhr, 'onerror')); + xhr.eventBus.addEventListener('abort', wrapProgressEvent(xhr, 'onabort')); + xhr.eventBus.addEventListener('timeout', wrapProgressEvent(xhr, 'ontimeout')); } function unconvertibleResponseTypeMessage(type) { @@ -51,7 +49,8 @@ getJasmineRequireObj().AjaxFakeRequest = function() { function fakeRequest(global, requestTracker, stubTracker, paramParser) { function FakeXMLHttpRequest() { requestTracker.track(this); - this.events = initializeEvents(this); + this.eventBus = eventBusFactory(); + initializeEvents(this); this.requestHeaders = {}; this.overriddenMimeType = null; } @@ -136,9 +135,9 @@ getJasmineRequireObj().AjaxFakeRequest = function() { this.status = 0; this.statusText = "abort"; this.onreadystatechange(); - this.events.progress(); - this.events.abort(); - this.events.loadend(); + this.eventBus.trigger('progress'); + this.eventBus.trigger('abort'); + this.eventBus.trigger('loadend'); }, readyState: 0, @@ -154,22 +153,12 @@ getJasmineRequireObj().AjaxFakeRequest = function() { onreadystatechange: function(isTimeout) { }, - addEventListener: function(event, callback) { - var existingCallback = this.events[event], - self = this; - - this.events[event] = function() { - callback.apply(self, [{}]); - existingCallback(); - }; + addEventListener: function() { + this.eventBus.addEventListener.apply(this.eventBus, arguments); }, removeEventListener: function(event, callback) { - var existingCallback = this.events[event]; - - if(existingCallback){ - delete this.events[event]; - } + this.eventBus.removeEventListener.apply(this.eventBus, arguments); }, status: null, @@ -177,7 +166,7 @@ getJasmineRequireObj().AjaxFakeRequest = function() { send: function(data) { this.params = data; this.readyState = 2; - this.events.loadstart(); + this.eventBus.trigger('loadstart'); this.onreadystatechange(); var stub = stubTracker.findStub(this.url, data, this.method); @@ -267,9 +256,9 @@ getJasmineRequireObj().AjaxFakeRequest = function() { } this.onreadystatechange(); - this.events.progress(); - this.events.load(); - this.events.loadend(); + this.eventBus.trigger('progress'); + this.eventBus.trigger('load'); + this.eventBus.trigger('loadend'); }, responseTimeout: function() { @@ -279,9 +268,9 @@ getJasmineRequireObj().AjaxFakeRequest = function() { this.readyState = 4; jasmine.clock().tick(30000); this.onreadystatechange('timeout'); - this.events.progress(); - this.events.timeout(); - this.events.loadend(); + this.eventBus.trigger('progress'); + this.eventBus.trigger('timeout'); + this.eventBus.trigger('loadend'); }, responseError: function() { @@ -290,9 +279,9 @@ getJasmineRequireObj().AjaxFakeRequest = function() { } this.readyState = 4; this.onreadystatechange(); - this.events.progress(); - this.events.error(); - this.events.loadend(); + this.eventBus.trigger('progress'); + this.eventBus.trigger('error'); + this.eventBus.trigger('loadend'); } }); diff --git a/src/requireAjax.js b/src/requireAjax.js index a20dccd..3659239 100644 --- a/src/requireAjax.js +++ b/src/requireAjax.js @@ -37,7 +37,8 @@ getJasmineRequireObj().ajax = function(jRequire) { $ajax.RequestTracker = jRequire.AjaxRequestTracker(); $ajax.StubTracker = jRequire.AjaxStubTracker(); $ajax.ParamParser = jRequire.AjaxParamParser(); - $ajax.fakeRequest = jRequire.AjaxFakeRequest(); + $ajax.eventBus = jRequire.AjaxEventBus(); + $ajax.fakeRequest = jRequire.AjaxFakeRequest($ajax.eventBus); $ajax.MockAjax = jRequire.MockAjax($ajax); return $ajax.MockAjax;