article.html
8.81 KB
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<html>
<head>
<title>Jasmine - Unit Testing</title>
<link href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css" rel="stylesheet" type="text/css" />
<link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" rel="stylesheet" type="text/css" />
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js" type="text/javascript"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js" type="text/javascript"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js" type="text/javascript"></script>
<style type="text/css">
.new-page {page-break-before: always;}
</style>
</head>
<body>
<h2>I. Introduction:</h2>
<p>In this tutorial we will take an existing Ext application and introduce the Jasmine assertion library for unit
testing. Readers must be familiar with JavaScript, ExtJS 4, the MVC architecture as well as the fundamentals of
HTML, CSS, and using resources.</p>
<p><b>Why Test?</b>
There are many reasons to test applications. Tests can verify an application's functionality to eliminate the
need to enumerate all the use cases manually. Also, if the application were to be refactored, or updated,
the tests could verify that the changes did not introduce new bugs into the system</p>
<h2>II. Getting started.</h2>
<p>For this tutorial, use the "simple" example of the MVC in the ExtJS bundle — found under
<ext>/examples/app/simple. Copy the simple folder to your workspace or desktop.</p>
<p>Add these folders:</p>
<pre class="brush: bash shell; toolbar: false; gutter: false">
<simple dir>/app-test
<simple dir>/app-test/specs</pre>
<p>Download and extract the Jasmine standalone library into the app-test folder.
<a href="http://pivotal.github.com/jasmine/download.html">Link</a></p>
<p>Create these files (leave them empty for now, you will fill them in next)</p>
<pre class="brush: bash shell; toolbar: false; gutter: false">
<simple dir>/app-test.js
<simple dir>/run-tests.html</pre>
<p>Your project should look like this now:</p>
<img src="folder.jpg"/>
<p class="new-page">Now that you have the files and folders setup, fill in the test-running environment. Open the run-tests.html
and put the following markup into it:</p>
<pre class="brush: xml; toolbar: false; gutter: false;">
<html>
<head>
<title id="page-title">Tester</title>
<link rel="stylesheet" type="text/css" href="app-test/lib/jasmine-1.1.0/jasmine.css">
<script type="text/javascript" src="extjs/ext-debug.js"></script>
<script type="text/javascript" src="app-test/lib/jasmine-1.1.0/jasmine.js"></script>
<script type="text/javascript" src="app-test/lib/jasmine-1.1.0/jasmine-html.js"></script>
<!-- include specs here -->
<!-- test launcher -->
<script type="text/javascript" src="app-test.js"></script>
</head>
<body>
</body>
</html></pre>
<p>There are a few key things to remember here: the jasmine resources, the ext framework resource and app-test.js.
These will need to be included with your tests (this order is important). You will include the specs
(jasmine assertion js files) above the app-test.js and below the rest of the files.</p>
<p>Next, open app-test.js and copy this code into it:</p>
<pre class="brush: js; toolbar: false; gutter: false;">
Ext.require('Ext.app.Application');
var APPLICATION = null;
Ext.onReady(function() {
APPLICATION = Ext.create('Ext.app.Application', {
name: 'AM',
controllers: [
'Users'
],
launch: function() {
//include the tests in the test.html head
jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
jasmine.getEnv().execute();
}
});
});</pre>
<p>The effect of the above code is a global reference to the <i>Application</i> instance and bootstrap for the
jasmine assertion library. This is accomplished by directly constructing the <i>Application</i> object and
storing the reference when the document is ready, bypassing the Ext.application() method.</p>
<p><b>Note:</b> this <i>Application</i> definition is not a copy and paste of your regular <i>Application</i>
definition in your app.js. This version will only include the controllers, stores, models, etc and when
<i>launch</i> is called it will invoke the Jasmine tests.</p>
<p>Now should you have a working test environment.</p>
<h2>III. Writing Tests.</h2>
<p>Under the specs folder (<simple>/app-test/specs) create two empty text files named:</p>
<pre class="brush: bash shell; toolbar: false; gutter: false;">
example.spec.js
users.spec.js</pre>
<p>Then go back to the <i>run-tests.html</i> file and add these two lines under the comment <i>"<!-- include
specs here -->"</i></p>
<pre class="brush: xml; first-line: 12; toolbar: false; gutter: false"><!-- include specs here -->
<script type="text/javascript" src="app-test/specs/example.spec.js"></script>
<script type="text/javascript" src="app-test/specs/users.spec.js"></script></pre>
<p><b>Note:</b> You may have noticed a pattern in the file names. Although, not required, its nice to indicate what
the file is for. (in this case the double extension of *.spec.js)</p>
<p>Start by filling in example.spec.js. Jasmine's specification syntax is very descriptive. Each suite of tests is
contained in a describe function, and each test is defined by an "it" function.</p>
<p>Example:</p>
<pre class="brush: js; toolbar: false; gutter: false">
describe("Basic Assumptions", function() {
it("has ExtJS4 loaded", function() {
expect(Ext).toBeDefined();
expect(Ext.getVersion()).toBeTruthy();
expect(Ext.getVersion().major).toEqual(4);
});
it("has loaded AM code",function(){
expect(AM).toBeDefined();
});
});</pre>
<p>To pass a test (each "it" block) simply call <i>expect(someValue).toBe<something>()</i></p>
<p class="new-page">Next a more complicated example. Testing a store, which is asynchronous, and retrieved from a Controller. (This
is where that global application reference will come in handy)</p>
<pre class="brush: js; toolbar: false; gutter: false">
describe("Users", function() {
var store = null, ctlr = null;
beforeEach(function(){
if(!ctlr) ctlr = APPLICATION.getController('Users');
if(!store) store = ctlr.getStore('Users');
expect(store).toBeTruthy();
waitsFor(
function(){ return !store.isLoading(); },
"load never completed",
4000
);
});
it("should have users",function(){
expect(store.getCount()).toBeGreaterThan(1);
});
it("should add and be able to get", function(){
store.add(Ext.create('AM.model.User', {
name: "John Doe",
email: "john.doe@anon.net"
}));
var user = store.findRecord('name', 'John Doe');
expect(user).toBeTruthy();
expect(user.get('email')).toBe('john.doe@anon.net');
});
it("should open the editor window", function(){
var grid = Ext.ComponentQuery.query('userlist')[0];
ctlr.editUser(grid,store.getAt(0));
var edit = Ext.ComponentQuery.query('useredit')[0];
expect(edit).toBeTruthy();
if(edit)edit.destroy();
});
});</pre>
<p class="new-page">Notice the "beforeEach" function (this will be called before each "it"). This function sets
up the stage for each test, and this example:
<ol>
<li>gets a <i>Store</i> from a <i>Controller</i></li>
<li>asserts that the store was successfully retrieved (not null or undefined)</li>
<li>waits for the store to complete loading — see the "waitFor" function — This store
auto loads data when its constructed: do not run tests before its ready.</li>
</ol>
</p>
<h2>IV. Automatting.</h2>
<p>Combining this with PhantomJS allows us to run these tests from the command line or from a cron job. The provided
<i>run-jasmine.js</i> in the PhantomJS distribution is all that is needed. (you can tweak it to make the output suit
your needs, <a href="run-jasmine.js">here</a> is an example tweaked version )</p>
<p>Example command line:</p>
<pre class="brush: bash shell; toolbar: false; gutter: false">phantomjs run-jasmine.js http://localhost/app/run-tests.html</pre>
<p>You will need to run the tests from a web server because XHR's cannot be made from the file:// protocol</p>
<p><b>About the Author:</b>
<a href="http://jonathangrimes.com">Jonathan Grimes</a> (<a href="http://www.facebook.com/jonathan.grimes">FB</a>,<a href="http://twitter.com/jsg2021">Tw</a>,<a href="https://plus.google.com/u/0/102578638400305127370/about">G+</a>) is a software engineer at <a href="http://nextthought.com">NextThought</a>, a technology start-up company that is currently building an integrated platform for online education. </p>
<script type="text/javascript"> SyntaxHighlighter.all() </script>
</body>
</html>