Merge branch 'mjeanroy-issue_108'

Fixes #114
This commit is contained in:
Gregg Van Hove 2015-06-12 14:17:20 -07:00
commit 3807269d27
8 changed files with 224 additions and 45 deletions

View File

@ -37,16 +37,70 @@ getJasmineRequireObj().ajax = function(jRequire) {
$ajax.RequestTracker = jRequire.AjaxRequestTracker();
$ajax.StubTracker = jRequire.AjaxStubTracker();
$ajax.ParamParser = jRequire.AjaxParamParser();
$ajax.eventBus = jRequire.AjaxEventBus();
$ajax.event = jRequire.AjaxEvent();
$ajax.eventBus = jRequire.AjaxEventBus($ajax.event);
$ajax.fakeRequest = jRequire.AjaxFakeRequest($ajax.eventBus);
$ajax.MockAjax = jRequire.MockAjax($ajax);
return $ajax.MockAjax;
};
getJasmineRequireObj().AjaxEventBus = function() {
function EventBus() {
getJasmineRequireObj().AjaxEvent = function() {
function now() {
return new Date().getTime();
}
function noop() {
}
// Event object
// https://dom.spec.whatwg.org/#concept-event
function XMLHttpRequestEvent(xhr, type) {
this.type = type;
this.bubbles = false;
this.cancelable = false;
this.timeStamp = now();
this.isTrusted = false;
this.defaultPrevented = false;
// Event phase should be "AT_TARGET"
// https://dom.spec.whatwg.org/#dom-event-at_target
this.eventPhase = 2;
this.target = xhr;
this.currentTarget = xhr;
}
XMLHttpRequestEvent.prototype.preventDefault = noop;
XMLHttpRequestEvent.prototype.stopPropagation = noop;
XMLHttpRequestEvent.prototype.stopImmediatePropagation = noop;
function XMLHttpRequestProgressEvent() {
XMLHttpRequestEvent.apply(this, arguments);
this.lengthComputable = false;
this.loaded = 0;
this.total = 0;
}
// Extend prototype
XMLHttpRequestProgressEvent.prototype = XMLHttpRequestEvent.prototype;
return {
event: function(xhr, type) {
return new XMLHttpRequestEvent(xhr, type);
},
progressEvent: function(xhr, type) {
return new XMLHttpRequestProgressEvent(xhr, type);
}
};
};
getJasmineRequireObj().AjaxEventBus = function(eventFactory) {
function EventBus(source) {
this.eventList = {};
this.source = source;
}
function ensureEvent(eventList, name) {
@ -68,10 +122,6 @@ getJasmineRequireObj().AjaxEventBus = function() {
return -1;
}
function slice(array, start) {
return Array.prototype.slice.call(array, start);
}
EventBus.prototype.addEventListener = function(event, callback) {
ensureEvent(this.eventList, event).push(callback);
};
@ -85,21 +135,31 @@ getJasmineRequireObj().AjaxEventBus = function() {
};
EventBus.prototype.trigger = function(event) {
// Arguments specified after event name need to be propagated
var args = slice(arguments, 1);
var evt;
// Event 'readystatechange' is should be a simple event.
// Others are progress event.
// https://xhr.spec.whatwg.org/#events
if (event === 'readystatechange') {
evt = eventFactory.event(this.source, event);
} else {
evt = eventFactory.progressEvent(this.source, event);
}
var eventListeners = this.eventList[event];
if(eventListeners){
for(var i = 0; i < eventListeners.length; i++){
eventListeners[i].apply(this, args);
if (eventListeners) {
for (var i = 0; i < eventListeners.length; i++) {
eventListeners[i].call(this.source, evt);
}
}
};
return function() {
return new EventBus();
return function(source) {
return new EventBus(source);
};
};
getJasmineRequireObj().AjaxFakeRequest = function(eventBusFactory) {
function extend(destination, source, propertiesToSkip) {
propertiesToSkip = propertiesToSkip || [];
@ -152,7 +212,7 @@ getJasmineRequireObj().AjaxFakeRequest = function(eventBusFactory) {
function fakeRequest(global, requestTracker, stubTracker, paramParser) {
function FakeXMLHttpRequest() {
requestTracker.track(this);
this.eventBus = eventBusFactory();
this.eventBus = eventBusFactory(this);
initializeEvents(this);
this.requestHeaders = {};
this.overriddenMimeType = null;
@ -257,7 +317,7 @@ getJasmineRequireObj().AjaxFakeRequest = function(eventBusFactory) {
addEventListener: function() {
this.eventBus.addEventListener.apply(this.eventBus, arguments);
},
removeEventListener: function(event, callback) {
this.eventBus.removeEventListener.apply(this.eventBus, arguments);
},
@ -376,7 +436,7 @@ getJasmineRequireObj().AjaxFakeRequest = function(eventBusFactory) {
}
this.readyState = 4;
jasmine.clock().tick(30000);
this.eventBus.trigger('readystatechange', 'timeout');
this.eventBus.trigger('readystatechange');
this.eventBus.trigger('progress');
this.eventBus.trigger('timeout');
this.eventBus.trigger('loadend');

View File

@ -1,24 +1,46 @@
describe('EventBus', function() {
beforeEach(function() {
this.bus = getJasmineRequireObj().AjaxEventBus()();
var event = this.event = jasmine.createSpyObj('event', [
'preventDefault',
'stopPropagation',
'stopImmediatePropagation'
]);
var progressEvent = this.progressEvent = jasmine.createSpyObj('progressEvent', [
'preventDefault',
'stopPropagation',
'stopImmediatePropagation'
]);
var eventFactory = this.eventFactory = {
event: jasmine.createSpy('event').and.returnValue(event),
progressEvent: jasmine.createSpy('progressEvent').and.returnValue(progressEvent)
};
this.xhr = jasmine.createSpy('xhr');
this.bus = getJasmineRequireObj().AjaxEventBus(eventFactory)(this.xhr);
});
it('calls an event listener', function() {
it('calls an event listener with event object', function() {
var callback = jasmine.createSpy('callback');
this.bus.addEventListener('foo', callback);
this.bus.trigger('foo');
expect(callback).toHaveBeenCalled();
expect(callback).toHaveBeenCalledWith(this.progressEvent);
expect(this.eventFactory.progressEvent).toHaveBeenCalledWith(this.xhr, 'foo');
expect(this.eventFactory.event).not.toHaveBeenCalled();
});
it('calls an event listener with additional arguments', function() {
it('calls an readystatechange listener with event object', function() {
var callback = jasmine.createSpy('callback');
this.bus.addEventListener('foo', callback);
this.bus.trigger('foo', 'bar');
this.bus.addEventListener('readystatechange', callback);
this.bus.trigger('readystatechange');
expect(callback).toHaveBeenCalledWith('bar');
expect(callback).toHaveBeenCalledWith(this.event);
expect(this.eventFactory.event).toHaveBeenCalledWith(this.xhr, 'readystatechange');
expect(this.eventFactory.progressEvent).not.toHaveBeenCalled();
});
it('only triggers callbacks for the specified event', function() {
@ -77,4 +99,4 @@ describe('EventBus', function() {
expect(callback1).toHaveBeenCalled();
expect(callback2).not.toHaveBeenCalled();
});
});
});

38
spec/eventSpec.js Normal file
View File

@ -0,0 +1,38 @@
describe('Event', function() {
beforeEach(function() {
this.eventFactory = getJasmineRequireObj().AjaxEvent();
this.xhr = jasmine.createSpy('xhr');
});
it('create an event', function() {
var event = this.eventFactory.event(this.xhr, 'readystatechange');
expect(event.type).toBe('readystatechange');
expect(event.currentTarget).toBe(this.xhr);
expect(event.target).toBe(this.xhr);
expect(event.cancelable).toBe(false);
expect(event.bubbles).toBe(false);
expect(event.defaultPrevented).toBe(false);
expect(event.eventPhase).toBe(2);
expect(event.timeStamp).toBeDefined();
expect(event.isTrusted).toBe(false);
});
it('create a progress event', function() {
var event = this.eventFactory.progressEvent(this.xhr, 'loadend');
expect(event.type).toBe('loadend');
expect(event.currentTarget).toBe(this.xhr);
expect(event.target).toBe(this.xhr);
expect(event.cancelable).toBe(false);
expect(event.bubbles).toBe(false);
expect(event.defaultPrevented).toBe(false);
expect(event.eventPhase).toBe(2);
expect(event.timeStamp).toBeDefined();
expect(event.isTrusted).toBe(false);
expect(event.lengthComputable).toBe(false);
expect(event.loaded).toBe(0);
expect(event.total).toBe(0);
});
});

View File

@ -146,7 +146,7 @@ describe('FakeRequest', function() {
jasmine.clock().uninstall();
expect(this.request.readyState).toBe(4);
expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('readystatechange', 'timeout');
expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('readystatechange');
});
it('has a ready state of 4 (loaded) when network erroring', function() {
@ -364,7 +364,7 @@ describe('FakeRequest', function() {
jasmine.clock().uninstall();
expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('loadstart');
expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('readystatechange', 'timeout');
expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('readystatechange');
expect(this.fakeEventBus.trigger).toHaveBeenCalledWith('progress');
expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('abort');
expect(this.fakeEventBus.trigger).not.toHaveBeenCalledWith('error');

52
src/event.js Normal file
View File

@ -0,0 +1,52 @@
getJasmineRequireObj().AjaxEvent = function() {
function now() {
return new Date().getTime();
}
function noop() {
}
// Event object
// https://dom.spec.whatwg.org/#concept-event
function XMLHttpRequestEvent(xhr, type) {
this.type = type;
this.bubbles = false;
this.cancelable = false;
this.timeStamp = now();
this.isTrusted = false;
this.defaultPrevented = false;
// Event phase should be "AT_TARGET"
// https://dom.spec.whatwg.org/#dom-event-at_target
this.eventPhase = 2;
this.target = xhr;
this.currentTarget = xhr;
}
XMLHttpRequestEvent.prototype.preventDefault = noop;
XMLHttpRequestEvent.prototype.stopPropagation = noop;
XMLHttpRequestEvent.prototype.stopImmediatePropagation = noop;
function XMLHttpRequestProgressEvent() {
XMLHttpRequestEvent.apply(this, arguments);
this.lengthComputable = false;
this.loaded = 0;
this.total = 0;
}
// Extend prototype
XMLHttpRequestProgressEvent.prototype = XMLHttpRequestEvent.prototype;
return {
event: function(xhr, type) {
return new XMLHttpRequestEvent(xhr, type);
},
progressEvent: function(xhr, type) {
return new XMLHttpRequestProgressEvent(xhr, type);
}
};
};

View File

@ -1,6 +1,7 @@
getJasmineRequireObj().AjaxEventBus = function() {
function EventBus() {
getJasmineRequireObj().AjaxEventBus = function(eventFactory) {
function EventBus(source) {
this.eventList = {};
this.source = source;
}
function ensureEvent(eventList, name) {
@ -22,10 +23,6 @@ getJasmineRequireObj().AjaxEventBus = function() {
return -1;
}
function slice(array, start) {
return Array.prototype.slice.call(array, start);
}
EventBus.prototype.addEventListener = function(event, callback) {
ensureEvent(this.eventList, event).push(callback);
};
@ -39,18 +36,27 @@ getJasmineRequireObj().AjaxEventBus = function() {
};
EventBus.prototype.trigger = function(event) {
// Arguments specified after event name need to be propagated
var args = slice(arguments, 1);
var evt;
// Event 'readystatechange' is should be a simple event.
// Others are progress event.
// https://xhr.spec.whatwg.org/#events
if (event === 'readystatechange') {
evt = eventFactory.event(this.source, event);
} else {
evt = eventFactory.progressEvent(this.source, event);
}
var eventListeners = this.eventList[event];
if(eventListeners){
for(var i = 0; i < eventListeners.length; i++){
eventListeners[i].apply(this, args);
if (eventListeners) {
for (var i = 0; i < eventListeners.length; i++) {
eventListeners[i].call(this.source, evt);
}
}
};
return function() {
return new EventBus();
return function(source) {
return new EventBus(source);
};
};
};

View File

@ -50,7 +50,7 @@ getJasmineRequireObj().AjaxFakeRequest = function(eventBusFactory) {
function fakeRequest(global, requestTracker, stubTracker, paramParser) {
function FakeXMLHttpRequest() {
requestTracker.track(this);
this.eventBus = eventBusFactory();
this.eventBus = eventBusFactory(this);
initializeEvents(this);
this.requestHeaders = {};
this.overriddenMimeType = null;
@ -155,7 +155,7 @@ getJasmineRequireObj().AjaxFakeRequest = function(eventBusFactory) {
addEventListener: function() {
this.eventBus.addEventListener.apply(this.eventBus, arguments);
},
removeEventListener: function(event, callback) {
this.eventBus.removeEventListener.apply(this.eventBus, arguments);
},
@ -274,7 +274,7 @@ getJasmineRequireObj().AjaxFakeRequest = function(eventBusFactory) {
}
this.readyState = 4;
jasmine.clock().tick(30000);
this.eventBus.trigger('readystatechange', 'timeout');
this.eventBus.trigger('readystatechange');
this.eventBus.trigger('progress');
this.eventBus.trigger('timeout');
this.eventBus.trigger('loadend');

View File

@ -37,7 +37,8 @@ getJasmineRequireObj().ajax = function(jRequire) {
$ajax.RequestTracker = jRequire.AjaxRequestTracker();
$ajax.StubTracker = jRequire.AjaxStubTracker();
$ajax.ParamParser = jRequire.AjaxParamParser();
$ajax.eventBus = jRequire.AjaxEventBus();
$ajax.event = jRequire.AjaxEvent();
$ajax.eventBus = jRequire.AjaxEventBus($ajax.event);
$ajax.fakeRequest = jRequire.AjaxFakeRequest($ajax.eventBus);
$ajax.MockAjax = jRequire.MockAjax($ajax);