feat($browser): JSONP error handling

since we don't know if the error was due to a client error (4xx) or
server error (5xx), we leave the status code as undefined.
This commit is contained in:
Di Peng 2011-08-02 16:44:25 -07:00 committed by Igor Minar
parent 718ebf1fcf
commit 05e2c3196c
2 changed files with 93 additions and 23 deletions

View file

@ -100,12 +100,19 @@ function Browser(window, document, body, XHR, $log) {
outstandingRequestCount ++;
if (lowercase(method) == 'json') {
var callbackId = ("angular_" + Math.random() + '_' + (idCounter++)).replace(/\d\./, '');
var script = self.addJs(url.replace('JSON_CALLBACK', callbackId));
window[callbackId] = function(data){
window[callbackId] = function(data) {
window[callbackId].data = data;
};
var script = self.addJs(url.replace('JSON_CALLBACK', callbackId), null, function() {
if (window[callbackId].data) {
completeOutstandingRequest(callback, 200, window[callbackId].data);
} else {
completeOutstandingRequest(callback);
}
delete window[callbackId];
body[0].removeChild(script);
completeOutstandingRequest(callback, 200, data);
};
});
} else {
var xhr = new XHR();
xhr.open(method, url, true);
@ -452,7 +459,7 @@ function Browser(window, document, body, XHR, $log) {
* @description
* Adds a script tag to the head.
*/
self.addJs = function(url, domId) {
self.addJs = function(url, domId, done) {
// we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
// - fetches local scripts via XHR and evals them
// - adds and immediately removes script elements from the document
@ -465,6 +472,15 @@ function Browser(window, document, body, XHR, $log) {
script.type = 'text/javascript';
script.src = url;
if (domId) script.id = domId;
if (msie) {
script.onreadystatechange = function() {
/loaded|complete/.test(script.readyState) && done && done();
}
} else {
if (done) script.onload = script.onerror = done;
}
body[0].appendChild(script);
return script;

View file

@ -87,27 +87,81 @@ describe('browser', function(){
describe('xhr', function(){
describe('JSON', function(){
it('should add script tag for request', function() {
var callback = jasmine.createSpy('callback');
var log = "";
browser.xhr('JSON', 'http://example.org/path?cb=JSON_CALLBACK', null, function(code, data){
log += code + ':' + data + ';';
});
browser.notifyWhenNoOutstandingRequests(callback);
expect(callback).not.toHaveBeenCalled();
expect(scripts.length).toEqual(1);
var script = scripts[0];
var url = script.src.split('?cb=');
expect(url[0]).toEqual('http://example.org/path');
expect(typeof fakeWindow[url[1]]).toEqual($function);
fakeWindow[url[1]]('data');
expect(callback).toHaveBeenCalled();
expect(log).toEqual('200:data;');
expect(scripts).toEqual(removedScripts);
expect(fakeWindow[url[1]]).toBeUndefined();
var log;
function callback(code, data) {
log += code + ':' + data + ';';
}
beforeEach(function() {
log = "";
});
// We don't have unit tests for IE because script.readyState is readOnly.
// Instead we run e2e tests on all browsers - see e2e for $xhr.
if (!msie) {
it('should add script tag for JSONP request', function() {
var notify = jasmine.createSpy('notify');
browser.xhr('JSON', 'http://example.org/path?cb=JSON_CALLBACK', null, callback);
browser.notifyWhenNoOutstandingRequests(notify);
expect(notify).not.toHaveBeenCalled();
expect(scripts.length).toEqual(1);
var script = scripts[0];
var url = script.src.split('?cb=');
expect(url[0]).toEqual('http://example.org/path');
expect(typeof fakeWindow[url[1]]).toEqual($function);
fakeWindow[url[1]]('data');
script.onload();
expect(notify).toHaveBeenCalled();
expect(log).toEqual('200:data;');
expect(scripts).toEqual(removedScripts);
expect(fakeWindow[url[1]]).toBeUndefined();
});
it('should call callback when script fails to load', function() {
browser.xhr('JSON', 'http://example.org/path?cb=JSON_CALLBACK', null, callback);
var script = scripts[0];
expect(typeof script.onload).toBe($function);
expect(typeof script.onerror).toBe($function);
script.onerror();
expect(log).toEqual('undefined:undefined;');
});
it('should update the outstandingRequests counter for successful requests', function() {
var notify = jasmine.createSpy('notify');
browser.xhr('JSON', 'http://example.org/path?cb=JSON_CALLBACK', null, callback);
browser.notifyWhenNoOutstandingRequests(notify);
expect(notify).not.toHaveBeenCalled();
var script = scripts[0];
var url = script.src.split('?cb=');
fakeWindow[url[1]]('data');
script.onload();
expect(notify).toHaveBeenCalled();
});
it('should update the outstandingRequests counter for failed requests', function() {
var notify = jasmine.createSpy('notify');
browser.xhr('JSON', 'http://example.org/path?cb=JSON_CALLBACK', null, callback);
browser.notifyWhenNoOutstandingRequests(notify);
expect(notify).not.toHaveBeenCalled();
scripts[0].onerror();
expect(notify).toHaveBeenCalled();
});
}
});
it('should normalize IE\'s 1223 status code into 204', function() {
var callback = jasmine.createSpy('XHR');