Skip to content

Instantly share code, notes, and snippets.

@twasink
Created September 16, 2019 13:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save twasink/7597f9fbe0cb49564ae9db51111209a8 to your computer and use it in GitHub Desktop.
Save twasink/7597f9fbe0cb49564ae9db51111209a8 to your computer and use it in GitHub Desktop.
An attempt to explore how error handling in ExtJS AJAX requests work. Use ExtJS, Jasmine
/**
* An attempt to explore how error handling in ExtJS AJAX requests work,
* in particular looking at ways to re-try requests and cope with
* both the conventional 'success/fail/callback' style and this
* new-fangled 'then/always/otherwise' promise approach.
*/
describe("Twasink.spike.AjaxErrorHandlingSpikeSpec", function() {
var successHandler;
var failHandler;
var alwaysHandler;
beforeEach(function() {
successHandler = jasmine.createSpy("success");
failHandler = jasmine.createSpy("fail");
alwaysHandler = jasmine.createSpy("always");
})
beforeEach(function() {
jasmine.Ajax.install();
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
beforeAll(function() {
Ext.Ajax.on('requestexception', 'listener', ajaxErrorHandler);
})
beforeEach(function() {
ajaxErrorHandler.called = false;
})
afterEach(function() {
ajaxErrorHandler.originalOptions = null;
ajaxErrorHandler.originalDeferred = null;
})
// Each approach for making an AJAX call differs in calling style, but should all be
// treated the same. To facilitate this, I'm using a little meta-programming here,
// defining a test suit as an object that I can call into multiple times,
// each time with a new ajax handler.
function runAjaxTests(title, ajaxCall) {
describe(title, function() {
function makeAjaxCall() {
ajaxCall();
expect(jasmine.Ajax.requests.mostRecent().url).toBe('http://example.org/');
}
// Prove I know how to make a normal call that works.
it("successful call example", function(done) {
makeAjaxCall();
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200
});
Ext.asap(function() {
expect(ajaxErrorHandler.called).not.toBeTruthy();
expect(successHandler.calls.count()).toEqual(1);
expect(failHandler.calls.count()).toEqual(0);
expect(alwaysHandler.calls.count()).toEqual(1);
done()
})
})
// Prove I know how to make a normal call that fails.
it("unhandled error example", function(done) {
makeAjaxCall();
jasmine.Ajax.requests.mostRecent().respondWith({
status: 500
});
Ext.asap(function() {
expect(ajaxErrorHandler.called).toBeTruthy();
expect(successHandler.calls.count()).toEqual(0);
expect(failHandler.calls.count()).toEqual(1);
expect(alwaysHandler.calls.count()).toEqual(1);
done();
})
})
// Prove I know how to make a normal call that fails and is retried.
it("handled error", function(done) {
makeAjaxCall();
expect(ajaxErrorHandler.called).not.toBeTruthy();
expect(jasmine.Ajax.requests.count()).toEqual(1);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 401
});
expect(ajaxErrorHandler.called).toBeTruthy();
// Nothing should have been called.
expect(successHandler.calls.count()).toEqual(0);
expect(failHandler.calls.count()).toEqual(0);
expect(alwaysHandler.calls.count()).toEqual(0);
ajaxErrorHandler.retryCall();
expect(jasmine.Ajax.requests.count()).toEqual(2);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200
});
Ext.asap(function() {
expect(successHandler.calls.count()).toEqual(1);
expect(failHandler.calls.count()).toEqual(0);
expect(alwaysHandler.calls.count()).toEqual(1);
done();
})
})
})
}
// And here's our attempt at handling the error. All we'll do here is make a new Ajax call and do our
// best to cancel the old one.
var ajaxErrorHandler = {
listener: function(connection, response, options) {
this.called = true;
// Start by doing nothing, and seeing the red bar
var originalRequest = response.request;
switch(response.status) {
case 401:
this.handleTheError(originalRequest, response, options);
return;
default:
// do nothing by default
return
}
},
handleTheError: function(request, response, options) {
console.log("Handling 401 error");
// capture the details.
this.originalOptions = Ext.clone(options);
this.originalDeferred = request.deferred;
// stop the original error.
options.failure = null;
// stop the callback, if any
options.callback = null;
request.deferred = null;
},
retryCall: function() {
var request = Ext.Ajax.request(this.originalOptions);
request.deferred = this.originalDeferred;
}
}
runAjaxTests("Conventional Ajax Approach", function() {
Ext.Ajax.request({
url: 'http://example.org/',
disableCaching: false,
success: successHandler,
failure: failHandler,
callback: alwaysHandler
})
});
runAjaxTests("Promise-style Approach 1", function() {
Ext.Ajax.request({
url: 'http://example.org/',
disableCaching: false,
})
.then(successHandler, failHandler)
.always(alwaysHandler)
})
runAjaxTests("Promise-style Approach 2", function() {
Ext.Ajax.request({
url: 'http://example.org/',
disableCaching: false,
})
.then(successHandler)
.otherwise(failHandler)
.always(alwaysHandler)
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment