How to Use Ext Ajax in Promise Style and Test It

After translated a blog about how Promise works in a more functional programming way, I tried to build something to make Ext Ajax call to work in Promise style as a practice.javascript

ExtPromise is a simple wrapper to Ext.Ajax and Ext.data.Connection to help you do an Ajax call in Promise style instead of passing success/failure callback to it. The Promise library I used is the bluebird. I chose it not only because its speed is faster than most of the Promise library, but also its error handling philosophy looks cleaner and more attractive.java

It didn't took long to implement the ExtPromise wrapper but it took me some time to test it.node

Originally, I thought I could use the jasmine-ajax I enhanced and shared before about how to test Ajax call in ExtJs. However, it doesn't work as expected. Testing Async method in Jasmine seems very awkward because the API in version 1.4 and 2.0 are dramaticlly different. Even worst, many strange issues messed around all the way.git

I finally gave up and search other alternative approaches. Sinon.js and Mocha come to rescure. It is pretty easy to test the Ajax call using the useFakeXMLHttpRequest provided by Sinon and the Async testing in Mocha looks more intuitive (Jasmine 2.0 use the same way). Let's see how the testing (BDD style) is setup.github

describe("Ajax should be now working in promise style", function() {
    var xhr, ajax;

    before(function() {
        xhr = sinon.useFakeXMLHttpRequest();
        xhr.onCreate = function(xhr) {
            ajax = xhr;
        }
    })

    after(function() {
        xhr.restore();
    });

    describe('ExtPromise.Ajax', function() {
        it("#success case", function(done) {
            ExtPromise.Ajax().request({url: 'foo'})
            .then(function(result) {
                expect(result.responseText).to.equal('Bar');
                done();
            })
            .catch(done);

            ajax.respond(200, { 'Content-Type': 'application/json' }, 'Bar');
        });
    });
});

It's quite straightforward. Before test spec runs, it's required to stub the XMLHttpRequest using Sinon's useFakeXMLHttpRequest API and obtain a reference in the onCreate method so that later it can be used to stub a response.ajax

Passing a done parameter in the test spec function tells Mocha that this spec is for Async testing and callinig done() will end it. One thing to notice here is this part.json

.catch(done);

If you don't do this, and the assertion in the test spec failed, the error it shows will be a timeout error instead of telling the true assertion error.promise

When testing failure case, the style written like below doesn't look good and error-prone because done() is called twice although you might think the success resolver doesnot require as it should not be called.app

ExtPromise.Ajax().request({url: 'foo', scope: scopeObj})
        .then(scopeObj.getName)
        .then(function(result) {
            expect(result).to.equal('Bar In scope');
            done();
        }, function(result) {
            expect(result.status).to.equal(500);
            done();
        })
        .catch(done);

    ajax.respond(500, { 'Content-Type': 'application/json' }, 'Error');

You may rewrite the call to done in a then call.ide

ExtPromise.Ajax().request({url: 'foo', scope: scopeObj})
        .then(scopeObj.getName)
        .then(function(result) {
            expect(result).to.equal('Bar In scope');
        }, function(result) {
            expect(result.status).to.equal(500);
        })
        .then(done)
        .catch(done);

    ajax.respond(500, { 'Content-Type': 'application/json' }, 'Error');
相關文章
相關標籤/搜索