Contents

After the integration for ExtJS, Jasmine and Maven is done, we should consider how the unit test should be done for some web application built by ExtJS.

My previous ExtJS projects experience are all for internal company usage in Retail or Logistics business, the UI is composed of plenty components and full of user interaction.  Hence, business logic are often intervened with UI behavior together.  This is also one of the reason previously we think it’s difficult to go for JS Unit Test.  (Maybe just we are too inexperienced on that.  Please share your experience to us if you have any.)

Assuming I need to introduce JS Unit Test to a system without any Unit Test covered, what should the general JS Unit Test principles to be firstly considered?  My opinions are:

  1. To test external contract against each ExtJS Component or JS function.  The external contract is where changes often take place.
  1. To test business logic (data calculation/validation, etc.) because this is where the real value in the business.
  1. Not to test the UI behavior (Window popup, Panel/Tree collapse/expand, Drap/Drop, Animation, etc.).  It’s quite difficult to mimic and verify the UI behavior because you have to twist your mind somehow to “tranform” the UI behavior to manual control the “movement” and then verify it.  It’s just writing even more UI logic to control other UI logic.
  1. Not to test all Ajax requests because it’s slow and actually should be considered as Integration Test.  It’s better to mock the interface data to test the Ajax caller & response handler.

Let’s see some real Unit Test example.  (Here some assumptions are made on how the components are generated and used in System: UI are completely built by ExtJS Designer.  It may not be the best practice, but it’s the way I think the real practice can be applied.)

Ext.data.Store

You might first wonder why Unit Test need to be done for Store component?  I got to tell you that I have met many bugs that are introduced because of fields’ definition changed.  This is the major contract bound the Store with the caller.

Below is a typical xxx.Datastore.js file generated by Ext Designer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Ext.ns('xxx');
xxx.DataStore = Ext.extend(Ext.data.JsonStore, {
constructor: function(cfg) {
cfg = cfg || {};
xxx.DataStore.superclass.constructor.call(this, Ext.apply({
storeId: 'xxx.DataStore',
url: 'http://www.foo.com/stub',
root: 'data.rows',
totalProperty: 'data.totalCount',
autoLoad: true,
fields: [
{
name: 'code'
},
{
name: 'name'
}
]
}, cfg));
}
});
new xxx.DataStore();

How should we test it?  This is an autoLoad Store.  As a JS source file to be linked in for testing, I cannot use Jasmine spyOn to stub it.  That is because JS source file is loaded before Jasmine spyOn in Spec can ever be run.  The only thing I can think of is to override the Ext Ajax lib to not doing actual request call.

Code in file globalTestStub.js to override the Ajax lib:

1
2
3
Ext.lib.Ajax.request = function() {
return {success: true};
};

Configuration in POM.xml

1
2
3
4
5
6
7
8
9
10
11
12
<configuration>
<preloadSources>
<source>adapter/ext/ext-base-debug.js</source>
<source>ext/ext-all-debug-w-comments.js</source>
<source>${project.basedir}/Resources/test/js/globalTestStub.js</source>
</preloadSources>
<jsSrcDir>${project.basedir}/Resources/js</jsSrcDir>
<jsTestSrcDir>${project.basedir}/Resources/test/js</jsTestSrcDir>
<sourceIncludes>
<include>xxx.DataStore.js</include>
...
</configuration>

ExtJS source and the globalTestStub.js are included in preloadSources so that all Stub/Mock code required for Unit Test can be initialized correctly before other JS sources and Test Spec files without polluting real production code.

How to write a Test Spec then?  Actually, there is no fixed way, but just a simple rule: to test the contract.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
describe('xxx.Datastore', function() {
it('should be able to initialized', function() {
var oStore = Ext.StoreMgr.lookup('xxx.DataStore');
expect(oStore).toBeTruthy();
});

it('should load data correctly', function() {
var oStore = Ext.StoreMgr.lookup('xxx.DataStore');
oStore.loadData({
data: {
rows: [
{
code: 'C1',
name: 'N1'
},
{
code: 'C2',
name: 'N2'
}
],
totalCount: 2
}
});

expect(oStore.getTotalCount()).toEqual(2);
var oRecord = oStore.getAt(0);
expect(oRecord.get('code')).toEqual('C1');
expect(oRecord.get('name')).toEqual('N1');
});
});

Unit Test for non-autoload Store would be similar but easier.

Beside how the Test is written, I would like to draw your attention to how I wrote the description for the Suite and the Spec.  I am not sure whether I understood the Behavior Driven Development comprehensively because I am still learning it.  However, I think this simple mind change helps me to think about how the behavior should be more than just simply how to write Test to meet coverage.  It can even helps us to review our design whether particular code belongs to the right place.

Let’s explore how Unit Test can be achieved more for ExtJS later.

Contents