jspec 3.3.3 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.md +22 -0
- data/README.md +85 -26
- data/bin/jspec +1 -1
- data/jspec.gemspec +2 -2
- data/lib/jspec.js +188 -68
- data/spec/node.js +1 -1
- data/spec/unit/spec.fixtures.js +7 -0
- data/spec/unit/spec.grammar.js +65 -31
- data/spec/unit/spec.shared-behaviors.js +246 -47
- metadata +5 -5
data/History.md
CHANGED
@@ -1,4 +1,26 @@
|
|
1
1
|
|
2
|
+
4.0.0 / 2010-03-22
|
3
|
+
==================
|
4
|
+
|
5
|
+
* Added json_fixture(). Closes #157
|
6
|
+
|
7
|
+
* Added swalke16 to contrib list (shared behavior fixes)
|
8
|
+
|
9
|
+
* Added shared_behaviors_for() for shared behavior support.
|
10
|
+
This is essentially a Suite instance, however the shared
|
11
|
+
behavior itself is no longer executed, only suites which use
|
12
|
+
should_behave_like().
|
13
|
+
|
14
|
+
* Added before_nested / after_nested for legacy support.
|
15
|
+
These hooks function just as before / after did < 4.0.0,
|
16
|
+
where they will execute once per nested suite as well.
|
17
|
+
|
18
|
+
* Changed; before / after are now executed ONLY once, not
|
19
|
+
when a nested suite is running. Use before_nested / after_nested
|
20
|
+
if you wish to re-gain this functionality.
|
21
|
+
|
22
|
+
* Removed JSpec.error()
|
23
|
+
|
2
24
|
3.3.3 / 2010-03-15
|
3
25
|
==================
|
4
26
|
|
data/README.md
CHANGED
@@ -48,6 +48,7 @@ To add or request removal from this list please email tj@vision-media.ca
|
|
48
48
|
* [Google - YouTube](http://youtube.com)
|
49
49
|
* [Palm](http://palm.com)
|
50
50
|
* [Carfax](http://carfax.com)
|
51
|
+
* [Apache CouchDB](http://couchdb.apache.org)
|
51
52
|
* [Vision Media](http://vision-media.ca)
|
52
53
|
|
53
54
|
## Installation
|
@@ -364,34 +365,81 @@ on any object when using the JSpec grammar:
|
|
364
365
|
## Shared Behaviors
|
365
366
|
|
366
367
|
JSpec's support for shared behaviors allows multiple suites or describe blocks to share
|
367
|
-
common functionality
|
368
|
+
common functionality, including specs and hooks. Shared functionality is run in the order in
|
369
|
+
which it is included in the hosting suite. For example a canine would inherit all
|
370
|
+
behavior of an animal, and particular breeds of dog would inherit all behavior from the canine.
|
371
|
+
Note that as in the poodle example, shared behaviors can be nested inside suites or describe
|
372
|
+
blocks and will be visible only to other describe blocks _at or below_ the same nesting level.
|
373
|
+
|
374
|
+
shared_behaviors_for 'animal'
|
375
|
+
before
|
376
|
+
animal = { eats: function(){return true }}
|
377
|
+
end
|
378
|
+
|
379
|
+
it 'should eat'
|
380
|
+
animal.eats().should.eql true
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
shared_behaviors_for 'canine'
|
385
|
+
should_behave_like('animal')
|
386
|
+
|
387
|
+
before
|
388
|
+
animal.hasFourLegs = function(){ return true }
|
389
|
+
animal.barks = function(){ return true }
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'should have 4 legs'
|
393
|
+
animal.hasFourLegs().should.eql true
|
394
|
+
end
|
395
|
+
|
396
|
+
it 'should bark'
|
397
|
+
animal.barks().should.eql true
|
398
|
+
end
|
399
|
+
end
|
368
400
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
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
|
401
|
+
describe 'mastif'
|
402
|
+
should_behave_like('canine')
|
403
|
+
|
404
|
+
before
|
405
|
+
animal.weight = 200
|
406
|
+
end
|
393
407
|
|
394
|
-
|
408
|
+
it 'should weigh > 100 lbs'
|
409
|
+
animal.weight.should.be_greater_than 100
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
describe 'poodle breeds'
|
414
|
+
should_behave_like('canine')
|
415
|
+
|
416
|
+
shared_behaviors_for 'poodle'
|
417
|
+
before
|
418
|
+
animal.isMean = true
|
419
|
+
end
|
420
|
+
|
421
|
+
it 'should be mean'
|
422
|
+
animal.isMean.should.eql true
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
describe 'fancy poodle'
|
427
|
+
should_behave_like('poodle')
|
428
|
+
|
429
|
+
before
|
430
|
+
animal.looksRidiculous = true
|
431
|
+
end
|
432
|
+
|
433
|
+
it 'should look ridiculous'
|
434
|
+
animal.looksRidiculous.should.eql true
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
NOTE: When the should_behave_like() call is searching for behaviors to include, it works inside out.
|
440
|
+
Therefore any nested shared behaviors by the same name as a shared behavior at a higher
|
441
|
+
nesting level will override the one at the higher level.
|
442
|
+
|
395
443
|
|
396
444
|
## Mock Ajax Requests
|
397
445
|
|
@@ -430,6 +478,10 @@ scope, they will both run, but this can help keep your specs readable.
|
|
430
478
|
- run before each specification
|
431
479
|
- after_each
|
432
480
|
- run after each specification
|
481
|
+
- before_nested
|
482
|
+
- run once before the suite and once before any nested suites
|
483
|
+
- after_nested
|
484
|
+
- run once after the suite and once after any nested suites
|
433
485
|
|
434
486
|
## Custom Contexts
|
435
487
|
|
@@ -540,6 +592,12 @@ manor:
|
|
540
592
|
In order for the `fixture()` utility to function you must pass the **fixturePath** option
|
541
593
|
to _JSpec.run()_ which provides JSpec with the fixture directory.
|
542
594
|
|
595
|
+
The `json_fixture()` utility works much the same as `fixture()` however `fixture('data')`
|
596
|
+
will be parsed as JSON, and resolved as shown below:
|
597
|
+
|
598
|
+
- <fixturePath>/data
|
599
|
+
- <fixturePath>/data.json
|
600
|
+
|
543
601
|
## Testing DOM Elements
|
544
602
|
|
545
603
|
When using jQuery testing DOM elements is very easy. Many may think they require specific
|
@@ -940,6 +998,7 @@ missed you on this list please let me know
|
|
940
998
|
- [kevin.gisi@gmail.com](kevin.gisi@gmail.com)
|
941
999
|
- [tony_t_tubbs@yahoo.com](tony_t_tubbs@yahoo.com)
|
942
1000
|
- [enno84@gmx.net](enno84@gmx.net)
|
1001
|
+
- swalke16
|
943
1002
|
- fnando
|
944
1003
|
- Tobias Svensson
|
945
1004
|
|
data/bin/jspec
CHANGED
data/jspec.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{jspec}
|
5
|
-
s.version = "
|
5
|
+
s.version = "4.0.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["TJ Holowaychuk"]
|
9
|
-
s.date = %q{2010-03-
|
9
|
+
s.date = %q{2010-03-22}
|
10
10
|
s.default_executable = %q{jspec}
|
11
11
|
s.description = %q{JavaScript BDD Testing Framework}
|
12
12
|
s.email = %q{tj@vision-media.ca}
|
data/lib/jspec.js
CHANGED
@@ -4,12 +4,13 @@
|
|
4
4
|
;(function(){
|
5
5
|
|
6
6
|
JSpec = {
|
7
|
-
version : '
|
7
|
+
version : '4.0.0',
|
8
8
|
assert : true,
|
9
9
|
cache : {},
|
10
10
|
suites : [],
|
11
11
|
modules : [],
|
12
12
|
allSuites : [],
|
13
|
+
sharedBehaviors: [],
|
13
14
|
matchers : {},
|
14
15
|
stubbed : [],
|
15
16
|
options : {},
|
@@ -68,6 +69,31 @@
|
|
68
69
|
return JSpec.cache[path] =
|
69
70
|
JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) ||
|
70
71
|
JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.html')
|
72
|
+
},
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Load json fixture at _path_.
|
76
|
+
*
|
77
|
+
* JSON fixtures are resolved as:
|
78
|
+
*
|
79
|
+
* - <path>
|
80
|
+
* - <path>.json
|
81
|
+
*
|
82
|
+
* @param {string} path
|
83
|
+
* @return {object}
|
84
|
+
* @api public
|
85
|
+
*/
|
86
|
+
|
87
|
+
json_fixture: function(path) {
|
88
|
+
if (!JSpec.cache['json:' + path])
|
89
|
+
JSpec.cache['json:' + path] =
|
90
|
+
JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) ||
|
91
|
+
JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.json')
|
92
|
+
try {
|
93
|
+
return eval('(' + JSpec.cache['json:' + path] + ')')
|
94
|
+
} catch (e) {
|
95
|
+
throw 'json_fixture("' + path + '"): ' + e
|
96
|
+
}
|
71
97
|
}
|
72
98
|
},
|
73
99
|
|
@@ -92,7 +118,7 @@
|
|
92
118
|
stats: JSpec.stats,
|
93
119
|
options: options,
|
94
120
|
results: map(results.allSuites, function(suite) {
|
95
|
-
if (suite.
|
121
|
+
if (suite.isExecutable())
|
96
122
|
return {
|
97
123
|
description: suite.description,
|
98
124
|
specs: map(suite.specs, function(spec) {
|
@@ -145,7 +171,7 @@
|
|
145
171
|
<span class="passes">Duration: <em>' + results.duration + '</em> ms</span> \
|
146
172
|
</div><table class="suites">' + map(results.allSuites, function(suite) {
|
147
173
|
var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran
|
148
|
-
if (displaySuite && suite.
|
174
|
+
if (displaySuite && suite.isExecutable())
|
149
175
|
return '<tr class="description"><td colspan="2">' + escape(suite.description) + '</td></tr>' +
|
150
176
|
map(suite.specs, function(i, spec) {
|
151
177
|
return '<tr class="' + (i % 2 ? 'odd' : 'even') + '">' +
|
@@ -181,7 +207,7 @@
|
|
181
207
|
|
182
208
|
each(results.allSuites, function(suite) {
|
183
209
|
var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran
|
184
|
-
if (displaySuite && suite.
|
210
|
+
if (displaySuite && suite.isExecutable()) {
|
185
211
|
print(color(' ' + suite.description, 'bold'))
|
186
212
|
each(suite.specs, function(spec){
|
187
213
|
var assertionsGraph = inject(spec.assertions, '', function(graph, assertion){
|
@@ -392,17 +418,21 @@
|
|
392
418
|
* @api private
|
393
419
|
*/
|
394
420
|
|
395
|
-
Suite : function(description, body) {
|
421
|
+
Suite : function(description, body, isShared) {
|
396
422
|
var self = this
|
397
423
|
extend(this, {
|
398
424
|
body: body,
|
399
425
|
description: description,
|
400
426
|
suites: [],
|
427
|
+
sharedBehaviors: [],
|
401
428
|
specs: [],
|
402
429
|
ran: false,
|
403
|
-
|
430
|
+
shared: isShared,
|
431
|
+
hooks: { 'before' : [], 'after' : [],
|
432
|
+
'before_each' : [], 'after_each' : [],
|
433
|
+
'before_nested' : [], 'after_nested' : []},
|
404
434
|
|
405
|
-
|
435
|
+
// Add a spec to the suite
|
406
436
|
|
407
437
|
addSpec : function(description, body) {
|
408
438
|
var spec = new JSpec.Spec(description, body)
|
@@ -411,16 +441,30 @@
|
|
411
441
|
spec.suite = this
|
412
442
|
},
|
413
443
|
|
414
|
-
// Add a hook to the suite
|
444
|
+
// Add a before hook to the suite
|
445
|
+
|
446
|
+
addBefore : function(options, body) {
|
447
|
+
body.options = options || {}
|
448
|
+
this.befores.push(body)
|
449
|
+
},
|
415
450
|
|
451
|
+
// Add an after hook to the suite
|
452
|
+
|
453
|
+
addAfter : function(options, body) {
|
454
|
+
body.options = options || {}
|
455
|
+
this.afters.unshift(body)
|
456
|
+
},
|
457
|
+
|
458
|
+
// Add a hook to the suite
|
459
|
+
|
416
460
|
addHook : function(hook, body) {
|
417
461
|
this.hooks[hook].push(body)
|
418
462
|
},
|
419
463
|
|
420
464
|
// Add a nested suite
|
421
465
|
|
422
|
-
addSuite : function(description, body) {
|
423
|
-
var suite = new JSpec.Suite(description, body)
|
466
|
+
addSuite : function(description, body, isShared) {
|
467
|
+
var suite = new JSpec.Suite(description, body, isShared)
|
424
468
|
JSpec.allSuites.push(suite)
|
425
469
|
suite.name = suite.description
|
426
470
|
suite.description = this.description + ' ' + suite.description
|
@@ -428,15 +472,17 @@
|
|
428
472
|
suite.suite = this
|
429
473
|
},
|
430
474
|
|
431
|
-
|
475
|
+
// Invoke a hook in context to this suite
|
432
476
|
|
433
477
|
hook : function(hook) {
|
434
|
-
|
478
|
+
if (hook != 'before' && hook != 'after')
|
479
|
+
if (this.suite) this.suite.hook(hook)
|
480
|
+
|
435
481
|
each(this.hooks[hook], function(body) {
|
436
482
|
JSpec.evalBody(body, "Error in hook '" + hook + "', suite '" + self.description + "': ")
|
437
483
|
})
|
438
484
|
},
|
439
|
-
|
485
|
+
|
440
486
|
// Check if nested suites are present
|
441
487
|
|
442
488
|
hasSuites : function() {
|
@@ -455,7 +501,15 @@
|
|
455
501
|
return !any(this.specs, function(spec){
|
456
502
|
return !spec.passed()
|
457
503
|
})
|
458
|
-
}
|
504
|
+
},
|
505
|
+
|
506
|
+
isShared : function(){
|
507
|
+
return this.shared
|
508
|
+
},
|
509
|
+
|
510
|
+
isExecutable : function() {
|
511
|
+
return !this.isShared() && this.hasSpecs()
|
512
|
+
}
|
459
513
|
})
|
460
514
|
},
|
461
515
|
|
@@ -603,7 +657,7 @@
|
|
603
657
|
},
|
604
658
|
|
605
659
|
describe : function(description, body) {
|
606
|
-
return JSpec.currentSuite.addSuite(description, body)
|
660
|
+
return JSpec.currentSuite.addSuite(description, body, false)
|
607
661
|
},
|
608
662
|
|
609
663
|
it : function(description, body) {
|
@@ -613,19 +667,31 @@
|
|
613
667
|
before : function(body) {
|
614
668
|
return JSpec.currentSuite.addHook('before', body)
|
615
669
|
},
|
616
|
-
|
670
|
+
|
617
671
|
after : function(body) {
|
618
672
|
return JSpec.currentSuite.addHook('after', body)
|
619
673
|
},
|
620
|
-
|
674
|
+
|
621
675
|
before_each : function(body) {
|
622
676
|
return JSpec.currentSuite.addHook('before_each', body)
|
623
677
|
},
|
624
|
-
|
678
|
+
|
625
679
|
after_each : function(body) {
|
626
680
|
return JSpec.currentSuite.addHook('after_each', body)
|
627
681
|
},
|
682
|
+
|
683
|
+
before_nested : function(body) {
|
684
|
+
return JSpec.currentSuite.addHook('before_nested', body)
|
685
|
+
},
|
686
|
+
|
687
|
+
after_nested : function(body){
|
688
|
+
return JSpec.currentSuite.addhook('after_nested', body)
|
689
|
+
},
|
628
690
|
|
691
|
+
shared_behaviors_for : function(description, body){
|
692
|
+
return JSpec.currentSuite.addSuite(description, body, true)
|
693
|
+
},
|
694
|
+
|
629
695
|
should_behave_like : function(description) {
|
630
696
|
return JSpec.shareBehaviorsOf(description)
|
631
697
|
}
|
@@ -702,8 +768,7 @@
|
|
702
768
|
|
703
769
|
evalHook : function(module, name, args) {
|
704
770
|
hook('evaluatingHookBody', module, name)
|
705
|
-
|
706
|
-
catch(e) { error('Error in hook ' + module.name + '.' + name + ': ', e) }
|
771
|
+
return module[name].apply(module, args)
|
707
772
|
},
|
708
773
|
|
709
774
|
/**
|
@@ -726,19 +791,69 @@
|
|
726
791
|
},
|
727
792
|
|
728
793
|
/**
|
729
|
-
* Find a suite by its description or name.
|
794
|
+
* Find a shared example suite by its description or name.
|
795
|
+
* First searches parent tree of suites for shared behavior
|
796
|
+
* before falling back to global scoped nested behaviors.
|
730
797
|
*
|
731
798
|
* @param {string} description
|
732
799
|
* @return {Suite}
|
733
800
|
* @api private
|
734
801
|
*/
|
735
802
|
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
803
|
+
findSharedBehavior : function(description) {
|
804
|
+
var behavior
|
805
|
+
return (behavior = JSpec.findLocalSharedBehavior(description))
|
806
|
+
? behavior
|
807
|
+
: JSpec.findGlobalSharedBehavior(description)
|
740
808
|
},
|
809
|
+
|
810
|
+
/**
|
811
|
+
* Find a shared example suite within the current suite's
|
812
|
+
* parent tree by its description or name.
|
813
|
+
*
|
814
|
+
* @param {string} description
|
815
|
+
* @return {Suite}
|
816
|
+
* @api private
|
817
|
+
*/
|
818
|
+
|
819
|
+
findLocalSharedBehavior : function(description) {
|
820
|
+
var behavior,
|
821
|
+
currentSuite = JSpec.currentSuite.suite
|
822
|
+
while (currentSuite)
|
823
|
+
if (behavior = find(currentSuite.suites, JSpec.suiteDescriptionPredicate(description)))
|
824
|
+
return behavior
|
825
|
+
else
|
826
|
+
currentSuite = currentSuite.suite
|
827
|
+
},
|
828
|
+
|
829
|
+
/**
|
830
|
+
* Find a shared example suite within the global
|
831
|
+
* scope by its description or name.
|
832
|
+
*
|
833
|
+
* @param {string} description
|
834
|
+
* @return {Suite}
|
835
|
+
* @api private
|
836
|
+
*/
|
837
|
+
|
838
|
+
findGlobalSharedBehavior : function(description) {
|
839
|
+
return find(JSpec.suites, JSpec.suiteDescriptionPredicate(description))
|
840
|
+
},
|
741
841
|
|
842
|
+
/**
|
843
|
+
* Build a predicate that will match a suite based on name or description
|
844
|
+
*
|
845
|
+
* @param {string} description
|
846
|
+
* @return {function}
|
847
|
+
* @api private
|
848
|
+
*/
|
849
|
+
|
850
|
+
suiteDescriptionPredicate : function(description) {
|
851
|
+
return function(suite){
|
852
|
+
return suite.name === description ||
|
853
|
+
suite.description === description
|
854
|
+
}
|
855
|
+
},
|
856
|
+
|
742
857
|
/**
|
743
858
|
* Share behaviors (specs) of the given suite with
|
744
859
|
* the current suite.
|
@@ -748,26 +863,13 @@
|
|
748
863
|
*/
|
749
864
|
|
750
865
|
shareBehaviorsOf : function(description) {
|
751
|
-
|
752
|
-
|
866
|
+
var suite = JSpec.findSharedBehavior(description)
|
867
|
+
if (suite)
|
868
|
+
JSpec.evalBody(suite.body)
|
869
|
+
else
|
870
|
+
throw new Error("failed to find shared behaviors named `" + description + "'")
|
753
871
|
},
|
754
872
|
|
755
|
-
/**
|
756
|
-
* Copy specs from one suite to another.
|
757
|
-
*
|
758
|
-
* @param {Suite} fromSuite
|
759
|
-
* @param {Suite} toSuite
|
760
|
-
* @api public
|
761
|
-
*/
|
762
|
-
|
763
|
-
copySpecs : function(fromSuite, toSuite) {
|
764
|
-
each(fromSuite.specs, function(spec){
|
765
|
-
var newSpec = new Object();
|
766
|
-
extend(newSpec, spec);
|
767
|
-
newSpec.assertions = [];
|
768
|
-
toSuite.specs.push(newSpec);
|
769
|
-
})
|
770
|
-
},
|
771
873
|
|
772
874
|
/**
|
773
875
|
* Convert arguments to an array.
|
@@ -1277,12 +1379,27 @@
|
|
1277
1379
|
*/
|
1278
1380
|
|
1279
1381
|
describe : function(description, body) {
|
1280
|
-
var suite = new JSpec.Suite(description, body)
|
1382
|
+
var suite = new JSpec.Suite(description, body, false)
|
1281
1383
|
hook('addingSuite', suite)
|
1282
1384
|
this.allSuites.push(suite)
|
1283
1385
|
this.suites.push(suite)
|
1284
1386
|
},
|
1285
1387
|
|
1388
|
+
/**
|
1389
|
+
* Add a shared example suite to JSpec.
|
1390
|
+
*
|
1391
|
+
* @param {string} description
|
1392
|
+
* @param {body} function
|
1393
|
+
* @api public
|
1394
|
+
*/
|
1395
|
+
|
1396
|
+
shared_behaviors_for : function(description, body) {
|
1397
|
+
var suite = new JSpec.Suite(description, body, true)
|
1398
|
+
hook('addingSuite', suite)
|
1399
|
+
this.allSuites.push(suite)
|
1400
|
+
this.suites.push(suite)
|
1401
|
+
},
|
1402
|
+
|
1286
1403
|
/**
|
1287
1404
|
* Return the contents of a function body.
|
1288
1405
|
*
|
@@ -1309,9 +1426,8 @@
|
|
1309
1426
|
var matchers = this.matchers
|
1310
1427
|
var context = this.context || this.defaultContext
|
1311
1428
|
var contents = this.contentsOf(body)
|
1312
|
-
|
1313
|
-
|
1314
|
-
catch(e) { error(errorMessage, e) }
|
1429
|
+
hook('evaluatingBody', dsl, matchers, context, contents)
|
1430
|
+
with (dsl){ with (context) { with (matchers) { eval(contents) }}}
|
1315
1431
|
},
|
1316
1432
|
|
1317
1433
|
/**
|
@@ -1331,8 +1447,9 @@
|
|
1331
1447
|
split('__END__')[0].
|
1332
1448
|
replace(/([\w\.]+)\.(stub|destub)\((.*?)\)$/gm, '$2($1, $3)').
|
1333
1449
|
replace(/describe\s+(.*?)$/gm, 'describe($1, function(){').
|
1450
|
+
replace(/shared_behaviors_for\s+(.*?)$/gm, 'shared_behaviors_for($1, function(){').
|
1334
1451
|
replace(/^\s+it\s+(.*?)$/gm, ' it($1, function(){').
|
1335
|
-
|
1452
|
+
replace(/^ *(before_nested|after_nested|before_each|after_each|before|after)(?= |\n|$)/gm, 'JSpec.currentSuite.addHook("$1", function(){').
|
1336
1453
|
replace(/^\s*end(?=\s|$)/gm, '});').
|
1337
1454
|
replace(/-\{/g, 'function(){').
|
1338
1455
|
replace(/(\d+)\.\.(\d+)/g, function(_, a, b){ return range(a, b) }).
|
@@ -1395,25 +1512,28 @@
|
|
1395
1512
|
*/
|
1396
1513
|
|
1397
1514
|
runSuite : function(suite) {
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1515
|
+
if (!suite.isShared())
|
1516
|
+
{
|
1517
|
+
this.currentSuite = suite
|
1518
|
+
this.evalBody(suite.body)
|
1519
|
+
suite.ran = true
|
1520
|
+
hook('beforeSuite', suite), suite.hook('before'), suite.hook('before_nested')
|
1521
|
+
each(suite.specs, function(spec) {
|
1522
|
+
hook('beforeSpec', spec)
|
1523
|
+
suite.hook('before_each')
|
1524
|
+
JSpec.runSpec(spec)
|
1525
|
+
hook('afterSpec', spec)
|
1526
|
+
suite.hook('after_each')
|
1527
|
+
})
|
1528
|
+
if (suite.hasSuites()) {
|
1529
|
+
each(suite.suites, function(suite) {
|
1530
|
+
JSpec.runSuite(suite)
|
1531
|
+
})
|
1532
|
+
}
|
1533
|
+
hook('afterSuite', suite), suite.hook('after_nested'), suite.hook('after')
|
1534
|
+
this.stats.suitesFinished++
|
1535
|
+
}
|
1536
|
+
},
|
1417
1537
|
|
1418
1538
|
/**
|
1419
1539
|
* Report a failure for the current spec.
|
@@ -1596,7 +1716,7 @@
|
|
1596
1716
|
return request.responseText
|
1597
1717
|
}
|
1598
1718
|
else
|
1599
|
-
|
1719
|
+
throw new Error("failed to load `" + file + "'")
|
1600
1720
|
},
|
1601
1721
|
|
1602
1722
|
/**
|
data/spec/node.js
CHANGED
@@ -12,6 +12,6 @@ JSpec
|
|
12
12
|
.exec('spec/unit/spec.shared-behaviors.js')
|
13
13
|
.exec('spec/unit/spec.grammar.js')
|
14
14
|
.exec('spec/unit/spec.grammar-less.js')
|
15
|
-
|
15
|
+
.exec('spec/unit/spec.fixtures.js')
|
16
16
|
.run({ reporter: JSpec.reporters.Terminal, failuresOnly: true, fixturePath: 'spec/fixtures' })
|
17
17
|
.report()
|
data/spec/unit/spec.fixtures.js
CHANGED
@@ -14,4 +14,11 @@ describe 'Utility'
|
|
14
14
|
delete JSpec.cache['test']
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
describe 'json_fixture()'
|
19
|
+
it 'should evaluate json fixtures'
|
20
|
+
json_fixture('test').should.eql { users : { tj : { email : 'tj@vision-media.ca' }}}
|
21
|
+
json_fixture('test.json').should.eql { users : { tj : { email : 'tj@vision-media.ca' }}}
|
22
|
+
end
|
23
|
+
end
|
17
24
|
end
|
data/spec/unit/spec.grammar.js
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
|
2
1
|
describe 'Grammar'
|
3
|
-
|
4
|
-
it 'should allow "it" spec literal'
|
2
|
+
it 'should allow "it" spec literal'
|
5
3
|
true.should.be_true
|
6
4
|
end
|
7
5
|
|
@@ -10,7 +8,7 @@ describe 'Grammar'
|
|
10
8
|
it 'should allow literal javascript outside of blocks'
|
11
9
|
n.should.eql 10
|
12
10
|
end
|
13
|
-
|
11
|
+
|
14
12
|
it 'should escape <html> in <p>descriptions</p> and body'
|
15
13
|
'<p></p>'.should.eql '<p></p>'
|
16
14
|
end
|
@@ -75,9 +73,9 @@ describe 'Grammar'
|
|
75
73
|
|
76
74
|
it 'should allow multi-line expect() assertions'
|
77
75
|
expect(' \
|
78
|
-
|
79
|
-
|
80
|
-
|
76
|
+
foo \
|
77
|
+
bar \
|
78
|
+
').to(include, 'foo', 'bar')
|
81
79
|
end
|
82
80
|
|
83
81
|
it 'should allow commenting out of conversions'
|
@@ -106,21 +104,21 @@ describe 'Grammar'
|
|
106
104
|
'bar'.should.not.equal 'foo'
|
107
105
|
end
|
108
106
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
107
|
+
describe 'with tabs'
|
108
|
+
before_each
|
109
|
+
foo = 'bar'
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should work'
|
113
|
+
foo.should.eql 'bar'
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should work'
|
117
|
+
true.should.be true
|
118
|
+
true.should.be(true)
|
119
|
+
true.should.be(true);
|
120
|
+
end
|
121
|
+
end
|
124
122
|
|
125
123
|
describe 'with nested describe'
|
126
124
|
it 'should work'
|
@@ -141,7 +139,7 @@ describe 'Grammar'
|
|
141
139
|
hits.push('before')
|
142
140
|
end
|
143
141
|
|
144
|
-
after
|
142
|
+
after
|
145
143
|
n = 0
|
146
144
|
hits.push('after')
|
147
145
|
end
|
@@ -158,15 +156,51 @@ describe 'Grammar'
|
|
158
156
|
end
|
159
157
|
|
160
158
|
describe 'with nested describe'
|
161
|
-
it 'should be accessable'
|
162
|
-
n.should.eql
|
163
|
-
hits.should.eql ['before']
|
159
|
+
it 'variables should be accessable'
|
160
|
+
n.should.eql 2
|
164
161
|
end
|
162
|
+
|
163
|
+
it 'should only run for outer describe'
|
164
|
+
hits.should.eql ['before']
|
165
|
+
end
|
165
166
|
end
|
166
167
|
end
|
167
168
|
|
169
|
+
describe 'before_nested / after_nested blocks'
|
170
|
+
before
|
171
|
+
x = 0
|
172
|
+
y = 0
|
173
|
+
end
|
174
|
+
|
175
|
+
before_nested
|
176
|
+
x++
|
177
|
+
end
|
178
|
+
|
179
|
+
after_nested
|
180
|
+
y++
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should execute before_nested before suite'
|
184
|
+
x.should.eql 1
|
185
|
+
end
|
186
|
+
|
187
|
+
describe 'with nested describe'
|
188
|
+
it 'should execute before_nested before nested suite'
|
189
|
+
x.should.eql 2
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe 'after_nested'
|
194
|
+
it 'should execute after_nested after nested suite'
|
195
|
+
y.should.eql 1
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
168
200
|
describe 'before_each / after_each blocks'
|
169
|
-
|
201
|
+
before
|
202
|
+
hits = []
|
203
|
+
end
|
170
204
|
|
171
205
|
before_each
|
172
206
|
n = 1
|
@@ -202,7 +236,7 @@ describe 'Grammar'
|
|
202
236
|
end
|
203
237
|
|
204
238
|
describe 'with more hooks'
|
205
|
-
before_each
|
239
|
+
before_each
|
206
240
|
hits.push('before_each')
|
207
241
|
end
|
208
242
|
|
@@ -232,10 +266,10 @@ describe 'Grammar'
|
|
232
266
|
end
|
233
267
|
|
234
268
|
end
|
235
|
-
|
269
|
+
|
236
270
|
__END__
|
237
|
-
|
271
|
+
|
238
272
|
this should not matter because it is
|
239
273
|
considered a comment by the JSpec grammar :)
|
240
|
-
and is sometimes useful for temp reference info
|
274
|
+
and is sometimes useful for temp reference info
|
241
275
|
when writting specs.
|
@@ -1,80 +1,279 @@
|
|
1
|
+
shared_behaviors_for 'animal'
|
2
|
+
before
|
3
|
+
animal = { eats: function(){ return true } }
|
4
|
+
end
|
5
|
+
|
6
|
+
it 'should eat'
|
7
|
+
animal.eats().should.eql true
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
shared_behaviors_for 'canine'
|
12
|
+
should_behave_like('animal')
|
13
|
+
|
14
|
+
before
|
15
|
+
animal.hasFourLegs = function(){ return true }
|
16
|
+
animal.barks = function(){ return true }
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should have 4 legs'
|
20
|
+
animal.hasFourLegs().should.eql true
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should bark'
|
24
|
+
animal.barks().should.eql true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'mastif'
|
29
|
+
should_behave_like('canine')
|
30
|
+
|
31
|
+
before
|
32
|
+
animal.weight = 200
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should weigh > 100 lbs'
|
36
|
+
animal.weight.should.be_greater_than 100
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'poodle breeds'
|
41
|
+
should_behave_like('canine')
|
42
|
+
|
43
|
+
shared_behaviors_for 'poodle'
|
44
|
+
before
|
45
|
+
animal.isMean = true
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should be mean'
|
49
|
+
animal.isMean.should.eql true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'fancy poodle'
|
54
|
+
should_behave_like('poodle')
|
55
|
+
|
56
|
+
before
|
57
|
+
animal.looksRidiculous = true
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should look ridiculous'
|
61
|
+
animal.looksRidiculous.should.eql true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'shared behaviors'
|
67
|
+
before
|
68
|
+
before_sequence = []
|
69
|
+
before_each_sequence = []
|
70
|
+
after_sequence = []
|
71
|
+
after_each_sequence = []
|
72
|
+
end
|
73
|
+
|
74
|
+
shared_behaviors_for 'A'
|
75
|
+
before
|
76
|
+
before_sequence.push('A')
|
77
|
+
end
|
78
|
+
|
79
|
+
after
|
80
|
+
after_sequence.push('A')
|
81
|
+
end
|
82
|
+
|
83
|
+
before_each
|
84
|
+
before_each_sequence.push('A')
|
85
|
+
end
|
86
|
+
|
87
|
+
after_each
|
88
|
+
after_each_sequence.push('A')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
shared_behaviors_for 'B'
|
93
|
+
before
|
94
|
+
before_sequence.push('B')
|
95
|
+
end
|
96
|
+
|
97
|
+
after
|
98
|
+
after_sequence.push('B')
|
99
|
+
end
|
100
|
+
|
101
|
+
before_each
|
102
|
+
before_each_sequence.push('B')
|
103
|
+
end
|
104
|
+
|
105
|
+
after_each
|
106
|
+
after_each_sequence.push('B')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe 'before ordering'
|
111
|
+
should_behave_like('B')
|
112
|
+
|
113
|
+
before
|
114
|
+
before_sequence.push('C')
|
115
|
+
end
|
116
|
+
|
117
|
+
should_behave_like('A')
|
118
|
+
|
119
|
+
after
|
120
|
+
after_sequence.push('C')
|
121
|
+
end
|
122
|
+
|
123
|
+
before_each
|
124
|
+
before_each_sequence.push('C')
|
125
|
+
end
|
126
|
+
|
127
|
+
after_each
|
128
|
+
after_each_sequence.push('C')
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should sequence befores in include order"
|
132
|
+
before_sequence.should.eql ['B', 'C', 'A']
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should sequence before_eachs in include order"
|
136
|
+
before_each_sequence.should.eql ['B', 'A', 'C', 'B', 'A', 'C']
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe 'after ordering'
|
141
|
+
it "should sequence afters in include order"
|
142
|
+
after_sequence.should.eql ['B', 'A', 'C']
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should sequence after_eachs in include order"
|
146
|
+
after_each_sequence.should.eql ['B', 'A', 'C', 'B', 'A', 'C']
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
shared_behaviors_for 'person'
|
152
|
+
it 'should have a name'
|
153
|
+
person.should.have_property 'name'
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
shared_behaviors_for 'administrator'
|
158
|
+
should_behave_like('person')
|
159
|
+
|
160
|
+
it 'should have access to all permissions'
|
161
|
+
person.may('edit pages').should.be_true
|
162
|
+
person.may('delete users').should.be_true
|
163
|
+
end
|
164
|
+
end
|
1
165
|
|
2
166
|
describe 'Shared Behaviors'
|
3
167
|
describe 'User'
|
4
168
|
before
|
5
169
|
User = function(name) { this.name = name }
|
6
|
-
|
170
|
+
person = new User('joe')
|
7
171
|
end
|
8
172
|
|
9
|
-
|
10
|
-
|
173
|
+
should_behave_like('person')
|
174
|
+
end
|
175
|
+
|
176
|
+
describe 'Administrator'
|
177
|
+
before
|
178
|
+
Admin = function(name) { this.name = name }
|
179
|
+
Admin.prototype.may = function(perm){ return true }
|
180
|
+
person = new Admin('tj')
|
11
181
|
end
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
it 'should have access to all permissions'
|
23
|
-
user.may('edit pages').should.be_true
|
24
|
-
user.may('delete users').should.be_true
|
25
|
-
end
|
26
|
-
|
27
|
-
describe 'Super Administrator'
|
28
|
-
should_behave_like('Administrator')
|
29
|
-
|
30
|
-
before
|
31
|
-
SuperAdmin = function(name) { this.name = name }
|
32
|
-
SuperAdmin.prototype.may = function(perm){ return true }
|
33
|
-
user = new SuperAdmin('tj')
|
34
|
-
end
|
35
|
-
end
|
182
|
+
|
183
|
+
should_behave_like('administrator')
|
184
|
+
end
|
185
|
+
|
186
|
+
describe 'Super Administrator'
|
187
|
+
before
|
188
|
+
SuperAdmin = function(name) { this.name = name }
|
189
|
+
SuperAdmin.prototype.may = function(perm){ return true }
|
190
|
+
SuperAdmin.prototype.canCreateUsers = function(){ return true }
|
191
|
+
person = new SuperAdmin('tj')
|
36
192
|
end
|
193
|
+
|
194
|
+
should_behave_like('administrator')
|
195
|
+
|
196
|
+
it "should be allowed to create users"
|
197
|
+
person.canCreateUsers().should.be_true
|
198
|
+
end
|
37
199
|
end
|
38
200
|
|
39
|
-
|
201
|
+
shared_behaviors_for 'User with toString()'
|
40
202
|
before
|
41
|
-
|
203
|
+
person = { toString : function() { return '<User tj>' }}
|
42
204
|
end
|
43
205
|
|
44
206
|
it 'should return <User NAME>'
|
45
|
-
|
207
|
+
person.toString().should.match(/\<User/)
|
46
208
|
end
|
47
209
|
end
|
48
210
|
|
49
211
|
describe 'Manager'
|
50
|
-
should_behave_like('
|
212
|
+
should_behave_like('person')
|
51
213
|
should_behave_like('User with toString()')
|
52
214
|
|
53
215
|
before
|
54
216
|
Manager = function(name) { this.name = name }
|
55
217
|
Manager.prototype.may = function(perm){ return perm == 'hire' || perm == 'fire' }
|
56
218
|
Manager.prototype.toString = function(){ return '<User ' + this.name + '>' }
|
57
|
-
|
219
|
+
person = new Manager('tj')
|
58
220
|
end
|
59
221
|
|
60
222
|
it 'should have access to hire or fire employees'
|
61
|
-
|
62
|
-
|
63
|
-
|
223
|
+
person.may('hire').should.be_true
|
224
|
+
person.may('fire').should.be_true
|
225
|
+
person.may('do anything else').should.be_false
|
64
226
|
end
|
65
227
|
end
|
66
228
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
it 'should
|
73
|
-
JSpec.
|
74
|
-
end
|
75
|
-
|
229
|
+
describe 'findLocalSharedBehavior'
|
230
|
+
it 'should find shared behavior by name'
|
231
|
+
JSpec.findLocalSharedBehavior('User with toString()').should.be_a JSpec.Suite
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'should return null when not found'
|
235
|
+
JSpec.findGlobalSharedBehavior('Rawr').should.be_null
|
236
|
+
end
|
237
|
+
|
238
|
+
describe 'nested'
|
239
|
+
it 'should find shared behavior by name when nested'
|
240
|
+
JSpec.findLocalSharedBehavior('User with toString()').should.be_a JSpec.Suite
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe 'findGlobalSharedBehavior'
|
246
|
+
it 'should find shared behavior by name'
|
247
|
+
JSpec.findGlobalSharedBehavior('person').should.be_a JSpec.Suite
|
248
|
+
end
|
249
|
+
|
76
250
|
it 'should return null when not found'
|
77
|
-
JSpec.
|
251
|
+
JSpec.findGlobalSharedBehavior('Rawr').should.be_null
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
describe 'findSharedBehavior'
|
256
|
+
shared_behaviors_for 'person'
|
257
|
+
it 'should not have name'
|
258
|
+
person.should.not.have_property 'name'
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
describe 'override behavior'
|
263
|
+
it 'should find local shared behavior before global'
|
264
|
+
JSpec.findSharedBehavior('person').body.toString().should.match(/should not have name/)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'should find shared global behavior by name'
|
269
|
+
JSpec.findGlobalSharedBehavior('animal').should.be_a JSpec.Suite
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'should return null when not found at either level'
|
273
|
+
JSpec.findGlobalSharedBehavior('Rawr').should.be_null
|
78
274
|
end
|
79
|
-
|
80
|
-
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
|
metadata
CHANGED
@@ -3,10 +3,10 @@ name: jspec
|
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
|
-
-
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version:
|
6
|
+
- 4
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 4.0.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- TJ Holowaychuk
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-03-
|
17
|
+
date: 2010-03-22 00:00:00 -07:00
|
18
18
|
default_executable: jspec
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|