This repository has been archived by the owner on Mar 15, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
documentation.html
463 lines (359 loc) · 12.4 KB
/
documentation.html
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
---
layout: home
---
<!-- Documentation -->
<h1>Documentation</h1>
<p>
Hopefully these docs help you out, but if they don't then please <a href="https://github.com/foobarfighter/foounit/issues/new">file a bug</a>. Documentation bugs will be treated with high priority.
</p>
<ul class="index">
<li><a href="#syntax-overview">Syntax overview</a></li>
<li><a href="#async-awesomeness">Async awesomeness</a></li>
<li><a href="#matchers">Matchers</a></li>
<li><a href="#suites">Suites</a></li>
<li><a href="#loader">Loading files</a></li>
</ul>
<br>
<!-- Syntax Overview -->
<a name="syntax-overview"></a>
<h1>Syntax Overview</h1>
<h3>The Basics</h3>
The main keywords in foounit are:
<pre class="code">
describe, it, before, after, expect, mock
</pre>
There's another class of foounit keywords for asynchronous testing, but these are explained in the <a href="#async-awesomeness">async awesomeness</a> section.
<pre class="code">
waitFor, run, waitForTimeout
</pre>
<a name="it"></a>
<a name="example"></a>
<h3>it (aka example)</h3>
<p>
In BDD-speak an <em>it</em> block is an example that defines usage of a feature. So let's say we want to test that a string is less than 10 characters. You might create an <em>it</em> block that looks like this:
<pre class="code">
it('returns true', function (){
var str = "sml_string";
// expect is assertion... don't worry about this for now, but this test will pass
expect(str.length < 10).to(beTrue);
});
</pre>
</p>
<p>
You might think that an <em>it</em> block is overkill for a test like this, but this is a contrived example. The nice thing about using an <em>it</em> block is that you can provide documentation for the next developer working on the code.
</p>
<p>
If you want to experiment, you can try this example. Create a file called <em>test.js</em> with this code:
<pre class="code">
var foounit = require('foounit').globalize();
it('fails the test', function (){
expect(true).to(beFalse);
});
foounit.run();
</pre>
Then run the file with this command:
<pre class="code">$ node test.js</pre>
</p>
<p>
This test will fail, but it will give you an idea of what happens when you run an example.
</p>
<a name="describe"></a>
<h3>describe (aka group)</h3>
<p>
Internally, <em>describe</em> creates a group of <em><a href="#example">examples</a></em>. <em>describe</em>s describe a group of related behavior.
</p>
<p>
Let's say you have a signup form widget that lets you submit a form when you have a password that is 8 or more characters, but it shows an error message if you have password that is less than 8 characters. You'll have a test that looks like this:
<pre class="code">
describe('when the password is 8 or more characters', function (){
it('allows you to submit the form', function (){
...
});
});
describe('when the password is less than 8 characters', function (){
it('displays an error message', function (){
...
});
});
</pre>
</p>
<p>
You can nest <em>describe</em>s if your code has nested behaviors (or nested <em>if</em> statements). Nested describes look something like this:
<pre class="code">
describe('when foo is not falsy', function (){
describe('when foo is an integer', function (){
it('returns true', function (){
...
});
});
describe('when foo is a boolean', function (){
it('returns false', function (){
...
});
});
});
describe('when foo is falsy', function (){
it('returns false', function (){
...
});
});
</pre>
</p>
<a name="expect"></a>
<a name="assertion"></a>
<h3>expect (aka assertion)</h3>
<p>
The <em>expect </em> <a href="#keywords">keyword</a> creates an assertion. An assertion tests that a value is the value you expect it to be. Here is a breakdown of how <em>expect</em> works:
<pre class="code">
expect(
foo // actual value
).to(
be // this is a === matcher... more on this later
, 100 // expected value
);
</pre>
</p>
<p>
Here are some additional example expectations:
<pre class="code">
expect(1).to(beLt, 2); // passes
expect(true).to(beFalse); // fails
expect([1,2,3]).to(include, 2); // passes
</pre>
</p>
<p>
Here are some examples of expectations that assert actual and expected do <em>not</em> match:
<pre class="code">
expect(1).toNot(be, 2); // passes
expect(function (){
throw new Error('errar!');
}).toNot(throwError); // fails
</pre>
</p>
<a name="before"></a>
<h3>before (aka setup)</h3>
<p>
A <em>before</em> block is a function that sets up a test. A <em>before</em> block is run once for each group, and it can exist within nested groups. <em>before</em> blocks are great for asserting that a test is setup properly before an <em>example</em> runs, and they remove clutter from your tests. Nested groups will run <em>before</em> blocks in the order in which the groups are nested.
<pre class="code">
describe('when foo is 1', function (){
var foo;
before(function (){ // runs first
foo = 1;
});
it('does something', function (){
...
});
describe(when foo is 2', function (){
before(function (){ // runs second
foo++;
expect(foo).to(be, 2);
});
it('does another thing', function (){
...
});
});
});
</pre>
<a name="after"></a>
<h3>after (aka teardown)</h3>
<p>
<em>after</em> runs after each test. It should be used for cleaning up the previous test and it runs regardless of whether the example passes or fails.
</p>
<p>
Here is how to use <em>before</em> and <em>after</em> in conjunction to cleanup global variables:
<pre class="code">
describe('when the current user is bob', function (){
var origUser;
before(function (){
origUser = global.currentUser; // save off currentUser
global.currentUser = 'bob';
});
after(function (){
global.currentUser = origUser; // reset currentUser after the test runs
});
it('does something', function (){
...
});
});
</pre>
</p>
<p>
These <em>keywords</em> are 90% of what you need to write tests in BDD-style using foounit. There is a lot more to foounit than just these keywords but you can get by without learning about additional matchers and asynchronous testing if you are just experimenting.
</p>
<!-- /Syntax Overview -->
<br><br>
<!-- Async Awesomeness -->
<a name="async-awesomeness"></a>
<h1>Async Awesomeness</h1>
foounit is a fully asynchronous test runner. When a foounit <em>example</em> is created, it runs an asynchronous execution queue so all tests are asynchronous by default. Each asynchronous <em>keyword</em> adds an item to the queue and does not run until the previous task has completed.
<h3>waitFor</h3>
There are many cases in which you may want to wait for an asynchronous event to finish before passing or failing a test. The <em>waitFor</em> keyword will poll until a expectation has been met or a timeout occurs. Here is an example:
<pre class="code">
var successCallback;
before(function (){
successCallback = mock(function (data){});
$.ajax('http://localhost:5057/data.json', { success: successCallback });
});
it('gets the data', function (){
waitFor(function (){
expect(successCallback).to(haveBeenCalled);
});
});
</pre>
<p>
In this example, an xhr request is made to get the JSON data at <em>http://localhost:5057/data.json</em>. We have mocked the success callback and we wait for the response to succeed and call our callback. If the request succeeds then the test will pass, but if the request is unsuccessful then the test will fail. The <em>waitFor</em> keyword waits for the function it is passed to run without failing. If the <em>waitFor</em> block fails, then it is retried until a timeout is reached. If the timeout is reached then the test fails and a kitten dies.
</p>
<h3>run</h3>
<p>
There's more to asynchronous testing than just <em>waitFor</em> but <em>waitFor</em> will generally get you pretty far. Another common use-case is to wait for an expectation to be met, then do something else and wait for another expectation. In this case you can use <em>run</em> to insert a block into foounit's asynchronous execution queue. Here is an example:
<pre class="code">
it('does a lot of async stuff', function (){
var foo = '';
setTimeout(function (){ foo = 'bar'; }, 200);
// Waits for foo to become 'bar'
waitFor(function (){ expect(foo).to(be, 'bar'); });
// Runs after the waitFor above
run(function (){
setTimeout(function (){ foo = 'baz'; }, 200);
});
// Waits for foo to become 'baz'
waitFor(function (){ expect(foo).to(be, 'baz'); });
});
</pre>
<h3>waitForTimeout</h3>
<p>
foounit can assert that something never happens with the use of waitForTimeout. These kinds of tests are generally frowned upon because they slow down a test suite, but sometimes they are valuable enough to offset the downside of slowing down the test suite.
<p>
<p>
<em>waitForTimeout</em> will run a function until a timeout is reached. The first time the function passes without error, <em>waitForTimeout</em> fails. Consider this example:
</p>
<pre class="code">
it('doesnt get to 1000 fast enough', function (){
var foo = 0
, inc = function (){ foo++; setTimeout(inc, 200); }
setTimeout(inc, 200);
waitForTimeout(function (){
expect(foo).to(beGt, 999);
});
});
</pre>
<p>
This example will fail because foo will not reach 1000 in the time that it takes for <em>waitForTimeout</em> to timeout.
</p>
<!-- /Async Awesomness -->
<br><br>
<!-- Matchers -->
<a name="matchers"></a>
<h1>Matchers</h1>
<h3>be</h3>
<p>
Asserts that actual === expected.
<pre class="code">
expect(1).to(be, 1); // passes
expect(undefined).to(be, null); // fails
</pre>
</p>
<h3>beGt</h3>
<p>
Assert that actual is greater than expected.
<pre class="code">
expect(5).to(beGt, 4); // passes
expect(1).to(beGt, 2); // fails
</pre>
</p>
<h3>beFalse</h3>
<p>
Assert that actual is === false.
<pre class="code">
expect(false).to(beFalse); // passes
expect(null).to(beFalse); // fails
</pre>
</p>
<h3>beFalsy</h3>
<p>
Assert that actual is falsy.
<pre class="code">
expect(false).to(beFalsy); // passes
expect(null).to(beFalsy); // passes
expect("test").to(beFalsy); // fails
</pre>
</p>
<h3>beLt</h3>
<p>
Assert that actual is less than expected.
<pre class="code">
expect(1).to(beLt, 2); // passes
expect(5).to(beLt, 4); // fails
</pre>
</p>
<h3>beNull</h3>
<p>
Asserts that actual === null.
<pre class="code">
expect(null).to(beNull); // passes
expect(undefined).to(beNull); // fails
</pre>
</p>
<h3>beTruthy</h3>
<p>
Asserts that actual is truthy.
<pre class="code">
expect(1).to(beTruthy); // passes
expect('').to(beTruthy); // fails
expect(true).to(beTruthy); // passes
</pre>
</p>
<h3>beUndefined</h3>
<p>
Asserts that actual === undefined.
<pre class="code">
expect(null).to(beUndefined); // fails
expect(undefined).to(beUndefined); // passes
</pre>
</p>
<h3>equal</h3>
<p>
Assert that actual is deeply equal to expected. This is useful for saying that one object is the same as another but they are referencing different objects.
<pre class="code">
expect({ foo: ['bar'] }).to(equal, { foo: ['bar'] }); // passes
expect({ baz: 1 }).to(equal, { baz: 2 }); // fails
</pre>
</p>
<h3>include</h3>
<p>
Assert that an array has an element that matches type and object equality of expected.
<pre class="code">
expect([1, 2, 3]).to(include, 2); // passes
expect([1, 2, 3]).to(include, 10); // fails
</pre>
</p>
<h3>match</h3>
<p>
Assert that actual matches a regex.
<pre class="code">
expect('foo bar baz').to(match, /bar/); // passes
expect('foo bar baz').to(match, /qux/); // fails
</pre>
</p>
<a name="throwError"></a>
<h3>throwError</h3>
<p>
Asserts that the a function throws an error. The error message can be matched with a regex to assert that the correct error message was thrown.
<pre class="code">
expect(function (){ throw new Error(); }).to(throwError); // passes
expect(function (){ throw new Error('HEY NOW'); }).to(throwError, /Fuuuuuu/); // fails
expect(function (){ /** I don't throw **/ }).to(throwError); // fails
</pre>
</p>
<!-- /Matchers -->
<!-- Suites -->
<a name="suites"></a>
<h1>Suites</h1>
<p>TODOC</p>
<!-- /Suites -->
<!-- Loading files -->
<a name="loader"></a>
<h1>Loading files</h1>
<p>TODOC</p>
<!-- /Loading files -->
<!-- /Documentation -->