Setting up Jasmine with ExtJS for Unit Testing

I recently attempted to set up Jasmine to incorporate unit testing with my ExtJS projects. I started by following the tutorial provided by Sencha: http://docs.sencha.com/extjs/4.2.1/#!/guide/testing

 This guide seems to be outdated.It utilizes the old onReady() method as opposed to the new style of startup. For Sencha Architect users, the methodology in the article didn't seem to work. Lastly, the article references Jasmine 1.1.0, where the latest version (as of this writing) is 1.3.1.

So here's a quick tutorial on how to set it up.


Getting Started

It's probably a good idea to read through the Sencha tutorial referenced on the prior page as background material.

Create the directories and install Jasmine

Create the app-test and and app-test/specs directory as mentioned in the tutorial.

Download and extract Jasmine into the app-test directory. This will add a lib, spec and src directory to app-test along with a SpecRunner.html file. We can for the most part ignore these.

app-test Directory

Create your spec runner file

Create a run-tests.html file in the project directory (parent directory of app-test) and cut and paste the following code:

<html>
<head>
    <title id="page-title">Jasmine Example</title>
    <link rel="stylesheet" type="text/css" href="app-test/lib/jasmine-1.3.1/jasmine.css">
    <script type="text/javascript" src="extjs/ext-debug.js"></script>
    <script type="text/javascript" src="app-test/lib/jasmine-1.3.1/jasmine.js"></script>
    <script type="text/javascript" src="app-test/lib/jasmine-1.3.1/jasmine-html.js"></script>

    <!-- include specs here -->
    <script type="text/javascript" src="app-test/specs/initial.js"></script>
    <!-- test launcher -->
    <script type="text/javascript" src="app-test.js"></script>

</head>
<body>
</body>
</html>

 Note that you may have to change the path of your extjs distribution.

 


 Build the app-test.js file

Now cut and paste the code from your existing app.js file into a new file called app-test.js (in the project directory). If you use Architect like I do, it will look like this:

// File app-test.js
Ext.Loader.setConfig({
    enabled: true
});

Ext.application({
    models: [
        'Car'
    ],
    stores: [
        'Cars'
    ],
    views: [
        'InitialView'
    ],
    autoCreateViewport: true,
    controllers: [
        'Main'
    ],
    name: 'JasmineExample'
});

 To the application config, add a launch function with the contents below. If the launch function already exists in your code, just add the two Jasmine lines.

    launch: function() {
            jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
            jasmine.getEnv().execute();    
    }

When complete, the file will look like this:

// File app-test.js
Ext.require('Ext.app.Application');

Ext.Loader.setConfig({
    enabled: true
});

Ext.application({
       models: [
        'Car'
    ],
    stores: [
        'Cars'
    ],
    views: [
        'InitialView'
    ],
    autoCreateViewport: true,
    name: 'JasmineExample',

// ---------Inserted launch function -----------
    launch: function() {
            jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
            jasmine.getEnv().execute();    
    }
// --------------------------------------------
});


Create an empty spec file and test the Jasmine installation

Lastly, create the spec file (but leave it empty) referenced in run-tests.html (app-test/specs/initial.js) or modify the entry and create your own.

If all went well you should now be able to run the tests by calling projDir/run-tests.html in your favorite browser.

 Jasmine Success

 


Conclusion

That's all there is to getting Jasmine working with your ExtJS application. The bigger issue is figuring out tests that truly add value to your application.

I'm including the spec file below that I created for my JasmineExample project. This was the culmination of only 2 hours of Jasmine experience. As I work more with Jasmine, I'll share ideas on what seems to be beneficial.

// File initial.js
describe ("Initial", function(){ var app = null, controller = null, store = null, viewPort = null; beforeEach(function () { // Test to see if the app loaded if (!app){ app = JasmineExample.getApplication(); expect(app !== null).toBeTruthy(); } // Test the existence of the Main controller if (!controller){ controller = app.getController('Main'); expect(controller.id == "Main").toBeTruthy(); } // Get the initial view. For convenience query from it. if (!viewPort) { viewPort = Ext.ComponentQuery.query('viewport')[0]; expect(viewPort.xtype === 'viewport').toBeTruthy(); } // Verify the Cars store is attached to the Main controller. if (!store) { store = controller.getCarsStore(); expect(store.storeId == "Cars").toBeTruthy(); // Wait for it to load waitsFor( function() {return !store.isLoading(); }, "load never completed", 4000 ); } }); // before each it("Cars grid is found with the proper store and loaded", function(){ var grid = viewPort.query('grid')[0]; // Test that the grid panel was found expect(grid !== null).toBe(true); // Test that the store attached to the grid is the Cars store expect(grid.getStore().storeId == "Cars").toBeTruthy(); // Test the the number of initial records is 2 expect(grid.getStore().getCount() == 2).toBe(true); }); }); // describe Selector