Qunit based Unit and Regression Test Automation of Sencha applications


Image

Problem Statement: 

Qunit is a powerful, easy-to-use JavaScript unit testing framework. It is capable of testing any generic JavaScript code. In this article we would show how we can write Qunit test cases for Sencha ExtJS based codebase, execute them using PhantomJS and look at the coverage report to judge the overall quality of the code.

Scope of the article:

This article provides steps for unit testing ExtJS project code using Qunit, running Qunit scripts in PhantomJs and integrating ExtJS project with JSCover.

Pre-requisites:

  1. You need to have an ExtJS sample project running in your machine. If you don’t have, visit this blog to know steps to set up or you can download sample project here.
  2. js and css files for QUnit
  3. PhantomJs
  4. JsCover

Step 1: Configure QUnit in your project:

1)  Create a Js file which contains the Quni testing code. (say, qunit-test.js) in project structure
2)  Add created test file for QUnit in main html file after qunit.js got loaded.

<script src="qunit-test.js"></script>

3)  Add the following div tags in body of the html file.

<div id="qunit"></div>

<div id="qunit-fixture">test markup</div>

<h1 id="qunit-header">QUnit Test Suite</h1>

<h2 id="qunit-banner"></h2>

<div id="qunit-testrunner-toolbar"></div>

<h2 id="qunit-userAgent"></h2>

<ol id="qunit-tests"></ol>

Sample Code for Html file:

<!DOCTYPE HTML>

<html>

<head>

<meta charset="UTF-8">

<title>extjsExample</title>

<link rel="stylesheet" href="resources/theme/app.css">

<link rel="stylesheet" href="resources/css/example.css">

<script src="../../../brilliantarabia/libraries/extjs4.2/ext-all.js"></script>

<script src="bootstrap.js"></script>

<script src="app/app-qunit.js"></script>

<link rel="stylesheet" href="../../qunit/qunit.css">

<script src="../../qunit/qunit.js"></script>

<script src="qunit-test.js"></script>

</head>

<body>

<div id="qunit"></div>

<div id="qunit-fixture">test markup</div>

<h1 id="qunit-header">QUnit Test Suite</h1>

<h2 id="qunit-banner"></h2>

<div id="qunit-testrunner-toolbar"></div>

<h2 id="qunit-userAgent"></h2>

<ol id="qunit-tests"></ol>

</body>

</html>

4)  Open qunit-test.js file and add method QUnit.begin:

QUnit.begin(function(started){

});

QUnit.begin gets called after loading of qunit.js file. So after the QUnit got loaded, in that, you need to add the test scripts.

Step 2: Getting application instance into qunit-test.js

To test ExtJS code that was written for you project, you need to get the app instance into testing file. For that, add below code:

var store = null, ctlr = null; myApp = null; 

myApp = extjsExample;

extJsExample is the app name that you give in the app.js for your project. It will be available only after app.js got loaded. So, make sure that, you have added test file after app.js.

Step 3: Unit testing for model

1)  After you got the control on your application, all you need to do is testing your code. Let’s test for sample Model. In order to test for model, add below code

test("MODEL : Model Server has loaded successfully with fields name ",function(){

  equal(myApp.getApplication().getModel('Server').getFields()[0].name,'name','model has same value');

});

In the above code,

  • myApp.getApplication() will give you the application instance and myApp.getApplication().getModel(‘modelName’) gives you the complete model .
  • test is the function that enables you to write a simple function in that with your own title for the test.
  • eqals checks for the condition that you wrote for comparing is equal or not. If false, test script will be failed and displayes in failed scripts.

Step 4: Unit testing for Store

if (!store) {
 store = myApp.getApplication().getStore('Server');

 store.load();

  }

 store.on('load',function(store,recs){

 test("Check for Store count is 0 or not",function(){

 ok((store.getCount()==0),"Count is :"+store.getCount());

 });

 },this);

In above code, we are getting store using myApp.getApplication().getStore(‘Server’) and loading store. And then handling in on load event and checking for count of store. Ok method checks for the value that you have entered in 1st parenthesis are returning true or not. If not, script fails and shows script as failed while executing output.

Step 5: Testing for View

test("View : Test to verify the view ",function(){ 

ok(myApp.getApplication().getView('Registration').xtype == 'mainview',"Main View is "+myApp.getApplication().getView('Registration').xtype);

 });

Here, we are checking for view’s xtype is mainview or not. If yes, script returns as success and if no, script fails.

Step 6: Unit testing for Controller

var controller = myApp.getApplication().getMainController();

 test("Check for Controller weather id is Main or not",function(){

 equal(ctlr.id,'Main',"Controller Id is "+ctlr.id);

 });

Overall, sample code for qunit-test.js:

QUnit.begin(function(started){

 var store = null, ctlr = null; myApp = null;

 myApp = extjsExample;

 ctlr = myApp.getApplication().getMainController();

 // Controller check

 test("Check for Controller weather id is Main or not",function(){

 equal(ctlr.id,'Main',"Controller Id is "+ctlr.id);

 });

 // Store check

 if (!store) {

 store = myApp.getApplication().getStore('Server');

 store.load();

 }

 store.on('load',function(store,recs){

 test("Check for Store count is 0 or not",function(){

 ok((store.getCount()==0),"Count is :"+store.getCount());

 });

 },this);

// Model 

 test("MODEL : Model Server has loaded successfully with fields name ",function(){

 equal(myApp.getApplication().getModel('Server').getFields()[0].name,'name','model has same value'); 

 });

 // View Test

 test("View : Test to verify the view ",function(){

 ok(myApp.getApplication().getView('Registration').xtype == 'mainview',"Main View is "+myApp.getApplication().getView('Registration').xtype);

 });

});

Now run the application in browser. After running, you should be able to see the below out put

Image

Step 7: Running QUnit scripts using PhantomJs in headless mode:

1)  Create a js file with named run-qunit.js and paste the below code: Below code acts as an intermediate to run QUnit scripts with phantomjs .

/**

 * Wait until the test condition is true or a timeout occurs. Useful for waiting

 * on a server response or for a ui change (fadeIn, etc.) to occur.

 *

 * @param testFx javascript condition that evaluates to a boolean,

 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or

 * as a callback function.

 * @param onReady what to do when testFx condition is fulfilled,

 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or

 * as a callback function.

 * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.

 */

function waitFor(testFx, onReady, timeOutMillis) {

 var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 30001, //< Default Max Timout is 3s

 start = new Date().getTime(),

 condition = false,

 interval = setInterval(function() {

 if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {

 // If not time-out yet and condition not yet fulfilled

 condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code

 } else {

 if(!condition) {

 // If condition still not fulfilled (timeout but condition is 'false')

 phantom.exit(1);

 } else {

 // Condition fulfilled (timeout and/or condition is 'true')

 console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");

 typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled

 clearInterval(interval); //< Stop this interval

 }

 }

 }, 100); //< repeat check every 250ms

};

if (phantom.args.length === 0 || phantom.args.length > 2) {

 console.log('Usage: run-qunit.js URL');

 phantom.exit(1);

}

var page = require('webpage').create();

// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")

page.onConsoleMessage = function(msg) {

 console.log(msg);

};

page.open(phantom.args[0], function(status){

 if (status !== "success") {

 console.log("Unable to access network");

 phantom.exit(1);

 } else {

 waitFor(function(){

 return page.evaluate(function(){

 var el = document.getElementById('qunit-testresult');

 if (el && el.innerText.match('completed')) {

 return true;

 }

 return false;

 });

 }, function(){

 var failedNum = page.evaluate(function(){

 var el = document.getElementById('qunit-testresult');

 console.log(el.innerText);

 try {

 return el.getElementsByClassName('failed')[0].innerHTML;

 } catch (e) { }

 return 10000;

 });

 phantom.exit((parseInt(failedNum, 10) > 0) ? 1 : 0);

 });

 }

});

2)  Open command prompt and navigate to the PhantomJs installed folder. And run following command.

phantomjs /path/to/run-qunit.js /path/to/main html file/app-qunit.html

After running above command, you should see following output.

Image

Step 8: Integrating code with JsCover

In order to integrate jscover with project code, you need to run below command to set up jsCover to your project

1)  Go to command line and go the JsCover folder and run below command.

java -jar target/dist/JSCover-all.jar -fs --branch --document-root=C:/xampp/htdocs/Qunit/test/myproject --report-dir=targetfolder jsCover_FolderName --no-instrument=omit_folder

In the above command, document-root describes project location and report-dire should be the target where you want to set up jsCover package. –no-instrument is folder if you don’t want to include into coverage.

jsCover_FolderName is folder that you want create in target path (for example, ExtJS sdk folder is not required as a part of coverage. So you can give sdk folder as no-instrument folder).

After you execute the above command, you should see the folder created in target specified.

Image

2)  Run the application in browser by pointing target project’s jscoverage.html. You should see the below ui

Image

3)  Run the main html file of your project in the URL section.

Image

4)  Go to summary tab and see the coverage.

Image

4)  Now, run QUnit file’s main html file in URl section

Image

5)  Switch to summary tab. It will show the coverage for qunit js files.

Image

Summary: This article has provided steps for unit testing ExtJS project code using Qunit, running qunit scripts in PhantomJs and integrating ExtJS project with JSCover.

References:

  1. http://qunitjs.com/intro/
  2. http://api.qunitjs.com/category/all/
  3. http://tntim96.github.com/JSCover/manual/manual.xml
  4. https://gist.github.com/gmarik/1305062
  5. http://siliconforks.com/jscoverage/manual.html
  6. https://github.com/ariya/phantomjs/wiki
Tagged with: , , , , ,
Posted in Sencha ExtJS
One comment on “Qunit based Unit and Regression Test Automation of Sencha applications
  1. sat says:

    Can we configure JSCover to exclude covering the external third party js so that code coverage on actual source files is shown?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

We Have Moved Our Blog!

We have moved our blog to our company site. Check out https://walkingtree.tech/index.php/blog for all latest blogs.

Sencha Select Partner Sencha Training Partner
Xamarin Authorized Partner
Do More. With Sencha.

Recent Publication
%d bloggers like this: