jspec 2.11.13 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/History.md +714 -0
  2. data/Manifest +51 -36
  3. data/README.md +968 -0
  4. data/Rakefile +4 -53
  5. data/bin/jspec +93 -224
  6. data/jspec.gemspec +5 -5
  7. data/lib/images/sprites.png +0 -0
  8. data/lib/jspec.css +2 -2
  9. data/lib/jspec.growl.js +115 -0
  10. data/lib/jspec.jquery.js +1 -1
  11. data/lib/jspec.js +98 -101
  12. data/lib/jspec.shell.js +5 -2
  13. data/lib/jspec.timers.js +1 -1
  14. data/lib/jspec.xhr.js +12 -2
  15. data/spec/commands/example_command.rb +19 -0
  16. data/spec/dom.html +33 -0
  17. data/spec/node.js +32 -0
  18. data/spec/rhino.js +24 -0
  19. data/spec/ruby/bin/init_spec.rb +101 -0
  20. data/spec/ruby/bin/install_spec.rb +141 -0
  21. data/spec/ruby/bin/run_spec.rb +0 -0
  22. data/spec/ruby/bin/shell_spec.rb +13 -0
  23. data/spec/ruby/bin/spec_helper.rb +25 -0
  24. data/spec/ruby/bin/update_spec.rb +72 -0
  25. data/spec/server.html +29 -0
  26. data/spec/server.rb +1 -1
  27. data/spec/{env.js → support/env.js} +554 -664
  28. data/spec/support/jquery.js +4376 -0
  29. data/spec/{helpers.js → unit/helpers.js} +2 -0
  30. data/spec/{spec.fixtures.js → unit/spec.fixtures.js} +0 -1
  31. data/spec/{spec.grammar-less.js → unit/spec.grammar-less.js} +0 -0
  32. data/spec/{spec.grammar.js → unit/spec.grammar.js} +1 -11
  33. data/spec/{spec.jquery.js → unit/spec.jquery.js} +0 -17
  34. data/spec/{spec.jquery.xhr.js → unit/spec.jquery.xhr.js} +13 -2
  35. data/spec/unit/spec.js +187 -0
  36. data/spec/{spec.matchers.js → unit/spec.matchers.js} +141 -66
  37. data/spec/{spec.modules.js → unit/spec.modules.js} +0 -0
  38. data/spec/{spec.shared-behaviors.js → unit/spec.shared-behaviors.js} +0 -0
  39. data/spec/{spec.utils.js → unit/spec.utils.js} +123 -22
  40. data/spec/{spec.xhr.js → unit/spec.xhr.js} +11 -10
  41. data/{server → src}/browsers.rb +23 -0
  42. data/{server → src}/helpers.rb +2 -17
  43. data/src/installables.rb +229 -0
  44. data/src/project.rb +340 -0
  45. data/{server → src}/routes.rb +1 -1
  46. data/{server → src}/server.rb +0 -0
  47. data/support/js.jar +0 -0
  48. data/templates/default/History.md +5 -0
  49. data/templates/default/{README.rdoc → Readme.md} +3 -3
  50. data/templates/default/lib/{yourlib.core.js → yourlib.js} +0 -0
  51. data/templates/default/spec/commands/example_command.rb +19 -0
  52. data/templates/default/spec/{spec.dom.html → dom.html} +5 -3
  53. data/templates/default/spec/rhino.js +10 -0
  54. data/templates/default/spec/server.html +18 -0
  55. data/templates/default/spec/unit/spec.helper.js +0 -0
  56. data/templates/default/spec/{spec.core.js → unit/spec.js} +0 -0
  57. data/templates/rails/commands/example_commands.rb +19 -0
  58. data/templates/rails/{spec.dom.html → dom.html} +4 -2
  59. data/templates/rails/rhino.js +10 -0
  60. data/templates/rails/server.html +18 -0
  61. data/templates/rails/unit/spec.helper.js +0 -0
  62. data/templates/rails/{spec.application.js → unit/spec.js} +0 -0
  63. metadata +56 -41
  64. data/History.rdoc +0 -590
  65. data/README.rdoc +0 -842
  66. data/spec/async +0 -1
  67. data/spec/jquery.js +0 -19
  68. data/spec/spec.dom.html +0 -34
  69. data/spec/spec.js +0 -166
  70. data/spec/spec.node.js +0 -46
  71. data/spec/spec.rhino.js +0 -23
  72. data/spec/spec.server.html +0 -29
  73. data/templates/default/History.rdoc +0 -4
  74. data/templates/default/spec/spec.rhino.js +0 -8
  75. data/templates/default/spec/spec.server.html +0 -16
  76. data/templates/rails/spec.rhino.js +0 -8
  77. data/templates/rails/spec.server.html +0 -16
data/Manifest CHANGED
@@ -1,6 +1,6 @@
1
- History.rdoc
1
+ History.md
2
2
  Manifest
3
- README.rdoc
3
+ README.md
4
4
  Rakefile
5
5
  bin/jspec
6
6
  jspec.gemspec
@@ -11,48 +11,63 @@ lib/images/sprites.bg.png
11
11
  lib/images/sprites.png
12
12
  lib/images/vr.png
13
13
  lib/jspec.css
14
+ lib/jspec.growl.js
14
15
  lib/jspec.jquery.js
15
16
  lib/jspec.js
16
17
  lib/jspec.shell.js
17
18
  lib/jspec.timers.js
18
19
  lib/jspec.xhr.js
19
- server/browsers.rb
20
- server/helpers.rb
21
- server/routes.rb
22
- server/server.rb
23
- spec/async
24
- spec/env.js
20
+ spec/commands/example_command.rb
21
+ spec/dom.html
25
22
  spec/fixtures/test.html
26
23
  spec/fixtures/test.json
27
24
  spec/fixtures/test.xml
28
- spec/helpers.js
29
- spec/jquery.js
25
+ spec/node.js
26
+ spec/rhino.js
27
+ spec/ruby/bin/init_spec.rb
28
+ spec/ruby/bin/install_spec.rb
29
+ spec/ruby/bin/run_spec.rb
30
+ spec/ruby/bin/shell_spec.rb
31
+ spec/ruby/bin/spec_helper.rb
32
+ spec/ruby/bin/update_spec.rb
33
+ spec/server.html
30
34
  spec/server.rb
31
- spec/spec.dom.html
32
- spec/spec.fixtures.js
33
- spec/spec.grammar-less.js
34
- spec/spec.grammar.js
35
- spec/spec.jquery.js
36
- spec/spec.jquery.xhr.js
37
- spec/spec.js
38
- spec/spec.matchers.js
39
- spec/spec.modules.js
40
- spec/spec.node.js
41
- spec/spec.rhino.js
42
- spec/spec.server.html
43
- spec/spec.shared-behaviors.js
44
- spec/spec.utils.js
45
- spec/spec.xhr.js
46
- templates/default/History.rdoc
47
- templates/default/README.rdoc
48
- templates/default/lib/yourlib.core.js
35
+ spec/support/env.js
36
+ spec/support/jquery.js
37
+ spec/unit/helpers.js
38
+ spec/unit/spec.fixtures.js
39
+ spec/unit/spec.grammar-less.js
40
+ spec/unit/spec.grammar.js
41
+ spec/unit/spec.jquery.js
42
+ spec/unit/spec.jquery.xhr.js
43
+ spec/unit/spec.js
44
+ spec/unit/spec.matchers.js
45
+ spec/unit/spec.modules.js
46
+ spec/unit/spec.shared-behaviors.js
47
+ spec/unit/spec.utils.js
48
+ spec/unit/spec.xhr.js
49
+ src/browsers.rb
50
+ src/helpers.rb
51
+ src/installables.rb
52
+ src/project.rb
53
+ src/routes.rb
54
+ src/server.rb
55
+ support/js.jar
56
+ templates/default/History.md
57
+ templates/default/Readme.md
58
+ templates/default/lib/yourlib.js
59
+ templates/default/spec/commands/example_command.rb
60
+ templates/default/spec/dom.html
61
+ templates/default/spec/node.js
62
+ templates/default/spec/rhino.js
63
+ templates/default/spec/server.html
49
64
  templates/default/spec/server.rb
50
- templates/default/spec/spec.core.js
51
- templates/default/spec/spec.dom.html
52
- templates/default/spec/spec.rhino.js
53
- templates/default/spec/spec.server.html
65
+ templates/default/spec/unit/spec.helper.js
66
+ templates/default/spec/unit/spec.js
67
+ templates/rails/commands/example_commands.rb
68
+ templates/rails/dom.html
69
+ templates/rails/rhino.js
70
+ templates/rails/server.html
54
71
  templates/rails/server.rb
55
- templates/rails/spec.application.js
56
- templates/rails/spec.dom.html
57
- templates/rails/spec.rhino.js
58
- templates/rails/spec.server.html
72
+ templates/rails/unit/spec.helper.js
73
+ templates/rails/unit/spec.js
data/README.md ADDED
@@ -0,0 +1,968 @@
1
+
2
+ # JSpec
3
+
4
+ JSpec is a minimalistic JavaScript behavior driven development framework,
5
+ providing **simple installatio**n, extremely **low learning curve**, absolutely **no pollution**
6
+ to core prototypes, async request support, and incredibly sexy syntax, tons of matchers
7
+ and **much more**.
8
+
9
+ ## Features
10
+
11
+ * Highly readable
12
+ * Framework / DOM independent
13
+ * Modular via JSpec Module's and hooks
14
+ * Mock Ajax Requests
15
+ * Rhino support
16
+ * Node.js support
17
+ * Async support
18
+ * Growl (unobtrustive notifications) support
19
+ * Fixture support
20
+ * Ruby JavaScript testing server
21
+ * Nested describes
22
+ * Does not pollute core object prototypes
23
+ * Cascading before/after/before_each/after_each hooks
24
+ * Extremely simple and intuitive matcher declaration
25
+ * Over 45 core matchers
26
+ * Allows parens to be optional when using matchers to increase readability
27
+ * Several helpful reporters (DOM, Console, Terminal, ...)
28
+ * Assertion graphs displaying how many, and which assertions pass or failed
29
+ * Default / customizable evaluation contexts
30
+ * DOM sandbox support
31
+ * Great looking default DOM theme
32
+ * `jspec` command-line utility for auto-running specs, and initializing project templates
33
+ * Proxy or 'Spy' assertions
34
+ * Method Stubbing
35
+ * Shared behaviors
36
+ * Extend the jspec executable with project / user specific sub-commands.
37
+ * Profiling
38
+ * Interactive Shell
39
+ * Ruby on Rails Integration
40
+ * Install support projects with a single command (jQuery, Rhino, Prototype, Dojo, etc)
41
+ * Tiny (18 kb compressed, 1500-ish LOC)
42
+
43
+ ## Companies Using JSpec
44
+
45
+ To add or request removal from this list please email tj@vision-media.ca
46
+
47
+ * [Apple](http://apple.com)
48
+ * [Google - YouTube](http://youtube.com)
49
+ * [Palm](http://palm.com)
50
+ * [Carfax](http://carfax.com)
51
+ * [Vision Media](http://vision-media.ca)
52
+
53
+ ## Installation
54
+
55
+ Simply download JSpec and include _JSpec.css_ and _JSpec.js_ in your markup.
56
+ Head over to the downloads section on Github, clone this public repo, or
57
+ add JSpec as a git submodule with in your project. Alternatively JSpec is
58
+ also available as a Ruby Gem (though this is not required), which also
59
+ provides the `jspec` executable. First install [Gemcutter](http://gemcutter.org/) then execute:
60
+ $ sudo gem install jspec
61
+
62
+ At which point you may:
63
+
64
+ $ jspec init myproject
65
+
66
+ By default, the command above will use absolute path for all JSpec library files.
67
+ This behavior can be a problem when you're working across different computers or
68
+ operating systems. You can freeze the library or symlink it.
69
+
70
+ $ jspec init myproject --freeze
71
+ $ jspec init myproject --symlink
72
+
73
+ JSpec scripts should NOT be referenced via the `<script>` tag, they should be
74
+ loaded using the exec method (**unless you are using the grammar-less alternative**).
75
+ Below is an example:
76
+
77
+ ...
78
+ <script>
79
+ function runSuites() {
80
+ JSpec
81
+ .exec('spec.core.js')
82
+ .exec('spec.jquery.js')
83
+ .run({ failuresOnly : true })
84
+ .report()
85
+ }
86
+ </script>
87
+ <body onLoad="runSuites()">
88
+ ...
89
+
90
+ You may optionally want to use sources in the _/pkg_ directory
91
+ for your project, since it includes compressed alternatives generated
92
+ each release.
93
+
94
+ ## Example
95
+
96
+ describe 'ShoppingCart'
97
+ before_each
98
+ cart = new ShoppingCart
99
+ end
100
+
101
+ describe 'addProducts'
102
+ it 'should add several products'
103
+ cart.addProduct('cookie')
104
+ cart.addProduct('icecream')
105
+ cart.should.have 2, 'products'
106
+ end
107
+ end
108
+
109
+ describe 'checkout'
110
+ it 'should throw an error when checking out with no products'
111
+ -{ cart.clear().checkout() }.should.throw_error EmptyCart
112
+ end
113
+ end
114
+ end
115
+
116
+ ## Grammar-less Example
117
+
118
+ JSpec's grammar is optional, you may also use the equivalent grammar-less
119
+ alternative below using pure JavaScript (when using the JSpec grammar you
120
+ may also use grammar-less assertions):
121
+
122
+ JSpec.describe('ShoppingCart', function(){
123
+ before_each(function{
124
+ cart = new ShoppingCart
125
+ })
126
+
127
+ describe('addProducts', function(){
128
+ it ('should add several products', function(){
129
+ cart.addProducts('cookie')
130
+ cart.addProducts('icecream')
131
+ expect(cart).to(have, 2, 'products')
132
+ })
133
+ })
134
+
135
+ describe('checkout', function(){
136
+ it ('should throw an error when checking out with no products', function(){
137
+ expect(function(){ cart.clear().checkout() }).to(throw_error, EmptyCart)
138
+ })
139
+ })
140
+ })
141
+
142
+ ## Options
143
+
144
+ The following options may be passed to _JSpec.run()_.
145
+
146
+ - fixturePath
147
+ - {string} path to fixture directory (DOM, Terminal, Server)
148
+ - failuresOnly
149
+ - {bool} displays only failing specs, making them quick to discover and fix (DOM, Terminal, Server)
150
+ - reportToId
151
+ - {string} an element id to report to when using the DOM reporter (DOM)
152
+ - verbose
153
+ - {bool} verbose server output, defaults to false (Server)
154
+
155
+ ## Matchers
156
+
157
+ ### Core
158
+
159
+ - equal, be
160
+ - ===
161
+ - be_a, be_an
162
+ - have constructor of x
163
+ - be_an_instance_of
164
+ - instanceof x
165
+ - be_at_least
166
+ - &gt;=
167
+ - be_at_most
168
+ - &lt;=
169
+ - be_null
170
+ - == null
171
+ - be_empty
172
+ - length &lt; 0 or {}
173
+ - be_true
174
+ - == true
175
+ - be_false
176
+ - == false
177
+ - be_type
178
+ - be type of x
179
+ - be_greater_than
180
+ - &gt;
181
+ - be_less_than
182
+ - &lt;
183
+ - be_undefined
184
+ - check if variable passed is undefined
185
+ - throw_error
186
+ - should throw an error, optionally supply the error string or regexp for message comparison
187
+ - have
188
+ - object should have n of property (person.should.have(2, 'pets'))
189
+ - have_at_least
190
+ - object should have at least n of property
191
+ - have_at_most
192
+ - object should have a maximum n of property
193
+ - have_within
194
+ - object should have within n..n of property (person.should.have_within(1..3, 'pets')
195
+ - have_length
196
+ - length of n
197
+ - have_prop
198
+ - object should have property x, optionally supplying an expected value
199
+ - have_property
200
+ - strict version of have_prop
201
+ - be_within
202
+ - checks if n is within the range passed
203
+ - include
204
+ - include substring, array element, or hash key
205
+ - match
206
+ - string should match regexp x
207
+ - respond_to
208
+ - property x should be a function
209
+ - eql
210
+ - matches simple literals (strings, numbers) with ==
211
+ However composites like arrays or 'hashes' are recursively matched,
212
+ meaning that [1, 2, [3]].should_eql([1, 2, [3]]) will be true.
213
+
214
+ ### jQuery
215
+
216
+ - have_tag, have_one
217
+ - have exactly one tag
218
+ - have_tags, have_many
219
+ - have more than one tag
220
+ - have_child
221
+ - have exactly one child
222
+ - have_children
223
+ - have more than one child
224
+ - have_text
225
+ - have plain text
226
+ - have_attr
227
+ - have an attribute, with optional value
228
+ - have_type
229
+ - have_id
230
+ - have_title
231
+ - have_alt
232
+ - have_href
233
+ - have_rel
234
+ - have_rev
235
+ - have_name
236
+ - have_target
237
+ - have_value
238
+ - have_class
239
+ - have_classes
240
+ - be_visible
241
+ - be_hidden
242
+ - be_enabled
243
+ - be_disabled
244
+ - be_selected
245
+ - be_checked
246
+
247
+ ## Growl Support
248
+
249
+ JSpec uses the [JavaScript Growl](http://github.com/visionmedia/js-growl) library to provide
250
+ growl support when using the **Rhino JavaScript engine**. To enable simply `load()` _jspec.growl.js_
251
+ within _spec/rhino.js_
252
+
253
+ ## Async Support With Mock Timers
254
+
255
+ The javascript mock timers library is available at [http://github.com/visionmedia/js-mock-timers](http://github.com/visionmedia/js-mock-timers)
256
+ although it is already bundled with JSpec at _lib/jspec.timers.js_
257
+
258
+ Timers return ids and may be passed to `clearInterval()`, however
259
+ they do not execute in threads, they must be manually scheduled and
260
+ controlled via the `tick()` function.
261
+
262
+ setTimeout(function(){
263
+ alert('Wahoo!')
264
+ }, 400)
265
+
266
+ tick(200) // Nothing happens
267
+ tick(400) // Wahoo!
268
+
269
+ `setInterval()` works as expected, although it persists, where as `setTimeout()`
270
+ is destroyed after a single call. As conveyed by the last `tick()` call below,
271
+ a large increment in milliseconds may cause the callbacks to be called several times
272
+ to 'catch up'.
273
+
274
+ progress = ''
275
+ var id = setInterval(function(){
276
+ progress += '.'
277
+ }, 100)
278
+
279
+ tick(50), print(progress) // ''
280
+ tick(50), print(progress) // '.'
281
+ tick(100), print(progress) // '..'
282
+ tick(100), print(progress) // '...'
283
+ tick(300), print(progress) // '......'
284
+
285
+ clearInterval(id)
286
+
287
+ tick(800) // Nothing happens
288
+
289
+ You may also reset at any time using resetTimers()
290
+
291
+ ## Proxy Assertions
292
+
293
+ Proxy or 'Spy' assertions allow you to assert that a method is called n number
294
+ of times, with x arguments, returning x value. For example:
295
+
296
+ person = { getPets : function(species){ return ['izzy'] }}
297
+ person.should.receive('getPets', 'twice').with_args(an_instance_of(String))and_return(['izzy'])
298
+ person.getPets('dog') // This will pass
299
+ person.getPets() // This will fail because we asked an instance of String
300
+
301
+ This is a useful mechanism for testing the behavior of your object, as well as
302
+ how other methods may interact with it. Below is another example:
303
+
304
+ array = ['foo', 'bar']
305
+ array.should.receive('toString').and_return('foo,bar')
306
+ 'array: ' + array // This line causes the spec to pass due to calling toString()
307
+
308
+ For more examples view _spec/spec.matchers.js_
309
+
310
+ ## Method Stubbing
311
+
312
+ JSpec currently provides very simple stubbing support shown below:
313
+
314
+ person = { toString : function(){ return '<Person>' } }
315
+ stub(person, 'toString').and_return('Ive been stubbed!')
316
+
317
+ After each spec all stubs are restored to their original methods so
318
+ there is no reason to explicitly call `destub()`. To persist stubs,
319
+ use a before_each hook:
320
+
321
+ before_each
322
+ stub(someObject, 'method').and_return({ some : thing })
323
+ end
324
+
325
+ To destub a method simply call `destub()` at any time:
326
+
327
+ destub(person, 'toString')
328
+
329
+ If you would like to whipe an object clear of stubs simply pass it
330
+ to `destub()` without an additional method argument:
331
+
332
+ destub(person)
333
+
334
+ Alternatively both these utility functions may be called as methods
335
+ on any object when using the JSpec grammar:
336
+
337
+ someObject.stub('method').and_return('whatever')
338
+ // Converted to stub(someObject, 'method').and_return('whatever')
339
+
340
+ ## Helpers
341
+
342
+ * core
343
+
344
+ - an_instance_of
345
+ - used in conjunction with the 'receive' matcher
346
+
347
+ * jspec.xhr.js
348
+ - mockRequest, mock_request
349
+ - mock a request
350
+ - unmockRequest, unmock_request
351
+ - unmock requests
352
+ - lastRequest, last_request
353
+ - access previous request data
354
+
355
+ * jspec.jquery.js
356
+
357
+ - sandbox
358
+ - used to generate new DOM sandbox, using jQuery object
359
+ - element
360
+ - same as invoking jQuery, just reads better and no need to worry about $ collisions
361
+ - elements
362
+ - alias of element
363
+
364
+ ## Shared Behaviors
365
+
366
+ JSpec's support for shared behaviors allows multiple suites or describe blocks to share
367
+ common functionality. For example an Admin, would inherit all specs of User:
368
+
369
+ describe 'User'
370
+ before
371
+ User = function(name) { this.name = name }
372
+ user = new User('joe')
373
+ end
374
+
375
+ it 'should have a name'
376
+ user.should.have_property 'name'
377
+ end
378
+
379
+ describe 'Administrator'
380
+ should_behave_like('User')
381
+
382
+ before
383
+ Admin = function(name) { this.name = name }
384
+ Admin.prototype.may = function(perm){ return true }
385
+ user = new Admin('tj')
386
+ end
387
+
388
+ it 'should have access to all permissions'
389
+ user.may('edit pages').should.be_true
390
+ end
391
+ end
392
+ end
393
+
394
+ **NOTE**: both User and Administrator's before hooks implement the 'user' variable
395
+
396
+ ## Mock Ajax Requests
397
+
398
+ JSpec supports generic Ajax mocking which is usable with any JavaScript framework via _jspec.xhr.js_. The
399
+ API is comprised of two functions, `mock_request()` and `unmock_request()`. `unmock_request()` is
400
+ automatically called after each specification to restore the default functionality of XMLHttpRequest,
401
+ so it is uncommon to call `unmock_request()` directly. Below is a jQuery example:
402
+
403
+ it 'should mock requests'
404
+ mock_request().and_return('{ foo : "bar" }', 'application/json')
405
+ $.getJSON('foo', function(response, statusText){
406
+ response.foo.should.eql 'bar'
407
+ })
408
+ end
409
+
410
+ The mock_request().and_return signature is as follows:
411
+
412
+ mock_request().and_return(<data>, [content-type], [response-status-code], [headers-hash])
413
+
414
+ At the moment `mock_request()` itself does not accept any arguments, however in the future
415
+ this will be used to target specific uris for mocking.
416
+
417
+ **NOTE**: works with Rhino as well
418
+
419
+ ## Hooks
420
+
421
+ Currently the following hooks are supported, and may be utilized any number of times as they
422
+ are simply pushed to a stack. So for instance you may have two before_each blocks within the same
423
+ scope, they will both run, but this can help keep your specs readable.
424
+
425
+ - before
426
+ - run once before the suite is executed
427
+ - after
428
+ - run once after the suite is executed
429
+ - before_each
430
+ - run before each specification
431
+ - after_each
432
+ - run after each specification
433
+
434
+ ## Custom Contexts
435
+
436
+ Custom contexts can be applied to supply helper
437
+ methods or properties to all subsequent bodies (other hooks, or specs).
438
+
439
+ Keep in mind that when replacing the default context you will loose
440
+ functionality provided by it, unless you manually merge it with your
441
+ custom context.
442
+
443
+ To reset the context simply assign null to obtain the original context.
444
+
445
+ ...
446
+ before
447
+ JSpec.context = { foo : 'bar' }
448
+ end
449
+
450
+ after
451
+ JSpec.context = null
452
+ end
453
+
454
+ it 'will work ;)'
455
+ foo.should_equal 'bar'
456
+ end
457
+ ...
458
+
459
+ ## Async Support
460
+
461
+ Currently only _jspec.jquery.js_ supports async requests. JSpec uses `jQuery.ajaxSetup` and sets all
462
+ requests to sync, which preserves execution order, and reports correctly.
463
+
464
+ it 'should load mah cookies (textfile)'
465
+ $.post('async', function(text){
466
+ text.should_eql 'cookies!'
467
+ })
468
+ end
469
+
470
+ ## Grammer Pre-processor
471
+
472
+ The pre-processing capability of JSpec is extremely powerful. Your JavaScript
473
+ code is not necessarily what it seems. For example when you seemingly invoke a
474
+ object's prototype like below:
475
+
476
+ 'foobar'.should.include 'bar'
477
+
478
+ First parens are added:
479
+
480
+ 'foobar'.should.include('bar')
481
+
482
+ Secondly the matcher invocation is converted to a non-polluting match() call:
483
+
484
+ expect('foobar').to(include, 'bar')
485
+
486
+ This also means instead of:
487
+
488
+ var object = { foo : 'bar' }
489
+ object.should.include 'foo'
490
+
491
+ We can do:
492
+
493
+ { foo : 'bar' }.should.include 'foo'
494
+
495
+ ### Closure Literal
496
+
497
+ These are equivalent:
498
+
499
+ -{ throw 'test' }.should.throw_error
500
+ function() { throw 'test' }.should.throw_error
501
+
502
+ ### Inclusive Range Literal
503
+
504
+ The following expands to the array of [1,2,3,4,5]
505
+
506
+ n.should.be_within 1..5
507
+
508
+ ### __END__
509
+
510
+ Any text placed after **__END__** is considered irrelevant and
511
+ is striped out before evaluation. This is sometimes useful for
512
+ document or code reference while writing specs.
513
+
514
+ For example when writting regression specs it is sometimes useful
515
+ to paste the issue ticket's comment(s) below this area for reference.
516
+
517
+ ## Formatters
518
+
519
+ To change a reporter simply alter the options hash like below, assigning
520
+ a new constructor, or pass it within the hash to `run()`:
521
+
522
+ JSpec.options.reporter = JSpec.reporters.Console
523
+
524
+ OR
525
+
526
+ JSpec
527
+ .exec('...')
528
+ .run({ reporter: JSpec.reporters.Terminal })
529
+ .report()
530
+
531
+ ## Fixtures
532
+
533
+ The `fixture()` utility function may be used in order to load arbitrary file contents
534
+ for use with your specifications. JSpec will resolve `fixture('data')` in the following
535
+ manor:
536
+
537
+ - <fixturePath>/data
538
+ - <fixturePath>/data.html
539
+
540
+ In order for the `fixture()` utility to function you must pass the **fixturePath** option
541
+ to _JSpec.run()_ which provides JSpec with the fixture directory.
542
+
543
+ ## Testing DOM Elements
544
+
545
+ When using jQuery testing DOM elements is very easy. Many may think they require specific
546
+ sandbox divs in their html, however you do not. Using the fixture support mentioned above
547
+ you may simply load some HTML, and use the `elements()` utility which is an alias of jQuery:
548
+
549
+ describe 'JSpec DOM testing'
550
+ describe 'is so easy'
551
+ before_each
552
+ list = elements(fixture('users-list'))
553
+ // or list = jQuery(fixture('users-list'))
554
+ // or list = $(fixture('users-list'))
555
+ end
556
+
557
+ it 'should have users'
558
+ list.should.have_tag 'ul'
559
+ end
560
+ end
561
+ end
562
+
563
+ You may also use simple strings, since jQuery's constructor will convert them to DOM elements:
564
+
565
+ describe 'Something'
566
+ before_each
567
+ html = elements('<p>Foo</p>')
568
+ // or html = $('<p>Foo</p>') ...
569
+ end
570
+
571
+ it 'should do something'
572
+ html.should.have_text 'Foo'
573
+ end
574
+ end
575
+
576
+ ## Custom Matchers
577
+
578
+ First lets create a simple equality matcher. In the case below JSpec is smart enough to realize
579
+ this is simply a binary operator, and simply transforms this into `actual === expected`
580
+
581
+ JSpec.addMatchers({
582
+ equal : '==='
583
+ })
584
+
585
+ To alias a method to keep your specs readable you may alias them like below:
586
+
587
+ JSpec.addMatchers({
588
+ be : 'alias equal'
589
+ })
590
+
591
+ 'foo'.should.equal 'foo'
592
+ true.should.be true
593
+
594
+ Matchers with string bodies implicitly return the expression value.
595
+ The expanded version of the equal matcher would then be:
596
+
597
+ JSpec.addMatchers({
598
+ equal : 'actual === expected'
599
+ })
600
+
601
+ Large matchers or those which require several parameters may wish
602
+ to utilize the hash method:
603
+
604
+ JSpec.addMatchers({
605
+ equal : { match : function(actual, expected){
606
+ return actual === expected
607
+ }}
608
+ })
609
+
610
+ To keep JSpec tiny, JSpec will default to generating failure messages
611
+ for you, how ever this can be explicitly defined:
612
+
613
+ JSpec.addMatchers({
614
+ equal : {
615
+ match : function(actual, expected){
616
+ return actual === expected
617
+ },
618
+ message : function(actual, expected, negate) {
619
+ return 'a message here'
620
+ }
621
+ }
622
+ })
623
+
624
+ When defining matchers that are extremely similar in functionality, however
625
+ require different names, you may use a prefixed list of words like below which
626
+ defines be_disabled, be_selected, be_checked, and have_type, have_id, etc. Each
627
+ function must return the matcher body which will be used.
628
+
629
+ JSpec.addMatchers({
630
+ 'be disabled selected checked' : function(attr) {
631
+ return 'jQuery(actual).attr("' + attr + '")'
632
+ },
633
+
634
+ 'have type id title alt href src sel rev name target' : function(attr) {
635
+ return function(actual, value) {
636
+ return value ? jQuery(actual).attr(attr) ## value:
637
+ jQuery(actual).attr(attr)
638
+ }
639
+ }
640
+ })
641
+
642
+ ## Extending Or Hooking Into JSpec
643
+
644
+ JSpec provides a hook architecture for extending or analyzing various
645
+ points in its execution, through the use of modules. For a module
646
+ example view _lib/jspec.jquery.js_.
647
+
648
+ The following methods or properties are utilized by JSpec:
649
+
650
+ - name : module name string
651
+ - init : called to initialize a module
652
+ - reporters : hash of reporters merged with JSpec.reporters
653
+ - utilities : hash of utility functions merged with JSpec.defaultContext
654
+ - matchers : hash of matchers merged with JSpec's core matchers via JSpec.addMatchers()
655
+ - DSLs : hash of DSL methods; for example DSLs.snake contains before_each, after_each, etc.
656
+ Where as DSLs.camel may contain beforeEach, afterEach, etc.
657
+
658
+ Below is a list of hooks, descriptions, and valid return values which
659
+ may simply be implemented as module methods. beforeSuite, afterSuite, beforeSpec, and afterSpec have lower
660
+ precedence than before_each, after_each etc within the specs themselves, allowing them to override or undo
661
+ anything that has been done by a Module.
662
+
663
+ - running(options) : started running JSpec with the options passed : returning 'stop' will halt running
664
+ - loading(file) : loading a file : returning 'stop' will prevent loading
665
+ - executing(file) : executing a file : returning 'stop' will prevent execution
666
+ - posting(data, url) : posting data to a url : returning 'stop' will prevent request
667
+ - preprocessing(input) : before input string is preprocessed : return input string for next hook to preprocess
668
+ - stubbing(object, method, result) : called when stubbing an object's method, and return value (result). : (no return value)
669
+ - requiring(dependency, message) : requiring a dependency : (no return value)
670
+ - beforeAssertion(assertion) : before an assertion has been made : (no return value)
671
+ - afterAssertion(assertion) : after an assertion has been made : (no return value)
672
+ - addingMatcher(name, body) : unprocessed matcher name and body : (no return value)
673
+ - addingSuite(suite) : adding Suite instance to JSpec : (no return value)
674
+ - beforeSuite(suite) : before running of suite (describe block) : (no return value)
675
+ - afterSuite(suite) : after running of suite (describe block) : (no return value)
676
+ - beforeSpec(spec) : before running of spec (it block) : (no return value)
677
+ - afterSpec(spec) : after running of spec (it block) : (no return value)
678
+ - reporting(options) : called before reporting : (no return value)
679
+ - evaluatingBody(dsl, matchers, context, contents) : evaluating body contents, with the given context, matchers and dsl. : (no return value)
680
+
681
+ For example you may wish to proxy files which are being executed, simply implement the
682
+ executing method like below. This example will stop execution of any file matching /matchers/.
683
+
684
+ MyModule = {
685
+ executing : function(file) {
686
+ if (file.match(/matchers/))
687
+ return 'stop'
688
+ }
689
+ }
690
+ JSpec.include(MyModule)
691
+
692
+ Immutable values may also be passed to hooks using hookImmutable() internally. This allows
693
+ for simple numbers, strings, etc to be utilized or altered within a hook implementation. Below
694
+ is an example module which adds functionality to the JSpec grammar by converting `SomeObject.stub('method')`
695
+ to `stub(SomeObject, 'method')`:
696
+
697
+ JSpec.include({
698
+ preprocessing : function(input) {
699
+ return input.replace(/(\w+)\.(stub|destub)\((.*?)\)$/gm, '$2($1, $3)')
700
+ }
701
+ })
702
+
703
+ ## JSpec Command-line Utility
704
+
705
+ When installed as a Ruby Gem, the `jspec` executable will become available,
706
+ allowing you to initialize project templates quickly, as well as auto-testing
707
+ specifications when a file is altered.
708
+
709
+ Initialize JSpec-driven project template in directory _myproject_:
710
+ $ jspec init myproject
711
+
712
+ Once within 'myproject' start testing by executing:
713
+ $ jspec
714
+
715
+ For additional usage execute:
716
+ $ jspec help
717
+
718
+ Or for specific usage:
719
+ $ jspec help run
720
+
721
+ ## Extending JSpec's Executable
722
+
723
+ Both project specific, and user specific sub-commands may be used to
724
+ extend those already provided by `jspec`. For example create the following
725
+ in spec/commands/example_command.rb which are loaded when `jspec` is executed.
726
+
727
+ command :example do |c|
728
+ c.syntax = 'jspec example [options]'
729
+ c.description = 'Just an example command'
730
+ c.option '-f', '--foo string', 'Does some foo with <string>'
731
+ c.option '-b', '--bar [string]', 'Does some bar with [string]'
732
+ c.example 'Do some foo', 'jspec example --foo bar'
733
+ c.example 'Do some bar', 'jspec example --bar'
734
+ c.when_called do |args, options|
735
+ p args
736
+ p options.__hash__
737
+ # options.foo
738
+ # options.bar
739
+ # options.__hash__[:foo]
740
+ # options.__hash__[:bar]
741
+ end
742
+ end
743
+
744
+ And execute with:
745
+
746
+ `$ jspec example`
747
+
748
+ They may also be placed at ~/jspec/commands for global usage.
749
+
750
+ For more information on the command creation visit http://visionmedia.github.com/commander
751
+
752
+ ## Installing Support Projects
753
+
754
+ Lets say you need jQuery for your project, and wish to test against it. You could download
755
+ jQuery manually, use an absolute uri to Google's CDN, or use the following command, which will
756
+ install jQuery to _spec/support/jquery.js_.
757
+ $ jspec install jquery
758
+
759
+ Alternatively we may specify the destination path:
760
+ $ jspec install jquery spec/jquery.js
761
+
762
+ Or provide a specific version string:
763
+ $ jspec install jquery --release 1.3.1
764
+
765
+ The install command will also install Rhino for you (**MacOS only**) so you
766
+ can run specs, and js via the command-line.
767
+ $ jspec install rhino
768
+
769
+ To view the current projects supported view:
770
+ $ jspec help install
771
+
772
+ ## Rhino
773
+
774
+ JSpec provides transparent support for Rhino, while using the Terminal reporter.
775
+ Simply create a JavaScript file with contents similar to below, and then execute
776
+ the command following it:
777
+
778
+ load('lib/jspec.js')
779
+
780
+ JSpec
781
+ .exec('spec/spec.grammar.js')
782
+ .exec('spec/spec.core.js')
783
+ .run({ reporter: JSpec.reporters.Terminal, failuresOnly: true })
784
+ .report()
785
+
786
+ Initialize project with:
787
+ $ jspec init myproject
788
+
789
+ Run with:
790
+ $ jspec run --rhino
791
+
792
+ Or bind (automated testing):
793
+ $ jspec --rhino
794
+
795
+ ## Server
796
+
797
+ The Ruby JavaScript testing server included with JSpec simply runs
798
+ the spec suites within each browser you specify, while reporting result
799
+ back to the terminal. It is essentially the same as using the DOM reporter
800
+ and auto-testing each browser, however results are centralized to the terminal,
801
+ removing the need to manually view each browser's output.
802
+
803
+ When utilizing the server if a file named _spec/jspec.rb_ (or _jspec/jspec.rb_ for rails)
804
+ is present, then it will be loaded before the server is started. This allows you to
805
+ add Sinatra routes, support additional Browsers, etc.
806
+
807
+ Run with all supported browsers:
808
+ $ jspec run --server
809
+
810
+ Run with specific browsers:
811
+ $ jspec run --browsers Safari,Firefox,Chrome,Explorer
812
+
813
+ Run with alternative browser names:
814
+ $ jspec run --browsers safari,ff,chrome,ie
815
+
816
+ Browsers supported in core:
817
+
818
+ - Browser::Default (system default)
819
+ - Browser::Safari
820
+ - Browser::Chrome
821
+ - Browser::Opera
822
+ - Browser::Firefox
823
+ - Browser::IE
824
+
825
+ Supplied routes:
826
+
827
+ - /slow/NUMBER
828
+ - /status/NUMBER
829
+
830
+ For example `$.get('/slow/4', function(){})` will take 4 seconds
831
+ to reply, where as `$.get('/status/404', function(){})` will respond
832
+ with an 404 status code. Add additional Sinatra routes to the jspec.rb
833
+ file to add your own functionality.
834
+
835
+ ## Interactive Shell
836
+
837
+ JSpec provides an interactive shell through Rhino, utilize with:
838
+
839
+ $ jspec shell
840
+
841
+ Or to specify additional files to load:
842
+
843
+ $ jspec shell lib/*.js
844
+
845
+ Or view additional shell help
846
+
847
+ $ jspec help shell
848
+
849
+ When running the shell JSpec provides several commands:
850
+
851
+ - quit, exit
852
+ - Terminate the shell session
853
+ - p()
854
+ - Inspect the object passed
855
+
856
+ Or add your own. In the examples below, `foo` will become a getter, so it can
857
+ be invoked simply as `$ foo ` where as `bar` is a regular function which must be called
858
+ as `$ bar("something") `.
859
+
860
+ Shell.commands.foo = ['Does some foo', function(){ return 'something' }]
861
+ Shell.commands.bar = ['Does some bar', function(o){ return 'something' }]
862
+
863
+ ## Ruby on Rails
864
+
865
+ No additional gems are required for JSpec to work with rails, although
866
+ [jspec-rails](http://github.com/bhauman/jspec-rails) has been created by 'bhauman'. JSpec
867
+ supports Rails out of the box, simply execute:
868
+
869
+ $ jspec init --rails
870
+
871
+ Then while still in the root directory of your Rails project, run the following
872
+ command which will bind to, and refresh your browsers automatically when any changes
873
+ are made to _./public/javascripts/*.js_ or _./jspec/*.js_
874
+
875
+ $ jspec
876
+
877
+ Or just like regular JSpec applications, run once:
878
+
879
+ $ jspec run
880
+
881
+ Or run via the terminal using Rhino:
882
+
883
+ $ jspec run --rhino
884
+
885
+ ## Support Browsers
886
+
887
+ Browsers below are supported and can be found in _server/browsers.rb_, however
888
+ your _spec/server.rb_ file may support additional browsers.
889
+
890
+ - Safari
891
+ - Chrome
892
+ - Firefox
893
+ - Opera
894
+ - Internet Explorer
895
+
896
+ ## Known Issues
897
+
898
+ - The preprocessor is not (yet) capable of multiline conversions. For example the following is invalid
899
+
900
+ object.stub('getContentsOfURL').and_return(function(url){
901
+ return 'html'
902
+ })
903
+
904
+ In cases such as this, you may always revert to utilizing JSpec in a grammar-less form as follows:
905
+
906
+ stub(object, 'getContentsOfURL').and_return(function(url){
907
+ return 'html'
908
+ })
909
+
910
+ ## Additional JSpec Modules
911
+
912
+ - JSocka stubbing http://github.com/gisikw/jsocka/tree/master
913
+
914
+ ## More Information
915
+
916
+ - [Google Group](http://groups.google.com/group/jspec)
917
+ - IRC Channel [irc://irc.freenode.net#jspec](irc://irc.freenode.net#jspec)
918
+ - Featured article in JSMag [http://www.jsmag.com/main.issues.description/id=21/](http://www.jsmag.com/main.issues.description/id=21/)
919
+ - Syntax comparison with other frameworks [http://gist.github.com/92283](http://gist.github.com/92283)
920
+ - Get the TextMate bundle at [https://github.com/visionmedia/jspec.tmbundle/tree](https://github.com/visionmedia/jspec.tmbundle/tree)
921
+ - For more information consult the JSpec source code documentation or visit [http://visionmedia.github.com/jspec](http://visionmedia.github.com/jspec)
922
+ - jQuery + HTML fixture example [http://gist.github.com/147831](http://gist.github.com/147831)
923
+ - [http://twitter.com/tjholowaychuk](Twitter)
924
+ - [JSpec Vim Snippits](http://github.com/tobiassvn/snipmate-jspec/)
925
+
926
+ ## Contributors
927
+
928
+ Many ideas and bug reports were contributed by
929
+ the following developers, thankyou for making
930
+ JSpec more enjoyable, and bug free. If I have
931
+ missed you on this list please let me know
932
+ (aka the fellow who donated [jspec.info](http://jspec.info))
933
+
934
+ - Lawrence Pit
935
+ - [mpd@jesters-court.ne](mpd@jesters-court.ne)
936
+ - [Sarah Brown](brown.sarah.v@gmail.com)
937
+ - [kevin.gisi@gmail.com](kevin.gisi@gmail.com)
938
+ - [tony_t_tubbs@yahoo.com](tony_t_tubbs@yahoo.com)
939
+ - [enno84@gmx.net](enno84@gmx.net)
940
+ - fnando
941
+ - Tobias Svensson
942
+
943
+ ## License
944
+
945
+ (The MIT License)
946
+
947
+ Copyright (c) 2008 - 2009 TJ Holowaychuk <tj@vision-media.ca>
948
+
949
+ Permission is hereby granted, free of charge, to any person obtaining
950
+ a copy of this software and associated documentation files (the
951
+ 'Software'), to deal in the Software without restriction, including
952
+ without limitation the rights to use, copy, modify, merge, publish,
953
+ distribute, sublicense, and/or sell copies of the Software, and to
954
+ permit persons to whom the Software is furnished to do so, subject to
955
+ the following conditions:
956
+
957
+ The above copyright notice and this permission notice shall be
958
+ included in all copies or substantial portions of the Software.
959
+
960
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
961
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
962
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
963
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
964
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
965
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
966
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
967
+
968
+