Tuesday, June 18, 2013

Dojo and Jasmine

D.O.H. sounding too much like D'oh, I'll then focus on the Jasmine BDD approach, which is both modern and fun to work with.

My folder strcuture:

  • web
    • css
    • img
    • js
      • com
        • acme
          • dashboard
            • Query.js
            • request.js
            • util.js
            • chart
              • fixed.js
            • ...more js modules...

    • less
    • test
      • com
        • acme
          • dashboard
            • Query.js
            • request.js
            • util.js
The Dojo modules I want to test are in the js folder. The index.html page is my production page. The specifications (i.e. test) are in the test folder. In the specs, I completely mirrored the js structure naming the specs identically as the module they're supposed to validate (personal choice).

The SpecRunner.html is the page used to bootstrap the Jasmine Tests.

This is the source:
<head>
    <title>Jasmine Spec Runner</title>

    <link href="lib/jasmine-1.3.1/jasmine.css" rel="stylesheet" type="text/css"></link>
    <script src="lib/jasmine-1.3.1/jasmine.js" type="text/javascript"></script>
    <script src="lib/jasmine-1.3.1/jasmine-html.js" type="text/javascript"></script>

</head>
    <script>
        var dojoConfig = {
            packages: [
                // Any references to a "dash" resource should load modules locally, *not* from CDN
                {
                    name: "dash",
                    location: "/js/com/acme/dashboard"
                },
                // Any references to a "spec" resource should load modules locally, *not* from CDN
                {
                    name: "spec",
                    location: "/test/com/acme/dashboard"
                }
            ],
            asynch: true
        };
    </script>
    <script src="//ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script>

    <script>
        require(["dojo/ready","spec/util","spec/Query","spec/request"],
                function (ready) {
                    ready(function () {
                        // Set up the HTML reporter - this is responsible for
                        // aggregating the results reported by Jasmine as the
                        // tests and suites are executed.
                        jasmine.getEnv().addReporter(
                                new jasmine.HtmlReporter()
                        );
                        // Run all the loaded test specs.
                        jasmine.getEnv().execute();
                    });
                });
    </script>
In this file I configure the dojo AMD loader to point locally to my modules (in js) and my specs (in test). Dojo itself is taken from a CDN. Any tests I want to run are declared in the require dependencies array. Dojo will call the dependent modules before executing the ready callback preparing all my tests for jasmine to execute.

This is the module under test (js/com/acme/dashboard/request.js) :

define([ "dojo/request", "dojo/json", "dash/constants", "dash/response","dojo/topic","dash/messages", "dash/util"], 
function (request, JSON, constants, response,topic,messages, util) {
    return function (esQuery, type, sync) {
        topic.publish(constants.event_request_in_progress);//in progress handler not working in IE9 and <
        return request.post(constants.es_endpoint, {
            //payload
            data: JSON.stringify(esQuery.getData()),
            handleAs: "json",
            sync:sync
        }).then(
            function (esResponse) {
                var _type = type || constants.query_type_fixed,res = response(esResponse);
                topic.publish(constants.event_response_completed,res,_type);
                return res;
            },
            function (err) {
                topic.publish(constants.event_request_in_error,err);
            },
            function (evt) {
                topic.publish(constants.event_request_in_progress,evt);
            }
        );
    };
});

...And the spec (test/com/acme/dashboard/request.js):

define(["dash/request","dash/Query","dash/constants","dojo/topic"],
    function (request,Query,constants,topic) {
        describe(
            "Testing request to Elastic Search",
            function () {
                var query,es_backup;
                beforeEach(function(){
                    query = new Query();
                    es_backup = constants.es_endpoint;
                    constants.es_endpoint = "http://test_es:9200/classes/student/_search";
                });
                afterEach(function(){
                    constants.es_endpoint = es_backup;
                });

                it("should execute request against Elastic Search on TEST w/o errors", function () {
                    var called;
                    function completed(response,type){
                        called = true;
                    }
                    topic.subscribe(constants.event_response_completed,completed);
                    runs(function(){
                            request(query,constants.query_type_fixed);
                        }
                    );
                    waitsFor(function() {
                        return called;
                    }, "Elastic Search should have been called within 2 seconds on TEST server", 2000);

                    runs(function() {
                        expect(called).toBe(true);
                    });
                });
        );
    });

This spec shows off the interesting Jasmine asynch support. Modules under test are injected into the spec along with any other dojo modules. Next step will be to automate all this. Stay tuned!

Ref http://www.bennadel.com/blog/2393-Writing-My-First-Unit-Tests-With-Jasmine-And-RequireJS.htm


No comments:

Post a Comment

Thank you for your comment