Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Chutzpah, AngularJS, Jasmine and RequireJS

DZone's Guide to

Chutzpah, AngularJS, Jasmine and RequireJS

· Web Dev Zone
Free Resource

Learn how to build modern digital experience apps with Crafter CMS. Download this eBook now. Brought to you in partnership with Crafter Software

I'm not sure how many of you are using Chutzpah as a JavaScript test runner, personally I consider it to be a great tool. OK, I will be honest ... the name really poses some difficulties for me but c'est la vie. Chutzpah currently supports the QUnit and Jasmine testing frameworks and uses PhantomJS headless browser to run the tests. It can be run from the command line or from Visual Studio (there is a plug-in available for download). It can also be run in the TeamCity continuous integration server. So, as you can see, Chutzpah provides many options.

In one of my projects, I had to run unit tests using Jasmine for a JavaScript business framework  that is based on AngularJS, RequireJS and TypeScript. I can tell you up front that TypeScript (I do love TypeScript) is not relevant for this scenario. The issue that I bumped into is that Chutzpah does not recognize test suites if placed inside the "require" method.

A short explanation about what the "require" method from RequireJS does: It loads the defined dependencies and it makes sure that those dependencies are loaded before it executes the callback function. As you probably figured out already this is an asynchronous process.

Thanks to Jasmine, we can use a workaround in order to overcome our issues. Jasmine provides support for asynchronous operations. We are going to make use of runs and waitsFor functions, which, according to Jasmine's docs, have the following behavior: Specs are written by defining a set of blocks with calls to runs, which usually finish with an asynchronous call. The waitsFor block takes a latch function, a failure message and a timeout. The latch function polls until it returns true or the timeout expires, whichever comes first. If the timeout expires, the spec fails with the error message. Once the asynchronous conditions have been met, another runs block defines the final test behavior. This is usually an expectation based on the state after the asynchronous call returns.

In my approach, I haven't used a "runs" block because there was no need for it. What I basically did is the following: I declared a status flag (this is my "ready" variable) in the global scope and declared the variable that is going to be tested in the global scope (this is myObject variable). Then, on the require callback function that is going to be executed once all the defined dependencies are satisfied, I set the flag value to true and created a new object instance for the myObject variable.

Now we can define our test suite (note that it will not be placed inside the callback since Chutzpah will not run the test). As mentioned previously, we are going to rely on the waitsFor and runs functions. This is all that is needed in order to make Chutzpah happy and run the test:

var ready = false;
var myObject = null;

require.config({
    baseUrl: './../../../scripts',
    paths: {
        jasmine: 'tests/lib/jasmine',
        jquery: 'lib/jquery-1.9.1',
        angular: 'lib/angular'
    },
    shim: {
        angular: {
            deps: ['jquery'], exports: 'angular'
        },
        priority: ['angular']
    }
});
require(['angular'], (angular) => {
    ready = true;
    myObject = new Object();
});
 
describe("Constructor", function () {
    it("should create a new instance:", function () {
        if (!ready) {
            waitsFor(function () {
                return  ready;
            }, "Environment is not ready", 40);
        }
 
        runs(function () {
            expect(myObject).toNotBe(null);
        });
    });
});

Crafter is a modern CMS platform for building modern websites and content-rich digital experiences. Download this eBook now. Brought to you in partnership with Crafter Software.

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}