jspec 2.11.13 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+