mocha_rails 0.0.4 → 0.0.5

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.
@@ -1,6 +1,5 @@
1
1
  ;(function(){
2
2
 
3
-
4
3
  // CommonJS require()
5
4
 
6
5
  function require(p){
@@ -32,11 +31,11 @@ require.register = function (path, fn){
32
31
  require.relative = function (parent) {
33
32
  return function(p){
34
33
  if ('.' != p.charAt(0)) return require(p);
35
-
34
+
36
35
  var path = parent.split('/')
37
36
  , segs = p.split('/');
38
37
  path.pop();
39
-
38
+
40
39
  for (var i = 0; i < segs.length; i++) {
41
40
  var seg = segs[i];
42
41
  if ('..' == seg) path.pop();
@@ -52,12 +51,366 @@ require.register("browser/debug.js", function(module, exports, require){
52
51
 
53
52
  module.exports = function(type){
54
53
  return function(){
55
-
56
54
  }
57
55
  };
56
+
58
57
  }); // module: browser/debug.js
59
58
 
60
59
  require.register("browser/diff.js", function(module, exports, require){
60
+ /* See LICENSE file for terms of use */
61
+
62
+ /*
63
+ * Text diff implementation.
64
+ *
65
+ * This library supports the following APIS:
66
+ * JsDiff.diffChars: Character by character diff
67
+ * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace
68
+ * JsDiff.diffLines: Line based diff
69
+ *
70
+ * JsDiff.diffCss: Diff targeted at CSS content
71
+ *
72
+ * These methods are based on the implementation proposed in
73
+ * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986).
74
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
75
+ */
76
+ var JsDiff = (function() {
77
+ /*jshint maxparams: 5*/
78
+ function clonePath(path) {
79
+ return { newPos: path.newPos, components: path.components.slice(0) };
80
+ }
81
+ function removeEmpty(array) {
82
+ var ret = [];
83
+ for (var i = 0; i < array.length; i++) {
84
+ if (array[i]) {
85
+ ret.push(array[i]);
86
+ }
87
+ }
88
+ return ret;
89
+ }
90
+ function escapeHTML(s) {
91
+ var n = s;
92
+ n = n.replace(/&/g, '&amp;');
93
+ n = n.replace(/</g, '&lt;');
94
+ n = n.replace(/>/g, '&gt;');
95
+ n = n.replace(/"/g, '&quot;');
96
+
97
+ return n;
98
+ }
99
+
100
+ var Diff = function(ignoreWhitespace) {
101
+ this.ignoreWhitespace = ignoreWhitespace;
102
+ };
103
+ Diff.prototype = {
104
+ diff: function(oldString, newString) {
105
+ // Handle the identity case (this is due to unrolling editLength == 0
106
+ if (newString === oldString) {
107
+ return [{ value: newString }];
108
+ }
109
+ if (!newString) {
110
+ return [{ value: oldString, removed: true }];
111
+ }
112
+ if (!oldString) {
113
+ return [{ value: newString, added: true }];
114
+ }
115
+
116
+ newString = this.tokenize(newString);
117
+ oldString = this.tokenize(oldString);
118
+
119
+ var newLen = newString.length, oldLen = oldString.length;
120
+ var maxEditLength = newLen + oldLen;
121
+ var bestPath = [{ newPos: -1, components: [] }];
122
+
123
+ // Seed editLength = 0
124
+ var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);
125
+ if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) {
126
+ return bestPath[0].components;
127
+ }
128
+
129
+ for (var editLength = 1; editLength <= maxEditLength; editLength++) {
130
+ for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) {
131
+ var basePath;
132
+ var addPath = bestPath[diagonalPath-1],
133
+ removePath = bestPath[diagonalPath+1];
134
+ oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;
135
+ if (addPath) {
136
+ // No one else is going to attempt to use this value, clear it
137
+ bestPath[diagonalPath-1] = undefined;
138
+ }
139
+
140
+ var canAdd = addPath && addPath.newPos+1 < newLen;
141
+ var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;
142
+ if (!canAdd && !canRemove) {
143
+ bestPath[diagonalPath] = undefined;
144
+ continue;
145
+ }
146
+
147
+ // Select the diagonal that we want to branch from. We select the prior
148
+ // path whose position in the new string is the farthest from the origin
149
+ // and does not pass the bounds of the diff graph
150
+ if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {
151
+ basePath = clonePath(removePath);
152
+ this.pushComponent(basePath.components, oldString[oldPos], undefined, true);
153
+ } else {
154
+ basePath = clonePath(addPath);
155
+ basePath.newPos++;
156
+ this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined);
157
+ }
158
+
159
+ var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath);
160
+
161
+ if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) {
162
+ return basePath.components;
163
+ } else {
164
+ bestPath[diagonalPath] = basePath;
165
+ }
166
+ }
167
+ }
168
+ },
169
+
170
+ pushComponent: function(components, value, added, removed) {
171
+ var last = components[components.length-1];
172
+ if (last && last.added === added && last.removed === removed) {
173
+ // We need to clone here as the component clone operation is just
174
+ // as shallow array clone
175
+ components[components.length-1] =
176
+ {value: this.join(last.value, value), added: added, removed: removed };
177
+ } else {
178
+ components.push({value: value, added: added, removed: removed });
179
+ }
180
+ },
181
+ extractCommon: function(basePath, newString, oldString, diagonalPath) {
182
+ var newLen = newString.length,
183
+ oldLen = oldString.length,
184
+ newPos = basePath.newPos,
185
+ oldPos = newPos - diagonalPath;
186
+ while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) {
187
+ newPos++;
188
+ oldPos++;
189
+
190
+ this.pushComponent(basePath.components, newString[newPos], undefined, undefined);
191
+ }
192
+ basePath.newPos = newPos;
193
+ return oldPos;
194
+ },
195
+
196
+ equals: function(left, right) {
197
+ var reWhitespace = /\S/;
198
+ if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) {
199
+ return true;
200
+ } else {
201
+ return left === right;
202
+ }
203
+ },
204
+ join: function(left, right) {
205
+ return left + right;
206
+ },
207
+ tokenize: function(value) {
208
+ return value;
209
+ }
210
+ };
211
+
212
+ var CharDiff = new Diff();
213
+
214
+ var WordDiff = new Diff(true);
215
+ var WordWithSpaceDiff = new Diff();
216
+ WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) {
217
+ return removeEmpty(value.split(/(\s+|\b)/));
218
+ };
219
+
220
+ var CssDiff = new Diff(true);
221
+ CssDiff.tokenize = function(value) {
222
+ return removeEmpty(value.split(/([{}:;,]|\s+)/));
223
+ };
224
+
225
+ var LineDiff = new Diff();
226
+ LineDiff.tokenize = function(value) {
227
+ return value.split(/^/m);
228
+ };
229
+
230
+ return {
231
+ Diff: Diff,
232
+
233
+ diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); },
234
+ diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); },
235
+ diffWordsWithSpace: function(oldStr, newStr) { return WordWithSpaceDiff.diff(oldStr, newStr); },
236
+ diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); },
237
+
238
+ diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); },
239
+
240
+ createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) {
241
+ var ret = [];
242
+
243
+ ret.push('Index: ' + fileName);
244
+ ret.push('===================================================================');
245
+ ret.push('--- ' + fileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader));
246
+ ret.push('+++ ' + fileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader));
247
+
248
+ var diff = LineDiff.diff(oldStr, newStr);
249
+ if (!diff[diff.length-1].value) {
250
+ diff.pop(); // Remove trailing newline add
251
+ }
252
+ diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier
253
+
254
+ function contextLines(lines) {
255
+ return lines.map(function(entry) { return ' ' + entry; });
256
+ }
257
+ function eofNL(curRange, i, current) {
258
+ var last = diff[diff.length-2],
259
+ isLast = i === diff.length-2,
260
+ isLastOfType = i === diff.length-3 && (current.added !== last.added || current.removed !== last.removed);
261
+
262
+ // Figure out if this is the last line for the given file and missing NL
263
+ if (!/\n$/.test(current.value) && (isLast || isLastOfType)) {
264
+ curRange.push('\');
265
+ }
266
+ }
267
+
268
+ var oldRangeStart = 0, newRangeStart = 0, curRange = [],
269
+ oldLine = 1, newLine = 1;
270
+ for (var i = 0; i < diff.length; i++) {
271
+ var current = diff[i],
272
+ lines = current.lines || current.value.replace(/\n$/, '').split('\n');
273
+ current.lines = lines;
274
+
275
+ if (current.added || current.removed) {
276
+ if (!oldRangeStart) {
277
+ var prev = diff[i-1];
278
+ oldRangeStart = oldLine;
279
+ newRangeStart = newLine;
280
+
281
+ if (prev) {
282
+ curRange = contextLines(prev.lines.slice(-4));
283
+ oldRangeStart -= curRange.length;
284
+ newRangeStart -= curRange.length;
285
+ }
286
+ }
287
+ curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?'+':'-') + entry; }));
288
+ eofNL(curRange, i, current);
289
+
290
+ if (current.added) {
291
+ newLine += lines.length;
292
+ } else {
293
+ oldLine += lines.length;
294
+ }
295
+ } else {
296
+ if (oldRangeStart) {
297
+ // Close out any changes that have been output (or join overlapping)
298
+ if (lines.length <= 8 && i < diff.length-2) {
299
+ // Overlapping
300
+ curRange.push.apply(curRange, contextLines(lines));
301
+ } else {
302
+ // end the range and output
303
+ var contextSize = Math.min(lines.length, 4);
304
+ ret.push(
305
+ '@@ -' + oldRangeStart + ',' + (oldLine-oldRangeStart+contextSize)
306
+ + ' +' + newRangeStart + ',' + (newLine-newRangeStart+contextSize)
307
+ + ' @@');
308
+ ret.push.apply(ret, curRange);
309
+ ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));
310
+ if (lines.length <= 4) {
311
+ eofNL(ret, i, current);
312
+ }
313
+
314
+ oldRangeStart = 0; newRangeStart = 0; curRange = [];
315
+ }
316
+ }
317
+ oldLine += lines.length;
318
+ newLine += lines.length;
319
+ }
320
+ }
321
+
322
+ return ret.join('\n') + '\n';
323
+ },
324
+
325
+ applyPatch: function(oldStr, uniDiff) {
326
+ var diffstr = uniDiff.split('\n');
327
+ var diff = [];
328
+ var remEOFNL = false,
329
+ addEOFNL = false;
330
+
331
+ for (var i = (diffstr[0][0]==='I'?4:0); i < diffstr.length; i++) {
332
+ if(diffstr[i][0] === '@') {
333
+ var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/);
334
+ diff.unshift({
335
+ start:meh[3],
336
+ oldlength:meh[2],
337
+ oldlines:[],
338
+ newlength:meh[4],
339
+ newlines:[]
340
+ });
341
+ } else if(diffstr[i][0] === '+') {
342
+ diff[0].newlines.push(diffstr[i].substr(1));
343
+ } else if(diffstr[i][0] === '-') {
344
+ diff[0].oldlines.push(diffstr[i].substr(1));
345
+ } else if(diffstr[i][0] === ' ') {
346
+ diff[0].newlines.push(diffstr[i].substr(1));
347
+ diff[0].oldlines.push(diffstr[i].substr(1));
348
+ } else if(diffstr[i][0] === '\\') {
349
+ if (diffstr[i-1][0] === '+') {
350
+ remEOFNL = true;
351
+ } else if(diffstr[i-1][0] === '-') {
352
+ addEOFNL = true;
353
+ }
354
+ }
355
+ }
356
+
357
+ var str = oldStr.split('\n');
358
+ for (var i = diff.length - 1; i >= 0; i--) {
359
+ var d = diff[i];
360
+ for (var j = 0; j < d.oldlength; j++) {
361
+ if(str[d.start-1+j] !== d.oldlines[j]) {
362
+ return false;
363
+ }
364
+ }
365
+ Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newlines));
366
+ }
367
+
368
+ if (remEOFNL) {
369
+ while (!str[str.length-1]) {
370
+ str.pop();
371
+ }
372
+ } else if (addEOFNL) {
373
+ str.push('');
374
+ }
375
+ return str.join('\n');
376
+ },
377
+
378
+ convertChangesToXML: function(changes){
379
+ var ret = [];
380
+ for ( var i = 0; i < changes.length; i++) {
381
+ var change = changes[i];
382
+ if (change.added) {
383
+ ret.push('<ins>');
384
+ } else if (change.removed) {
385
+ ret.push('<del>');
386
+ }
387
+
388
+ ret.push(escapeHTML(change.value));
389
+
390
+ if (change.added) {
391
+ ret.push('</ins>');
392
+ } else if (change.removed) {
393
+ ret.push('</del>');
394
+ }
395
+ }
396
+ return ret.join('');
397
+ },
398
+
399
+ // See: http://code.google.com/p/google-diff-match-patch/wiki/API
400
+ convertChangesToDMP: function(changes){
401
+ var ret = [], change;
402
+ for ( var i = 0; i < changes.length; i++) {
403
+ change = changes[i];
404
+ ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]);
405
+ }
406
+ return ret;
407
+ }
408
+ };
409
+ })();
410
+
411
+ if (typeof module !== 'undefined') {
412
+ module.exports = JsDiff;
413
+ }
61
414
 
62
415
  }); // module: browser/diff.js
63
416
 
@@ -80,7 +433,7 @@ function isArray(obj) {
80
433
  /**
81
434
  * Event emitter constructor.
82
435
  *
83
- * @api public.
436
+ * @api public
84
437
  */
85
438
 
86
439
  function EventEmitter(){};
@@ -188,7 +541,7 @@ EventEmitter.prototype.removeAllListeners = function (name) {
188
541
  /**
189
542
  * Gets all listeners for a certain event.
190
543
  *
191
- * @api publci
544
+ * @api public
192
545
  */
193
546
 
194
547
  EventEmitter.prototype.listeners = function (name) {
@@ -386,8 +739,14 @@ exports.isatty = function(){
386
739
  };
387
740
 
388
741
  exports.getWindowSize = function(){
389
- return [window.innerHeight, window.innerWidth];
742
+ if ('innerHeight' in global) {
743
+ return [global.innerHeight, global.innerWidth];
744
+ } else {
745
+ // In a Web Worker, the DOM Window is not available.
746
+ return [640, 480];
747
+ }
390
748
  };
749
+
391
750
  }); // module: browser/tty.js
392
751
 
393
752
  require.register("context.js", function(module, exports, require){
@@ -407,15 +766,16 @@ module.exports = Context;
407
766
  function Context(){}
408
767
 
409
768
  /**
410
- * Set the context `Test` to `test`.
769
+ * Set or get the context `Runnable` to `runnable`.
411
770
  *
412
- * @param {Test} test
771
+ * @param {Runnable} runnable
413
772
  * @return {Context}
414
773
  * @api private
415
774
  */
416
775
 
417
- Context.prototype.test = function(test){
418
- this._test = test;
776
+ Context.prototype.runnable = function(runnable){
777
+ if (0 == arguments.length) return this._runnable;
778
+ this.test = this._runnable = runnable;
419
779
  return this;
420
780
  };
421
781
 
@@ -428,12 +788,25 @@ Context.prototype.test = function(test){
428
788
  */
429
789
 
430
790
  Context.prototype.timeout = function(ms){
431
- this._test.timeout(ms);
791
+ this.runnable().timeout(ms);
792
+ return this;
793
+ };
794
+
795
+ /**
796
+ * Set test slowness threshold `ms`.
797
+ *
798
+ * @param {Number} ms
799
+ * @return {Context} self
800
+ * @api private
801
+ */
802
+
803
+ Context.prototype.slow = function(ms){
804
+ this.runnable().slow(ms);
432
805
  return this;
433
806
  };
434
807
 
435
808
  /**
436
- * Inspect the context void of `._test`.
809
+ * Inspect the context void of `._runnable`.
437
810
  *
438
811
  * @return {String}
439
812
  * @api private
@@ -441,9 +814,9 @@ Context.prototype.timeout = function(ms){
441
814
 
442
815
  Context.prototype.inspect = function(){
443
816
  return JSON.stringify(this, function(key, val){
444
- return '_test' == key
445
- ? undefined
446
- : val;
817
+ if ('_runnable' == key) return;
818
+ if ('test' == key) return;
819
+ return val;
447
820
  }, 2);
448
821
  };
449
822
 
@@ -480,10 +853,30 @@ function Hook(title, fn) {
480
853
  * Inherit from `Runnable.prototype`.
481
854
  */
482
855
 
483
- Hook.prototype = new Runnable;
856
+ function F(){};
857
+ F.prototype = Runnable.prototype;
858
+ Hook.prototype = new F;
484
859
  Hook.prototype.constructor = Hook;
485
860
 
486
861
 
862
+ /**
863
+ * Get or set the test `err`.
864
+ *
865
+ * @param {Error} err
866
+ * @return {Error}
867
+ * @api public
868
+ */
869
+
870
+ Hook.prototype.error = function(err){
871
+ if (0 == arguments.length) {
872
+ var err = this._error;
873
+ this._error = null;
874
+ return err;
875
+ }
876
+
877
+ this._error = err;
878
+ };
879
+
487
880
  }); // module: hook.js
488
881
 
489
882
  require.register("interfaces/bdd.js", function(module, exports, require){
@@ -493,11 +886,12 @@ require.register("interfaces/bdd.js", function(module, exports, require){
493
886
  */
494
887
 
495
888
  var Suite = require('../suite')
496
- , Test = require('../test');
889
+ , Test = require('../test')
890
+ , utils = require('../utils');
497
891
 
498
892
  /**
499
893
  * BDD-style interface:
500
- *
894
+ *
501
895
  * describe('Array', function(){
502
896
  * describe('#indexOf()', function(){
503
897
  * it('should return -1 when not present', function(){
@@ -509,18 +903,13 @@ var Suite = require('../suite')
509
903
  * });
510
904
  * });
511
905
  * });
512
- *
906
+ *
513
907
  */
514
908
 
515
909
  module.exports = function(suite){
516
910
  var suites = [suite];
517
911
 
518
- suite.on('pre-require', function(context){
519
-
520
- // noop variants
521
-
522
- context.xdescribe = function(){};
523
- context.xit = function(){};
912
+ suite.on('pre-require', function(context, file, mocha){
524
913
 
525
914
  /**
526
915
  * Execute before running tests.
@@ -559,12 +948,36 @@ module.exports = function(suite){
559
948
  * and callback `fn` containing nested suites
560
949
  * and/or tests.
561
950
  */
562
-
563
- context.describe = function(title, fn){
951
+
952
+ context.describe = context.context = function(title, fn){
564
953
  var suite = Suite.create(suites[0], title);
565
954
  suites.unshift(suite);
566
- fn();
955
+ fn.call(suite);
567
956
  suites.shift();
957
+ return suite;
958
+ };
959
+
960
+ /**
961
+ * Pending describe.
962
+ */
963
+
964
+ context.xdescribe =
965
+ context.xcontext =
966
+ context.describe.skip = function(title, fn){
967
+ var suite = Suite.create(suites[0], title);
968
+ suite.pending = true;
969
+ suites.unshift(suite);
970
+ fn.call(suite);
971
+ suites.shift();
972
+ };
973
+
974
+ /**
975
+ * Exclusive suite.
976
+ */
977
+
978
+ context.describe.only = function(title, fn){
979
+ var suite = context.describe(title, fn);
980
+ mocha.grep(suite.fullTitle());
568
981
  };
569
982
 
570
983
  /**
@@ -573,8 +986,32 @@ module.exports = function(suite){
573
986
  * acting as a thunk.
574
987
  */
575
988
 
576
- context.it = function(title, fn){
577
- suites[0].addTest(new Test(title, fn));
989
+ context.it = context.specify = function(title, fn){
990
+ var suite = suites[0];
991
+ if (suite.pending) var fn = null;
992
+ var test = new Test(title, fn);
993
+ suite.addTest(test);
994
+ return test;
995
+ };
996
+
997
+ /**
998
+ * Exclusive test-case.
999
+ */
1000
+
1001
+ context.it.only = function(title, fn){
1002
+ var test = context.it(title, fn);
1003
+ var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
1004
+ mocha.grep(new RegExp(reString));
1005
+ };
1006
+
1007
+ /**
1008
+ * Pending test case.
1009
+ */
1010
+
1011
+ context.xit =
1012
+ context.xspecify =
1013
+ context.it.skip = function(title){
1014
+ context.it(title);
578
1015
  };
579
1016
  });
580
1017
  };
@@ -592,19 +1029,19 @@ var Suite = require('../suite')
592
1029
 
593
1030
  /**
594
1031
  * TDD-style interface:
595
- *
1032
+ *
596
1033
  * exports.Array = {
597
1034
  * '#indexOf()': {
598
1035
  * 'should return -1 when the value is not present': function(){
599
- *
1036
+ *
600
1037
  * },
601
1038
  *
602
1039
  * 'should return the correct index when the value is present': function(){
603
- *
1040
+ *
604
1041
  * }
605
1042
  * }
606
1043
  * };
607
- *
1044
+ *
608
1045
  */
609
1046
 
610
1047
  module.exports = function(suite){
@@ -642,6 +1079,7 @@ module.exports = function(suite){
642
1079
  }
643
1080
  }
644
1081
  };
1082
+
645
1083
  }); // module: interfaces/exports.js
646
1084
 
647
1085
  require.register("interfaces/index.js", function(module, exports, require){
@@ -660,37 +1098,38 @@ require.register("interfaces/qunit.js", function(module, exports, require){
660
1098
  */
661
1099
 
662
1100
  var Suite = require('../suite')
663
- , Test = require('../test');
1101
+ , Test = require('../test')
1102
+ , utils = require('../utils');
664
1103
 
665
1104
  /**
666
1105
  * QUnit-style interface:
667
- *
1106
+ *
668
1107
  * suite('Array');
669
- *
1108
+ *
670
1109
  * test('#length', function(){
671
1110
  * var arr = [1,2,3];
672
1111
  * ok(arr.length == 3);
673
1112
  * });
674
- *
1113
+ *
675
1114
  * test('#indexOf()', function(){
676
1115
  * var arr = [1,2,3];
677
1116
  * ok(arr.indexOf(1) == 0);
678
1117
  * ok(arr.indexOf(2) == 1);
679
1118
  * ok(arr.indexOf(3) == 2);
680
1119
  * });
681
- *
1120
+ *
682
1121
  * suite('String');
683
- *
1122
+ *
684
1123
  * test('#length', function(){
685
1124
  * ok('foo'.length == 3);
686
1125
  * });
687
- *
1126
+ *
688
1127
  */
689
1128
 
690
1129
  module.exports = function(suite){
691
1130
  var suites = [suite];
692
1131
 
693
- suite.on('pre-require', function(context){
1132
+ suite.on('pre-require', function(context, file, mocha){
694
1133
 
695
1134
  /**
696
1135
  * Execute before running tests.
@@ -727,11 +1166,21 @@ module.exports = function(suite){
727
1166
  /**
728
1167
  * Describe a "suite" with the given `title`.
729
1168
  */
730
-
1169
+
731
1170
  context.suite = function(title){
732
1171
  if (suites.length > 1) suites.shift();
733
1172
  var suite = Suite.create(suites[0], title);
734
1173
  suites.unshift(suite);
1174
+ return suite;
1175
+ };
1176
+
1177
+ /**
1178
+ * Exclusive test-case.
1179
+ */
1180
+
1181
+ context.suite.only = function(title, fn){
1182
+ var suite = context.suite(title, fn);
1183
+ mocha.grep(suite.fullTitle());
735
1184
  };
736
1185
 
737
1186
  /**
@@ -741,7 +1190,27 @@ module.exports = function(suite){
741
1190
  */
742
1191
 
743
1192
  context.test = function(title, fn){
744
- suites[0].addTest(new Test(title, fn));
1193
+ var test = new Test(title, fn);
1194
+ suites[0].addTest(test);
1195
+ return test;
1196
+ };
1197
+
1198
+ /**
1199
+ * Exclusive test-case.
1200
+ */
1201
+
1202
+ context.test.only = function(title, fn){
1203
+ var test = context.test(title, fn);
1204
+ var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
1205
+ mocha.grep(new RegExp(reString));
1206
+ };
1207
+
1208
+ /**
1209
+ * Pending test case.
1210
+ */
1211
+
1212
+ context.test.skip = function(title){
1213
+ context.test(title);
745
1214
  };
746
1215
  });
747
1216
  };
@@ -755,7 +1224,8 @@ require.register("interfaces/tdd.js", function(module, exports, require){
755
1224
  */
756
1225
 
757
1226
  var Suite = require('../suite')
758
- , Test = require('../test');
1227
+ , Test = require('../test')
1228
+ , utils = require('../utils');;
759
1229
 
760
1230
  /**
761
1231
  * TDD-style interface:
@@ -765,7 +1235,7 @@ var Suite = require('../suite')
765
1235
  * suiteSetup(function(){
766
1236
  *
767
1237
  * });
768
- *
1238
+ *
769
1239
  * test('should return -1 when not present', function(){
770
1240
  *
771
1241
  * });
@@ -785,7 +1255,7 @@ var Suite = require('../suite')
785
1255
  module.exports = function(suite){
786
1256
  var suites = [suite];
787
1257
 
788
- suite.on('pre-require', function(context){
1258
+ suite.on('pre-require', function(context, file, mocha){
789
1259
 
790
1260
  /**
791
1261
  * Execute before each test case.
@@ -828,10 +1298,31 @@ module.exports = function(suite){
828
1298
  context.suite = function(title, fn){
829
1299
  var suite = Suite.create(suites[0], title);
830
1300
  suites.unshift(suite);
831
- fn();
1301
+ fn.call(suite);
1302
+ suites.shift();
1303
+ return suite;
1304
+ };
1305
+
1306
+ /**
1307
+ * Pending suite.
1308
+ */
1309
+ context.suite.skip = function(title, fn) {
1310
+ var suite = Suite.create(suites[0], title);
1311
+ suite.pending = true;
1312
+ suites.unshift(suite);
1313
+ fn.call(suite);
832
1314
  suites.shift();
833
1315
  };
834
1316
 
1317
+ /**
1318
+ * Exclusive test-case.
1319
+ */
1320
+
1321
+ context.suite.only = function(title, fn){
1322
+ var suite = context.suite(title, fn);
1323
+ mocha.grep(suite.fullTitle());
1324
+ };
1325
+
835
1326
  /**
836
1327
  * Describe a specification or test-case
837
1328
  * with the given `title` and callback `fn`
@@ -839,7 +1330,29 @@ module.exports = function(suite){
839
1330
  */
840
1331
 
841
1332
  context.test = function(title, fn){
842
- suites[0].addTest(new Test(title, fn));
1333
+ var suite = suites[0];
1334
+ if (suite.pending) var fn = null;
1335
+ var test = new Test(title, fn);
1336
+ suite.addTest(test);
1337
+ return test;
1338
+ };
1339
+
1340
+ /**
1341
+ * Exclusive test-case.
1342
+ */
1343
+
1344
+ context.test.only = function(title, fn){
1345
+ var test = context.test(title, fn);
1346
+ var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
1347
+ mocha.grep(new RegExp(reString));
1348
+ };
1349
+
1350
+ /**
1351
+ * Pending test case.
1352
+ */
1353
+
1354
+ context.test.skip = function(title){
1355
+ context.test(title);
843
1356
  };
844
1357
  });
845
1358
  };
@@ -847,7 +1360,6 @@ module.exports = function(suite){
847
1360
  }); // module: interfaces/tdd.js
848
1361
 
849
1362
  require.register("mocha.js", function(module, exports, require){
850
-
851
1363
  /*!
852
1364
  * mocha
853
1365
  * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
@@ -858,7 +1370,8 @@ require.register("mocha.js", function(module, exports, require){
858
1370
  * Module dependencies.
859
1371
  */
860
1372
 
861
- var path = require('browser/path');
1373
+ var path = require('browser/path')
1374
+ , utils = require('./utils');
862
1375
 
863
1376
  /**
864
1377
  * Expose `Mocha`.
@@ -866,17 +1379,11 @@ var path = require('browser/path');
866
1379
 
867
1380
  exports = module.exports = Mocha;
868
1381
 
869
- /**
870
- * Library version.
871
- */
872
-
873
- exports.version = '1.0.0';
874
-
875
1382
  /**
876
1383
  * Expose internals.
877
1384
  */
878
1385
 
879
- exports.utils = require('./utils');
1386
+ exports.utils = utils;
880
1387
  exports.interfaces = require('./interfaces');
881
1388
  exports.reporters = require('./reporters');
882
1389
  exports.Runnable = require('./runnable');
@@ -907,7 +1414,10 @@ function image(name) {
907
1414
  * - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
908
1415
  * - `globals` array of accepted globals
909
1416
  * - `timeout` timeout in milliseconds
1417
+ * - `bail` bail on the first test failure
1418
+ * - `slow` milliseconds to wait before considering a test slow
910
1419
  * - `ignoreLeaks` ignore global leaks
1420
+ * - `grep` string or regexp to filter tests with
911
1421
  *
912
1422
  * @param {Object} options
913
1423
  * @api public
@@ -917,12 +1427,28 @@ function Mocha(options) {
917
1427
  options = options || {};
918
1428
  this.files = [];
919
1429
  this.options = options;
1430
+ this.grep(options.grep);
920
1431
  this.suite = new exports.Suite('', new exports.Context);
921
1432
  this.ui(options.ui);
1433
+ this.bail(options.bail);
922
1434
  this.reporter(options.reporter);
923
- if (options.timeout) this.suite.timeout(options.timeout);
1435
+ if (null != options.timeout) this.timeout(options.timeout);
1436
+ if (options.slow) this.slow(options.slow);
924
1437
  }
925
1438
 
1439
+ /**
1440
+ * Enable or disable bailing on the first failure.
1441
+ *
1442
+ * @param {Boolean} [bail]
1443
+ * @api public
1444
+ */
1445
+
1446
+ Mocha.prototype.bail = function(bail){
1447
+ if (0 == arguments.length) bail = true;
1448
+ this.suite.bail(bail);
1449
+ return this;
1450
+ };
1451
+
926
1452
  /**
927
1453
  * Add test `file`.
928
1454
  *
@@ -936,16 +1462,24 @@ Mocha.prototype.addFile = function(file){
936
1462
  };
937
1463
 
938
1464
  /**
939
- * Set reporter to `name`, defaults to "dot".
1465
+ * Set reporter to `reporter`, defaults to "dot".
940
1466
  *
941
- * @param {String} name
1467
+ * @param {String|Function} reporter name or constructor
942
1468
  * @api public
943
1469
  */
944
1470
 
945
- Mocha.prototype.reporter = function(name){
946
- name = name || 'dot';
947
- this._reporter = require('./reporters/' + name);
948
- if (!this._reporter) throw new Error('invalid reporter "' + name + '"');
1471
+ Mocha.prototype.reporter = function(reporter){
1472
+ if ('function' == typeof reporter) {
1473
+ this._reporter = reporter;
1474
+ } else {
1475
+ reporter = reporter || 'dot';
1476
+ try {
1477
+ this._reporter = require('./reporters/' + reporter);
1478
+ } catch (err) {
1479
+ this._reporter = require(reporter);
1480
+ }
1481
+ if (!this._reporter) throw new Error('invalid reporter "' + reporter + '"');
1482
+ }
949
1483
  return this;
950
1484
  };
951
1485
 
@@ -970,13 +1504,16 @@ Mocha.prototype.ui = function(name){
970
1504
  * @api private
971
1505
  */
972
1506
 
973
- Mocha.prototype.loadFiles = function(){
1507
+ Mocha.prototype.loadFiles = function(fn){
1508
+ var self = this;
974
1509
  var suite = this.suite;
1510
+ var pending = this.files.length;
975
1511
  this.files.forEach(function(file){
976
1512
  file = path.resolve(file);
977
- suite.emit('pre-require', global, file);
978
- suite.emit('require', require(file), file);
979
- suite.emit('post-require', global, file);
1513
+ suite.emit('pre-require', global, file, self);
1514
+ suite.emit('require', require(file), file, self);
1515
+ suite.emit('post-require', global, file, self);
1516
+ --pending || (fn && fn());
980
1517
  });
981
1518
  };
982
1519
 
@@ -986,23 +1523,139 @@ Mocha.prototype.loadFiles = function(){
986
1523
  * @api private
987
1524
  */
988
1525
 
989
- Mocha.prototype.growl = function(runner, reporter) {
1526
+ Mocha.prototype._growl = function(runner, reporter) {
990
1527
  var notify = require('growl');
991
1528
 
992
1529
  runner.on('end', function(){
993
1530
  var stats = reporter.stats;
994
1531
  if (stats.failures) {
995
1532
  var msg = stats.failures + ' of ' + runner.total + ' tests failed';
996
- notify(msg, { title: 'Failed', image: image('fail') });
1533
+ notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });
997
1534
  } else {
998
1535
  notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
999
- title: 'Passed'
1000
- , image: image('pass')
1536
+ name: 'mocha'
1537
+ , title: 'Passed'
1538
+ , image: image('ok')
1001
1539
  });
1002
1540
  }
1003
1541
  });
1004
1542
  };
1005
1543
 
1544
+ /**
1545
+ * Add regexp to grep, if `re` is a string it is escaped.
1546
+ *
1547
+ * @param {RegExp|String} re
1548
+ * @return {Mocha}
1549
+ * @api public
1550
+ */
1551
+
1552
+ Mocha.prototype.grep = function(re){
1553
+ this.options.grep = 'string' == typeof re
1554
+ ? new RegExp(utils.escapeRegexp(re))
1555
+ : re;
1556
+ return this;
1557
+ };
1558
+
1559
+ /**
1560
+ * Invert `.grep()` matches.
1561
+ *
1562
+ * @return {Mocha}
1563
+ * @api public
1564
+ */
1565
+
1566
+ Mocha.prototype.invert = function(){
1567
+ this.options.invert = true;
1568
+ return this;
1569
+ };
1570
+
1571
+ /**
1572
+ * Ignore global leaks.
1573
+ *
1574
+ * @param {Boolean} ignore
1575
+ * @return {Mocha}
1576
+ * @api public
1577
+ */
1578
+
1579
+ Mocha.prototype.ignoreLeaks = function(ignore){
1580
+ this.options.ignoreLeaks = !!ignore;
1581
+ return this;
1582
+ };
1583
+
1584
+ /**
1585
+ * Enable global leak checking.
1586
+ *
1587
+ * @return {Mocha}
1588
+ * @api public
1589
+ */
1590
+
1591
+ Mocha.prototype.checkLeaks = function(){
1592
+ this.options.ignoreLeaks = false;
1593
+ return this;
1594
+ };
1595
+
1596
+ /**
1597
+ * Enable growl support.
1598
+ *
1599
+ * @return {Mocha}
1600
+ * @api public
1601
+ */
1602
+
1603
+ Mocha.prototype.growl = function(){
1604
+ this.options.growl = true;
1605
+ return this;
1606
+ };
1607
+
1608
+ /**
1609
+ * Ignore `globals` array or string.
1610
+ *
1611
+ * @param {Array|String} globals
1612
+ * @return {Mocha}
1613
+ * @api public
1614
+ */
1615
+
1616
+ Mocha.prototype.globals = function(globals){
1617
+ this.options.globals = (this.options.globals || []).concat(globals);
1618
+ return this;
1619
+ };
1620
+
1621
+ /**
1622
+ * Set the timeout in milliseconds.
1623
+ *
1624
+ * @param {Number} timeout
1625
+ * @return {Mocha}
1626
+ * @api public
1627
+ */
1628
+
1629
+ Mocha.prototype.timeout = function(timeout){
1630
+ this.suite.timeout(timeout);
1631
+ return this;
1632
+ };
1633
+
1634
+ /**
1635
+ * Set slowness threshold in milliseconds.
1636
+ *
1637
+ * @param {Number} slow
1638
+ * @return {Mocha}
1639
+ * @api public
1640
+ */
1641
+
1642
+ Mocha.prototype.slow = function(slow){
1643
+ this.suite.slow(slow);
1644
+ return this;
1645
+ };
1646
+
1647
+ /**
1648
+ * Makes all tests async (accepting a callback)
1649
+ *
1650
+ * @return {Mocha}
1651
+ * @api public
1652
+ */
1653
+
1654
+ Mocha.prototype.asyncOnly = function(){
1655
+ this.options.asyncOnly = true;
1656
+ return this;
1657
+ };
1658
+
1006
1659
  /**
1007
1660
  * Run tests and invoke `fn()` when complete.
1008
1661
  *
@@ -1012,20 +1665,136 @@ Mocha.prototype.growl = function(runner, reporter) {
1012
1665
  */
1013
1666
 
1014
1667
  Mocha.prototype.run = function(fn){
1015
- this.loadFiles();
1668
+ if (this.files.length) this.loadFiles();
1016
1669
  var suite = this.suite;
1017
1670
  var options = this.options;
1018
1671
  var runner = new exports.Runner(suite);
1019
1672
  var reporter = new this._reporter(runner);
1020
- runner.ignoreLeaks = options.ignoreLeaks;
1021
- if (options.grep) runner.grep(options.grep);
1673
+ runner.ignoreLeaks = false !== options.ignoreLeaks;
1674
+ runner.asyncOnly = options.asyncOnly;
1675
+ if (options.grep) runner.grep(options.grep, options.invert);
1022
1676
  if (options.globals) runner.globals(options.globals);
1023
- if (options.growl) this.growl(runner, reporter);
1677
+ if (options.growl) this._growl(runner, reporter);
1024
1678
  return runner.run(fn);
1025
1679
  };
1026
1680
 
1027
1681
  }); // module: mocha.js
1028
1682
 
1683
+ require.register("ms.js", function(module, exports, require){
1684
+ /**
1685
+ * Helpers.
1686
+ */
1687
+
1688
+ var s = 1000;
1689
+ var m = s * 60;
1690
+ var h = m * 60;
1691
+ var d = h * 24;
1692
+ var y = d * 365.25;
1693
+
1694
+ /**
1695
+ * Parse or format the given `val`.
1696
+ *
1697
+ * Options:
1698
+ *
1699
+ * - `long` verbose formatting [false]
1700
+ *
1701
+ * @param {String|Number} val
1702
+ * @param {Object} options
1703
+ * @return {String|Number}
1704
+ * @api public
1705
+ */
1706
+
1707
+ module.exports = function(val, options){
1708
+ options = options || {};
1709
+ if ('string' == typeof val) return parse(val);
1710
+ return options.long
1711
+ ? long(val)
1712
+ : short(val);
1713
+ };
1714
+
1715
+ /**
1716
+ * Parse the given `str` and return milliseconds.
1717
+ *
1718
+ * @param {String} str
1719
+ * @return {Number}
1720
+ * @api private
1721
+ */
1722
+
1723
+ function parse(str) {
1724
+ var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);
1725
+ if (!match) return;
1726
+ var n = parseFloat(match[1]);
1727
+ var type = (match[2] || 'ms').toLowerCase();
1728
+ switch (type) {
1729
+ case 'years':
1730
+ case 'year':
1731
+ case 'y':
1732
+ return n * y;
1733
+ case 'days':
1734
+ case 'day':
1735
+ case 'd':
1736
+ return n * d;
1737
+ case 'hours':
1738
+ case 'hour':
1739
+ case 'h':
1740
+ return n * h;
1741
+ case 'minutes':
1742
+ case 'minute':
1743
+ case 'm':
1744
+ return n * m;
1745
+ case 'seconds':
1746
+ case 'second':
1747
+ case 's':
1748
+ return n * s;
1749
+ case 'ms':
1750
+ return n;
1751
+ }
1752
+ }
1753
+
1754
+ /**
1755
+ * Short format for `ms`.
1756
+ *
1757
+ * @param {Number} ms
1758
+ * @return {String}
1759
+ * @api private
1760
+ */
1761
+
1762
+ function short(ms) {
1763
+ if (ms >= d) return Math.round(ms / d) + 'd';
1764
+ if (ms >= h) return Math.round(ms / h) + 'h';
1765
+ if (ms >= m) return Math.round(ms / m) + 'm';
1766
+ if (ms >= s) return Math.round(ms / s) + 's';
1767
+ return ms + 'ms';
1768
+ }
1769
+
1770
+ /**
1771
+ * Long format for `ms`.
1772
+ *
1773
+ * @param {Number} ms
1774
+ * @return {String}
1775
+ * @api private
1776
+ */
1777
+
1778
+ function long(ms) {
1779
+ return plural(ms, d, 'day')
1780
+ || plural(ms, h, 'hour')
1781
+ || plural(ms, m, 'minute')
1782
+ || plural(ms, s, 'second')
1783
+ || ms + ' ms';
1784
+ }
1785
+
1786
+ /**
1787
+ * Pluralization helper.
1788
+ */
1789
+
1790
+ function plural(ms, n, name) {
1791
+ if (ms < n) return;
1792
+ if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
1793
+ return Math.ceil(ms / n) + ' ' + name + 's';
1794
+ }
1795
+
1796
+ }); // module: ms.js
1797
+
1029
1798
  require.register("reporters/base.js", function(module, exports, require){
1030
1799
 
1031
1800
  /**
@@ -1033,7 +1802,18 @@ require.register("reporters/base.js", function(module, exports, require){
1033
1802
  */
1034
1803
 
1035
1804
  var tty = require('browser/tty')
1036
- , diff = require('browser/diff');
1805
+ , diff = require('browser/diff')
1806
+ , ms = require('../ms');
1807
+
1808
+ /**
1809
+ * Save timer references to avoid Sinon interfering (see GH-237).
1810
+ */
1811
+
1812
+ var Date = global.Date
1813
+ , setTimeout = global.setTimeout
1814
+ , setInterval = global.setInterval
1815
+ , clearTimeout = global.clearTimeout
1816
+ , clearInterval = global.clearInterval;
1037
1817
 
1038
1818
  /**
1039
1819
  * Check if both stdio streams are associated with a tty.
@@ -1053,6 +1833,12 @@ exports = module.exports = Base;
1053
1833
 
1054
1834
  exports.useColors = isatty;
1055
1835
 
1836
+ /**
1837
+ * Inline diffs instead of +/-
1838
+ */
1839
+
1840
+ exports.inlineDiffs = false;
1841
+
1056
1842
  /**
1057
1843
  * Default color map.
1058
1844
  */
@@ -1079,6 +1865,23 @@ exports.colors = {
1079
1865
  , 'diff removed': 41
1080
1866
  };
1081
1867
 
1868
+ /**
1869
+ * Default symbol map.
1870
+ */
1871
+
1872
+ exports.symbols = {
1873
+ ok: '✓',
1874
+ err: '✖',
1875
+ dot: '․'
1876
+ };
1877
+
1878
+ // With node.js on Windows: use symbols available in terminal default fonts
1879
+ if ('win32' == process.platform) {
1880
+ exports.symbols.ok = '\u221A';
1881
+ exports.symbols.err = '\u00D7';
1882
+ exports.symbols.dot = '.';
1883
+ }
1884
+
1082
1885
  /**
1083
1886
  * Color `str` with the given `type`,
1084
1887
  * allowing colors to be disabled,
@@ -1093,7 +1896,7 @@ exports.colors = {
1093
1896
 
1094
1897
  var color = exports.color = function(type, str) {
1095
1898
  if (!exports.useColors) return str;
1096
- return '\033[' + exports.colors[type] + 'm' + str + '\033[0m';
1899
+ return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
1097
1900
  };
1098
1901
 
1099
1902
  /**
@@ -1116,19 +1919,19 @@ exports.window = {
1116
1919
 
1117
1920
  exports.cursor = {
1118
1921
  hide: function(){
1119
- process.stdout.write('\033[?25l');
1922
+ process.stdout.write('\u001b[?25l');
1120
1923
  },
1121
1924
 
1122
1925
  show: function(){
1123
- process.stdout.write('\033[?25h');
1926
+ process.stdout.write('\u001b[?25h');
1124
1927
  },
1125
1928
 
1126
1929
  deleteLine: function(){
1127
- process.stdout.write('\033[2K');
1930
+ process.stdout.write('\u001b[2K');
1128
1931
  },
1129
1932
 
1130
1933
  beginningOfLine: function(){
1131
- process.stdout.write('\033[0G');
1934
+ process.stdout.write('\u001b[0G');
1132
1935
  },
1133
1936
 
1134
1937
  CR: function(){
@@ -1137,13 +1940,6 @@ exports.cursor = {
1137
1940
  }
1138
1941
  };
1139
1942
 
1140
- /**
1141
- * A test is considered slow if it
1142
- * exceeds the following value in milliseconds.
1143
- */
1144
-
1145
- exports.slow = 75;
1146
-
1147
1943
  /**
1148
1944
  * Outut the given `failures` as a list.
1149
1945
  *
@@ -1166,38 +1962,29 @@ exports.list = function(failures){
1166
1962
  , index = stack.indexOf(message) + message.length
1167
1963
  , msg = stack.slice(0, index)
1168
1964
  , actual = err.actual
1169
- , expected = err.expected;
1965
+ , expected = err.expected
1966
+ , escape = true;
1967
+
1968
+ // uncaught
1969
+ if (err.uncaught) {
1970
+ msg = 'Uncaught ' + msg;
1971
+ }
1972
+
1973
+ // explicitly show diff
1974
+ if (err.showDiff && sameType(actual, expected)) {
1975
+ escape = false;
1976
+ err.actual = actual = stringify(actual);
1977
+ err.expected = expected = stringify(expected);
1978
+ }
1170
1979
 
1171
1980
  // actual / expected diff
1172
1981
  if ('string' == typeof actual && 'string' == typeof expected) {
1173
- var len = Math.max(actual.length, expected.length);
1174
-
1175
- if (len < 20) msg = errorDiff(err, 'Chars');
1176
- else msg = errorDiff(err, 'Words');
1177
-
1178
- // linenos
1179
- var lines = msg.split('\n');
1180
- if (lines.length > 4) {
1181
- var width = String(lines.length).length;
1182
- msg = lines.map(function(str, i){
1183
- return pad(++i, width) + ' |' + ' ' + str;
1184
- }).join('\n');
1982
+ fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n');
1983
+ if (exports.inlineDiffs) {
1984
+ msg = inlineDiff(err, escape);
1985
+ } else {
1986
+ msg = unifiedDiff(err, escape);
1185
1987
  }
1186
-
1187
- // legend
1188
- msg = '\n'
1189
- + color('diff removed', 'actual')
1190
- + ' '
1191
- + color('diff added', 'expected')
1192
- + '\n\n'
1193
- + msg
1194
- + '\n';
1195
-
1196
- // indent
1197
- msg = msg.replace(/^/gm, ' ');
1198
-
1199
- fmt = color('error title', ' %s) %s:\n%s')
1200
- + color('error stack', '\n%s\n');
1201
1988
  }
1202
1989
 
1203
1990
  // indent stack trace without msg
@@ -1222,12 +2009,14 @@ exports.list = function(failures){
1222
2009
 
1223
2010
  function Base(runner) {
1224
2011
  var self = this
1225
- , stats = this.stats = { suites: 0, tests: 0, passes: 0, failures: 0 }
2012
+ , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }
1226
2013
  , failures = this.failures = [];
1227
2014
 
1228
2015
  if (!runner) return;
1229
2016
  this.runner = runner;
1230
2017
 
2018
+ runner.stats = stats;
2019
+
1231
2020
  runner.on('start', function(){
1232
2021
  stats.start = new Date;
1233
2022
  });
@@ -1245,8 +2034,8 @@ function Base(runner) {
1245
2034
  runner.on('pass', function(test){
1246
2035
  stats.passes = stats.passes || 0;
1247
2036
 
1248
- var medium = exports.slow / 2;
1249
- test.speed = test.duration > exports.slow
2037
+ var medium = test.slow() / 2;
2038
+ test.speed = test.duration > test.slow()
1250
2039
  ? 'slow'
1251
2040
  : test.duration > medium
1252
2041
  ? 'medium'
@@ -1266,6 +2055,10 @@ function Base(runner) {
1266
2055
  stats.end = new Date;
1267
2056
  stats.duration = new Date - stats.start;
1268
2057
  });
2058
+
2059
+ runner.on('pending', function(){
2060
+ stats.pending++;
2061
+ });
1269
2062
  }
1270
2063
 
1271
2064
  /**
@@ -1276,29 +2069,40 @@ function Base(runner) {
1276
2069
  */
1277
2070
 
1278
2071
  Base.prototype.epilogue = function(){
1279
- var stats = this.stats
1280
- , fmt;
2072
+ var stats = this.stats;
2073
+ var tests;
2074
+ var fmt;
1281
2075
 
1282
2076
  console.log();
1283
2077
 
1284
- // failure
2078
+ // passes
2079
+ fmt = color('bright pass', ' ')
2080
+ + color('green', ' %d passing')
2081
+ + color('light', ' (%s)');
2082
+
2083
+ console.log(fmt,
2084
+ stats.passes || 0,
2085
+ ms(stats.duration));
2086
+
2087
+ // pending
2088
+ if (stats.pending) {
2089
+ fmt = color('pending', ' ')
2090
+ + color('pending', ' %d pending');
2091
+
2092
+ console.log(fmt, stats.pending);
2093
+ }
2094
+
2095
+ // failures
1285
2096
  if (stats.failures) {
1286
- fmt = color('bright fail', ' ')
1287
- + color('fail', ' %d of %d tests failed')
1288
- + color('light', ':')
2097
+ fmt = color('fail', ' %d failing');
2098
+
2099
+ console.error(fmt,
2100
+ stats.failures);
1289
2101
 
1290
- console.error(fmt, stats.failures, this.runner.total);
1291
2102
  Base.list(this.failures);
1292
2103
  console.error();
1293
- return;
1294
2104
  }
1295
2105
 
1296
- // pass
1297
- fmt = color('bright pass', ' ✔')
1298
- + color('green', ' %d tests complete')
1299
- + color('light', ' (%dms)');
1300
-
1301
- console.log(fmt, stats.tests || 0, stats.duration);
1302
2106
  console.log();
1303
2107
  };
1304
2108
 
@@ -1316,6 +2120,73 @@ function pad(str, len) {
1316
2120
  return Array(len - str.length + 1).join(' ') + str;
1317
2121
  }
1318
2122
 
2123
+
2124
+ /**
2125
+ * Returns an inline diff between 2 strings with coloured ANSI output
2126
+ *
2127
+ * @param {Error} Error with actual/expected
2128
+ * @return {String} Diff
2129
+ * @api private
2130
+ */
2131
+
2132
+ function inlineDiff(err) {
2133
+ var msg = errorDiff(err, 'WordsWithSpace', escape);
2134
+
2135
+ // linenos
2136
+ var lines = msg.split('\n');
2137
+ if (lines.length > 4) {
2138
+ var width = String(lines.length).length;
2139
+ msg = lines.map(function(str, i){
2140
+ return pad(++i, width) + ' |' + ' ' + str;
2141
+ }).join('\n');
2142
+ }
2143
+
2144
+ // legend
2145
+ msg = '\n'
2146
+ + color('diff removed', 'actual')
2147
+ + ' '
2148
+ + color('diff added', 'expected')
2149
+ + '\n\n'
2150
+ + msg
2151
+ + '\n';
2152
+
2153
+ // indent
2154
+ msg = msg.replace(/^/gm, ' ');
2155
+ return msg;
2156
+ }
2157
+
2158
+ /**
2159
+ * Returns a unified diff between 2 strings
2160
+ *
2161
+ * @param {Error} Error with actual/expected
2162
+ * @return {String} Diff
2163
+ * @api private
2164
+ */
2165
+
2166
+ function unifiedDiff(err, escape) {
2167
+ var indent = ' ';
2168
+ function cleanUp(line) {
2169
+ if (escape) {
2170
+ line = escapeInvisibles(line);
2171
+ }
2172
+ if (line[0] === '+') return indent + colorLines('diff added', line);
2173
+ if (line[0] === '-') return indent + colorLines('diff removed', line);
2174
+ if (line.match(/\@\@/)) return null;
2175
+ if (line.match(/\\ No newline/)) return null;
2176
+ else return indent + line;
2177
+ }
2178
+ function notBlank(line) {
2179
+ return line != null;
2180
+ }
2181
+ msg = diff.createPatch('string', err.actual, err.expected);
2182
+ var lines = msg.split('\n').splice(4);
2183
+ return '\n '
2184
+ + colorLines('diff added', '+ expected') + ' '
2185
+ + colorLines('diff removed', '- actual')
2186
+ + '\n\n'
2187
+ + lines.map(cleanUp).filter(notBlank).join('\n');
2188
+ }
2189
+
1319
2190
  /**
1320
2191
  * Return a character diff for `err`.
1321
2192
  *
@@ -1324,14 +2195,29 @@ function pad(str, len) {
1324
2195
  * @api private
1325
2196
  */
1326
2197
 
1327
- function errorDiff(err, type) {
1328
- return diff['diff' + type](err.actual, err.expected).map(function(str){
2198
+ function errorDiff(err, type, escape) {
2199
+ var actual = escape ? escapeInvisibles(err.actual) : err.actual;
2200
+ var expected = escape ? escapeInvisibles(err.expected) : err.expected;
2201
+ return diff['diff' + type](actual, expected).map(function(str){
1329
2202
  if (str.added) return colorLines('diff added', str.value);
1330
2203
  if (str.removed) return colorLines('diff removed', str.value);
1331
2204
  return str.value;
1332
2205
  }).join('');
1333
2206
  }
1334
2207
 
2208
+ /**
2209
+ * Returns a string with all invisible characters in plain text
2210
+ *
2211
+ * @param {String} line
2212
+ * @return {String}
2213
+ * @api private
2214
+ */
2215
+ function escapeInvisibles(line) {
2216
+ return line.replace(/\t/g, '<tab>')
2217
+ .replace(/\r/g, '<CR>')
2218
+ .replace(/\n/g, '<LF>\n');
2219
+ }
2220
+
1335
2221
  /**
1336
2222
  * Color lines for `str`, using the color `name`.
1337
2223
  *
@@ -1347,6 +2233,34 @@ function colorLines(name, str) {
1347
2233
  }).join('\n');
1348
2234
  }
1349
2235
 
2236
+ /**
2237
+ * Stringify `obj`.
2238
+ *
2239
+ * @param {Mixed} obj
2240
+ * @return {String}
2241
+ * @api private
2242
+ */
2243
+
2244
+ function stringify(obj) {
2245
+ if (obj instanceof RegExp) return obj.toString();
2246
+ return JSON.stringify(obj, null, 2);
2247
+ }
2248
+
2249
+ /**
2250
+ * Check that a / b have the same type.
2251
+ *
2252
+ * @param {Object} a
2253
+ * @param {Object} b
2254
+ * @return {Boolean}
2255
+ * @api private
2256
+ */
2257
+
2258
+ function sameType(a, b) {
2259
+ a = Object.prototype.toString.call(a);
2260
+ b = Object.prototype.toString.call(b);
2261
+ return a == b;
2262
+ }
2263
+
1350
2264
  }); // module: reporters/base.js
1351
2265
 
1352
2266
  require.register("reporters/doc.js", function(module, exports, require){
@@ -1388,7 +2302,7 @@ function Doc(runner) {
1388
2302
  ++indents;
1389
2303
  console.log('%s<section class="suite">', indent());
1390
2304
  ++indents;
1391
- console.log('%s<h1>%s</h1>', indent(), suite.title);
2305
+ console.log('%s<h1>%s</h1>', indent(), utils.escape(suite.title));
1392
2306
  console.log('%s<dl>', indent());
1393
2307
  });
1394
2308
 
@@ -1401,29 +2315,12 @@ function Doc(runner) {
1401
2315
  });
1402
2316
 
1403
2317
  runner.on('pass', function(test){
1404
- console.log('%s <dt>%s</dt>', indent(), test.title);
1405
- var code = utils.escape(clean(test.fn.toString()));
2318
+ console.log('%s <dt>%s</dt>', indent(), utils.escape(test.title));
2319
+ var code = utils.escape(utils.clean(test.fn.toString()));
1406
2320
  console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
1407
2321
  });
1408
2322
  }
1409
2323
 
1410
- /**
1411
- * Strip the function definition from `str`,
1412
- * and re-indent for pre whitespace.
1413
- */
1414
-
1415
- function clean(str) {
1416
- str = str
1417
- .replace(/^function *\(.*\) *{/, '')
1418
- .replace(/\s+\}$/, '');
1419
-
1420
- var spaces = str.match(/^\n?( *)/)[1].length
1421
- , re = new RegExp('^ {' + spaces + '}', 'gm');
1422
-
1423
- str = str.replace(re, '');
1424
-
1425
- return str;
1426
- }
1427
2324
  }); // module: reporters/doc.js
1428
2325
 
1429
2326
  require.register("reporters/dot.js", function(module, exports, require){
@@ -1461,21 +2358,21 @@ function Dot(runner) {
1461
2358
  });
1462
2359
 
1463
2360
  runner.on('pending', function(test){
1464
- process.stdout.write(color('pending', '.'));
2361
+ process.stdout.write(color('pending', Base.symbols.dot));
1465
2362
  });
1466
2363
 
1467
2364
  runner.on('pass', function(test){
1468
2365
  if (++n % width == 0) process.stdout.write('\n ');
1469
2366
  if ('slow' == test.speed) {
1470
- process.stdout.write(color('bright yellow', '.'));
2367
+ process.stdout.write(color('bright yellow', Base.symbols.dot));
1471
2368
  } else {
1472
- process.stdout.write(color(test.speed, '.'));
2369
+ process.stdout.write(color(test.speed, Base.symbols.dot));
1473
2370
  }
1474
2371
  });
1475
2372
 
1476
2373
  runner.on('fail', function(test, err){
1477
2374
  if (++n % width == 0) process.stdout.write('\n ');
1478
- process.stdout.write(color('fail', '.'));
2375
+ process.stdout.write(color('fail', Base.symbols.dot));
1479
2376
  });
1480
2377
 
1481
2378
  runner.on('end', function(){
@@ -1488,7 +2385,9 @@ function Dot(runner) {
1488
2385
  * Inherit from `Base.prototype`.
1489
2386
  */
1490
2387
 
1491
- Dot.prototype = new Base;
2388
+ function F(){};
2389
+ F.prototype = Base.prototype;
2390
+ Dot.prototype = new F;
1492
2391
  Dot.prototype.constructor = Dot;
1493
2392
 
1494
2393
  }); // module: reporters/dot.js
@@ -1532,6 +2431,13 @@ function HTMLCov(runner) {
1532
2431
  });
1533
2432
  }
1534
2433
 
2434
+ /**
2435
+ * Return coverage class for `n`.
2436
+ *
2437
+ * @return {String}
2438
+ * @api private
2439
+ */
2440
+
1535
2441
  function coverageClass(n) {
1536
2442
  if (n >= 75) return 'high';
1537
2443
  if (n >= 50) return 'medium';
@@ -1551,6 +2457,16 @@ var Base = require('./base')
1551
2457
  , Progress = require('../browser/progress')
1552
2458
  , escape = utils.escape;
1553
2459
 
2460
+ /**
2461
+ * Save timer references to avoid Sinon interfering (see GH-237).
2462
+ */
2463
+
2464
+ var Date = global.Date
2465
+ , setTimeout = global.setTimeout
2466
+ , setInterval = global.setInterval
2467
+ , clearTimeout = global.clearTimeout
2468
+ , clearInterval = global.clearInterval;
2469
+
1554
2470
  /**
1555
2471
  * Expose `Doc`.
1556
2472
  */
@@ -1561,10 +2477,10 @@ exports = module.exports = HTML;
1561
2477
  * Stats template.
1562
2478
  */
1563
2479
 
1564
- var statsTemplate = '<ul id="stats">'
2480
+ var statsTemplate = '<ul id="mocha-stats">'
1565
2481
  + '<li class="progress"><canvas width="40" height="40"></canvas></li>'
1566
- + '<li class="passes">passes: <em>0</em></li>'
1567
- + '<li class="failures">failures: <em>0</em></li>'
2482
+ + '<li class="passes"><a href="#">passes:</a> <em>0</em></li>'
2483
+ + '<li class="failures"><a href="#">failures:</a> <em>0</em></li>'
1568
2484
  + '<li class="duration">duration: <em>0</em>s</li>'
1569
2485
  + '</ul>';
1570
2486
 
@@ -1575,31 +2491,58 @@ var statsTemplate = '<ul id="stats">'
1575
2491
  * @api public
1576
2492
  */
1577
2493
 
1578
- function HTML(runner) {
2494
+ function HTML(runner, root) {
1579
2495
  Base.call(this, runner);
1580
2496
 
1581
2497
  var self = this
1582
2498
  , stats = this.stats
1583
2499
  , total = runner.total
1584
- , root = document.getElementById('mocha')
1585
2500
  , stat = fragment(statsTemplate)
1586
2501
  , items = stat.getElementsByTagName('li')
1587
2502
  , passes = items[1].getElementsByTagName('em')[0]
2503
+ , passesLink = items[1].getElementsByTagName('a')[0]
1588
2504
  , failures = items[2].getElementsByTagName('em')[0]
2505
+ , failuresLink = items[2].getElementsByTagName('a')[0]
1589
2506
  , duration = items[3].getElementsByTagName('em')[0]
1590
2507
  , canvas = stat.getElementsByTagName('canvas')[0]
1591
- , stack = [root]
2508
+ , report = fragment('<ul id="mocha-report"></ul>')
2509
+ , stack = [report]
1592
2510
  , progress
1593
2511
  , ctx
1594
2512
 
2513
+ root = root || document.getElementById('mocha');
2514
+
1595
2515
  if (canvas.getContext) {
2516
+ var ratio = window.devicePixelRatio || 1;
2517
+ canvas.style.width = canvas.width;
2518
+ canvas.style.height = canvas.height;
2519
+ canvas.width *= ratio;
2520
+ canvas.height *= ratio;
1596
2521
  ctx = canvas.getContext('2d');
2522
+ ctx.scale(ratio, ratio);
1597
2523
  progress = new Progress;
1598
2524
  }
1599
2525
 
1600
2526
  if (!root) return error('#mocha div missing, add it to your document');
1601
2527
 
2528
+ // pass toggle
2529
+ on(passesLink, 'click', function(){
2530
+ unhide();
2531
+ var name = /pass/.test(report.className) ? '' : ' pass';
2532
+ report.className = report.className.replace(/fail|pass/g, '') + name;
2533
+ if (report.className.trim()) hideSuitesWithout('test pass');
2534
+ });
2535
+
2536
+ // failure toggle
2537
+ on(failuresLink, 'click', function(){
2538
+ unhide();
2539
+ var name = /fail/.test(report.className) ? '' : ' fail';
2540
+ report.className = report.className.replace(/fail|pass/g, '') + name;
2541
+ if (report.className.trim()) hideSuitesWithout('test fail');
2542
+ });
2543
+
1602
2544
  root.appendChild(stat);
2545
+ root.appendChild(report);
1603
2546
 
1604
2547
  if (progress) progress.size(40);
1605
2548
 
@@ -1607,11 +2550,12 @@ function HTML(runner) {
1607
2550
  if (suite.root) return;
1608
2551
 
1609
2552
  // suite
1610
- var el = fragment('<div class="suite"><h1>%s</h1></div>', suite.title);
2553
+ var url = '?grep=' + encodeURIComponent(suite.fullTitle());
2554
+ var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url, escape(suite.title));
1611
2555
 
1612
2556
  // container
1613
2557
  stack[0].appendChild(el);
1614
- stack.unshift(document.createElement('div'));
2558
+ stack.unshift(document.createElement('ul'));
1615
2559
  el.appendChild(stack[0]);
1616
2560
  });
1617
2561
 
@@ -1621,12 +2565,12 @@ function HTML(runner) {
1621
2565
  });
1622
2566
 
1623
2567
  runner.on('fail', function(test, err){
1624
- if (err.uncaught) runner.emit('test end', test);
2568
+ if ('hook' == test.type) runner.emit('test end', test);
1625
2569
  });
1626
2570
 
1627
2571
  runner.on('test end', function(test){
1628
2572
  // TODO: add to stats
1629
- var percent = stats.tests / total * 100 | 0;
2573
+ var percent = stats.tests / this.total * 100 | 0;
1630
2574
  if (progress) progress.update(percent).draw(ctx);
1631
2575
 
1632
2576
  // update stats
@@ -1637,11 +2581,11 @@ function HTML(runner) {
1637
2581
 
1638
2582
  // test
1639
2583
  if ('passed' == test.state) {
1640
- var el = fragment('<div class="test pass"><h2>%e</h2></div>', test.title);
2584
+ var el = fragment('<li class="test pass %e"><h2>%e<span class="duration">%ems</span> <a href="?grep=%e" class="replay">‣</a></h2></li>', test.speed, test.title, test.duration, encodeURIComponent(test.fullTitle()));
1641
2585
  } else if (test.pending) {
1642
- var el = fragment('<div class="test pass pending"><h2>%e</h2></div>', test.title);
2586
+ var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
1643
2587
  } else {
1644
- var el = fragment('<div class="test fail"><h2>%e</h2></div>', test.title);
2588
+ var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
1645
2589
  var str = test.err.stack || test.err.toString();
1646
2590
 
1647
2591
  // FF / Opera do not add the message
@@ -1662,23 +2606,23 @@ function HTML(runner) {
1662
2606
  }
1663
2607
 
1664
2608
  // toggle code
1665
- var h2 = el.getElementsByTagName('h2')[0];
1666
-
1667
- on(h2, 'click', function(){
1668
- pre.style.display = 'none' == pre.style.display
1669
- ? 'block'
1670
- : 'none';
1671
- });
1672
-
1673
- // code
1674
2609
  // TODO: defer
1675
2610
  if (!test.pending) {
1676
- var pre = fragment('<pre><code>%e</code></pre>', clean(test.fn.toString()));
2611
+ var h2 = el.getElementsByTagName('h2')[0];
2612
+
2613
+ on(h2, 'click', function(){
2614
+ pre.style.display = 'none' == pre.style.display
2615
+ ? 'block'
2616
+ : 'none';
2617
+ });
2618
+
2619
+ var pre = fragment('<pre><code>%e</code></pre>', utils.clean(test.fn.toString()));
1677
2620
  el.appendChild(pre);
1678
2621
  pre.style.display = 'none';
1679
2622
  }
1680
2623
 
1681
- stack[0].appendChild(el);
2624
+ // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.
2625
+ if (stack[0]) stack[0].appendChild(el);
1682
2626
  });
1683
2627
  }
1684
2628
 
@@ -1687,7 +2631,7 @@ function HTML(runner) {
1687
2631
  */
1688
2632
 
1689
2633
  function error(msg) {
1690
- document.body.appendChild(fragment('<div id="error">%s</div>', msg));
2634
+ document.body.appendChild(fragment('<div id="mocha-error">%s</div>', msg));
1691
2635
  }
1692
2636
 
1693
2637
  /**
@@ -1709,6 +2653,30 @@ function fragment(html) {
1709
2653
  return div.firstChild;
1710
2654
  }
1711
2655
 
2656
+ /**
2657
+ * Check for suites that do not have elements
2658
+ * with `classname`, and hide them.
2659
+ */
2660
+
2661
+ function hideSuitesWithout(classname) {
2662
+ var suites = document.getElementsByClassName('suite');
2663
+ for (var i = 0; i < suites.length; i++) {
2664
+ var els = suites[i].getElementsByClassName(classname);
2665
+ if (0 == els.length) suites[i].className += ' hidden';
2666
+ }
2667
+ }
2668
+
2669
+ /**
2670
+ * Unhide .hidden suites.
2671
+ */
2672
+
2673
+ function unhide() {
2674
+ var els = document.getElementsByClassName('suite hidden');
2675
+ for (var i = 0; i < els.length; ++i) {
2676
+ els[i].className = els[i].className.replace('suite hidden', 'suite');
2677
+ }
2678
+ }
2679
+
1712
2680
  /**
1713
2681
  * Set `el` text to `str`.
1714
2682
  */
@@ -1733,26 +2701,6 @@ function on(el, event, fn) {
1733
2701
  }
1734
2702
  }
1735
2703
 
1736
- /**
1737
- * Strip the function definition from `str`,
1738
- * and re-indent for pre whitespace.
1739
- */
1740
-
1741
- function clean(str) {
1742
- str = str
1743
- .replace(/^function *\(.*\) *{/, '')
1744
- .replace(/\s+\}$/, '');
1745
-
1746
- var spaces = str.match(/^\n?( *)/)[1].length
1747
- , re = new RegExp('^ {' + spaces + '}', 'gm');
1748
-
1749
- str = str
1750
- .replace(re, '')
1751
- .replace(/^\s+/, '');
1752
-
1753
- return str;
1754
- }
1755
-
1756
2704
  }); // module: reporters/html.js
1757
2705
 
1758
2706
  require.register("reporters/index.js", function(module, exports, require){
@@ -1766,13 +2714,15 @@ exports.HTML = require('./html');
1766
2714
  exports.List = require('./list');
1767
2715
  exports.Min = require('./min');
1768
2716
  exports.Spec = require('./spec');
2717
+ exports.Nyan = require('./nyan');
2718
+ exports.XUnit = require('./xunit');
2719
+ exports.Markdown = require('./markdown');
1769
2720
  exports.Progress = require('./progress');
1770
2721
  exports.Landing = require('./landing');
1771
2722
  exports.JSONCov = require('./json-cov');
1772
2723
  exports.HTMLCov = require('./html-cov');
1773
2724
  exports.JSONStream = require('./json-stream');
1774
- exports.XUnit = require('./xunit')
1775
- exports.Teamcity = require('./teamcity')
2725
+ exports.Teamcity = require('./teamcity');
1776
2726
 
1777
2727
  }); // module: reporters/index.js
1778
2728
 
@@ -1859,6 +2809,10 @@ function map(cov) {
1859
2809
  ret.sloc += data.sloc;
1860
2810
  }
1861
2811
 
2812
+ ret.files.sort(function(a, b) {
2813
+ return a.filename.localeCompare(b.filename);
2814
+ });
2815
+
1862
2816
  if (ret.sloc > 0) {
1863
2817
  ret.coverage = (ret.hits / ret.sloc) * 100;
1864
2818
  }
@@ -2142,14 +3096,14 @@ function Landing(runner) {
2142
3096
  }
2143
3097
 
2144
3098
  // render landing strip
2145
- stream.write('\033[4F\n\n');
3099
+ stream.write('\u001b[4F\n\n');
2146
3100
  stream.write(runway());
2147
3101
  stream.write('\n ');
2148
3102
  stream.write(color('runway', Array(col).join('⋅')));
2149
3103
  stream.write(plane)
2150
3104
  stream.write(color('runway', Array(width - col).join('⋅') + '\n'));
2151
3105
  stream.write(runway());
2152
- stream.write('\033[0m');
3106
+ stream.write('\u001b[0m');
2153
3107
  });
2154
3108
 
2155
3109
  runner.on('end', function(){
@@ -2163,7 +3117,9 @@ function Landing(runner) {
2163
3117
  * Inherit from `Base.prototype`.
2164
3118
  */
2165
3119
 
2166
- Landing.prototype = new Base;
3120
+ function F(){};
3121
+ F.prototype = Base.prototype;
3122
+ Landing.prototype = new F;
2167
3123
  Landing.prototype.constructor = Landing;
2168
3124
 
2169
3125
  }); // module: reporters/landing.js
@@ -2213,7 +3169,7 @@ function List(runner) {
2213
3169
  });
2214
3170
 
2215
3171
  runner.on('pass', function(test){
2216
- var fmt = color('checkmark', ' ')
3172
+ var fmt = color('checkmark', ' '+Base.symbols.dot)
2217
3173
  + color('pass', ' %s: ')
2218
3174
  + color(test.speed, '%dms');
2219
3175
  cursor.CR();
@@ -2232,14 +3188,15 @@ function List(runner) {
2232
3188
  * Inherit from `Base.prototype`.
2233
3189
  */
2234
3190
 
2235
- List.prototype = new Base;
3191
+ function F(){};
3192
+ F.prototype = Base.prototype;
3193
+ List.prototype = new F;
2236
3194
  List.prototype.constructor = List;
2237
3195
 
2238
3196
 
2239
3197
  }); // module: reporters/list.js
2240
3198
 
2241
3199
  require.register("reporters/markdown.js", function(module, exports, require){
2242
-
2243
3200
  /**
2244
3201
  * Module dependencies.
2245
3202
  */
@@ -2265,7 +3222,6 @@ function Markdown(runner) {
2265
3222
 
2266
3223
  var self = this
2267
3224
  , stats = this.stats
2268
- , total = runner.total
2269
3225
  , level = 0
2270
3226
  , buf = '';
2271
3227
 
@@ -2310,7 +3266,7 @@ function Markdown(runner) {
2310
3266
  runner.on('suite', function(suite){
2311
3267
  ++level;
2312
3268
  var slug = utils.slug(suite.fullTitle());
2313
- buf += '<a name="' + slug + '" />' + '\n';
3269
+ buf += '<a name="' + slug + '"></a>' + '\n';
2314
3270
  buf += title(suite.title) + '\n';
2315
3271
  });
2316
3272
 
@@ -2319,9 +3275,9 @@ function Markdown(runner) {
2319
3275
  });
2320
3276
 
2321
3277
  runner.on('pass', function(test){
2322
- var code = clean(test.fn.toString());
3278
+ var code = utils.clean(test.fn.toString());
2323
3279
  buf += test.title + '.\n';
2324
- buf += '\n```js';
3280
+ buf += '\n```js\n';
2325
3281
  buf += code + '\n';
2326
3282
  buf += '```\n\n';
2327
3283
  });
@@ -2332,27 +3288,10 @@ function Markdown(runner) {
2332
3288
  process.stdout.write(buf);
2333
3289
  });
2334
3290
  }
2335
-
2336
- /**
2337
- * Strip the function definition from `str`,
2338
- * and re-indent for pre whitespace.
2339
- */
2340
-
2341
- function clean(str) {
2342
- str = str
2343
- .replace(/^function *\(.*\) *{/, '')
2344
- .replace(/\s+\}$/, '');
2345
-
2346
- var spaces = str.match(/^\n?( *)/)[1].length
2347
- , re = new RegExp('^ {' + spaces + '}', 'gm');
2348
-
2349
- str = str.replace(re, '');
2350
-
2351
- return str;
2352
- }
2353
3291
  }); // module: reporters/markdown.js
2354
3292
 
2355
3293
  require.register("reporters/min.js", function(module, exports, require){
3294
+
2356
3295
  /**
2357
3296
  * Module dependencies.
2358
3297
  */
@@ -2374,12 +3313,12 @@ exports = module.exports = Min;
2374
3313
 
2375
3314
  function Min(runner) {
2376
3315
  Base.call(this, runner);
2377
-
3316
+
2378
3317
  runner.on('start', function(){
2379
3318
  // clear screen
2380
- process.stdout.write('\033[2J');
3319
+ process.stdout.write('\u001b[2J');
2381
3320
  // set cursor position
2382
- process.stdout.write('\033[1;3H');
3321
+ process.stdout.write('\u001b[1;3H');
2383
3322
  });
2384
3323
 
2385
3324
  runner.on('end', this.epilogue.bind(this));
@@ -2389,11 +3328,282 @@ function Min(runner) {
2389
3328
  * Inherit from `Base.prototype`.
2390
3329
  */
2391
3330
 
2392
- Min.prototype = new Base;
3331
+ function F(){};
3332
+ F.prototype = Base.prototype;
3333
+ Min.prototype = new F;
2393
3334
  Min.prototype.constructor = Min;
2394
3335
 
3336
+
2395
3337
  }); // module: reporters/min.js
2396
3338
 
3339
+ require.register("reporters/nyan.js", function(module, exports, require){
3340
+ /**
3341
+ * Module dependencies.
3342
+ */
3343
+
3344
+ var Base = require('./base')
3345
+ , color = Base.color;
3346
+
3347
+ /**
3348
+ * Expose `Dot`.
3349
+ */
3350
+
3351
+ exports = module.exports = NyanCat;
3352
+
3353
+ /**
3354
+ * Initialize a new `Dot` matrix test reporter.
3355
+ *
3356
+ * @param {Runner} runner
3357
+ * @api public
3358
+ */
3359
+
3360
+ function NyanCat(runner) {
3361
+ Base.call(this, runner);
3362
+ var self = this
3363
+ , stats = this.stats
3364
+ , width = Base.window.width * .75 | 0
3365
+ , rainbowColors = this.rainbowColors = self.generateColors()
3366
+ , colorIndex = this.colorIndex = 0
3367
+ , numerOfLines = this.numberOfLines = 4
3368
+ , trajectories = this.trajectories = [[], [], [], []]
3369
+ , nyanCatWidth = this.nyanCatWidth = 11
3370
+ , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth)
3371
+ , scoreboardWidth = this.scoreboardWidth = 5
3372
+ , tick = this.tick = 0
3373
+ , n = 0;
3374
+
3375
+ runner.on('start', function(){
3376
+ Base.cursor.hide();
3377
+ self.draw();
3378
+ });
3379
+
3380
+ runner.on('pending', function(test){
3381
+ self.draw();
3382
+ });
3383
+
3384
+ runner.on('pass', function(test){
3385
+ self.draw();
3386
+ });
3387
+
3388
+ runner.on('fail', function(test, err){
3389
+ self.draw();
3390
+ });
3391
+
3392
+ runner.on('end', function(){
3393
+ Base.cursor.show();
3394
+ for (var i = 0; i < self.numberOfLines; i++) write('\n');
3395
+ self.epilogue();
3396
+ });
3397
+ }
3398
+
3399
+ /**
3400
+ * Draw the nyan cat
3401
+ *
3402
+ * @api private
3403
+ */
3404
+
3405
+ NyanCat.prototype.draw = function(){
3406
+ this.appendRainbow();
3407
+ this.drawScoreboard();
3408
+ this.drawRainbow();
3409
+ this.drawNyanCat();
3410
+ this.tick = !this.tick;
3411
+ };
3412
+
3413
+ /**
3414
+ * Draw the "scoreboard" showing the number
3415
+ * of passes, failures and pending tests.
3416
+ *
3417
+ * @api private
3418
+ */
3419
+
3420
+ NyanCat.prototype.drawScoreboard = function(){
3421
+ var stats = this.stats;
3422
+ var colors = Base.colors;
3423
+
3424
+ function draw(color, n) {
3425
+ write(' ');
3426
+ write('\u001b[' + color + 'm' + n + '\u001b[0m');
3427
+ write('\n');
3428
+ }
3429
+
3430
+ draw(colors.green, stats.passes);
3431
+ draw(colors.fail, stats.failures);
3432
+ draw(colors.pending, stats.pending);
3433
+ write('\n');
3434
+
3435
+ this.cursorUp(this.numberOfLines);
3436
+ };
3437
+
3438
+ /**
3439
+ * Append the rainbow.
3440
+ *
3441
+ * @api private
3442
+ */
3443
+
3444
+ NyanCat.prototype.appendRainbow = function(){
3445
+ var segment = this.tick ? '_' : '-';
3446
+ var rainbowified = this.rainbowify(segment);
3447
+
3448
+ for (var index = 0; index < this.numberOfLines; index++) {
3449
+ var trajectory = this.trajectories[index];
3450
+ if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift();
3451
+ trajectory.push(rainbowified);
3452
+ }
3453
+ };
3454
+
3455
+ /**
3456
+ * Draw the rainbow.
3457
+ *
3458
+ * @api private
3459
+ */
3460
+
3461
+ NyanCat.prototype.drawRainbow = function(){
3462
+ var self = this;
3463
+
3464
+ this.trajectories.forEach(function(line, index) {
3465
+ write('\u001b[' + self.scoreboardWidth + 'C');
3466
+ write(line.join(''));
3467
+ write('\n');
3468
+ });
3469
+
3470
+ this.cursorUp(this.numberOfLines);
3471
+ };
3472
+
3473
+ /**
3474
+ * Draw the nyan cat
3475
+ *
3476
+ * @api private
3477
+ */
3478
+
3479
+ NyanCat.prototype.drawNyanCat = function() {
3480
+ var self = this;
3481
+ var startWidth = this.scoreboardWidth + this.trajectories[0].length;
3482
+ var color = '\u001b[' + startWidth + 'C';
3483
+ var padding = '';
3484
+
3485
+ write(color);
3486
+ write('_,------,');
3487
+ write('\n');
3488
+
3489
+ write(color);
3490
+ padding = self.tick ? ' ' : ' ';
3491
+ write('_|' + padding + '/\\_/\\ ');
3492
+ write('\n');
3493
+
3494
+ write(color);
3495
+ padding = self.tick ? '_' : '__';
3496
+ var tail = self.tick ? '~' : '^';
3497
+ var face;
3498
+ write(tail + '|' + padding + this.face() + ' ');
3499
+ write('\n');
3500
+
3501
+ write(color);
3502
+ padding = self.tick ? ' ' : ' ';
3503
+ write(padding + '"" "" ');
3504
+ write('\n');
3505
+
3506
+ this.cursorUp(this.numberOfLines);
3507
+ };
3508
+
3509
+ /**
3510
+ * Draw nyan cat face.
3511
+ *
3512
+ * @return {String}
3513
+ * @api private
3514
+ */
3515
+
3516
+ NyanCat.prototype.face = function() {
3517
+ var stats = this.stats;
3518
+ if (stats.failures) {
3519
+ return '( x .x)';
3520
+ } else if (stats.pending) {
3521
+ return '( o .o)';
3522
+ } else if(stats.passes) {
3523
+ return '( ^ .^)';
3524
+ } else {
3525
+ return '( - .-)';
3526
+ }
3527
+ }
3528
+
3529
+ /**
3530
+ * Move cursor up `n`.
3531
+ *
3532
+ * @param {Number} n
3533
+ * @api private
3534
+ */
3535
+
3536
+ NyanCat.prototype.cursorUp = function(n) {
3537
+ write('\u001b[' + n + 'A');
3538
+ };
3539
+
3540
+ /**
3541
+ * Move cursor down `n`.
3542
+ *
3543
+ * @param {Number} n
3544
+ * @api private
3545
+ */
3546
+
3547
+ NyanCat.prototype.cursorDown = function(n) {
3548
+ write('\u001b[' + n + 'B');
3549
+ };
3550
+
3551
+ /**
3552
+ * Generate rainbow colors.
3553
+ *
3554
+ * @return {Array}
3555
+ * @api private
3556
+ */
3557
+
3558
+ NyanCat.prototype.generateColors = function(){
3559
+ var colors = [];
3560
+
3561
+ for (var i = 0; i < (6 * 7); i++) {
3562
+ var pi3 = Math.floor(Math.PI / 3);
3563
+ var n = (i * (1.0 / 6));
3564
+ var r = Math.floor(3 * Math.sin(n) + 3);
3565
+ var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3);
3566
+ var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3);
3567
+ colors.push(36 * r + 6 * g + b + 16);
3568
+ }
3569
+
3570
+ return colors;
3571
+ };
3572
+
3573
+ /**
3574
+ * Apply rainbow to the given `str`.
3575
+ *
3576
+ * @param {String} str
3577
+ * @return {String}
3578
+ * @api private
3579
+ */
3580
+
3581
+ NyanCat.prototype.rainbowify = function(str){
3582
+ var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
3583
+ this.colorIndex += 1;
3584
+ return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
3585
+ };
3586
+
3587
+ /**
3588
+ * Stdout helper.
3589
+ */
3590
+
3591
+ function write(string) {
3592
+ process.stdout.write(string);
3593
+ }
3594
+
3595
+ /**
3596
+ * Inherit from `Base.prototype`.
3597
+ */
3598
+
3599
+ function F(){};
3600
+ F.prototype = Base.prototype;
3601
+ NyanCat.prototype = new F;
3602
+ NyanCat.prototype.constructor = NyanCat;
3603
+
3604
+
3605
+ }); // module: reporters/nyan.js
3606
+
2397
3607
  require.register("reporters/progress.js", function(module, exports, require){
2398
3608
 
2399
3609
  /**
@@ -2438,7 +3648,7 @@ function Progress(runner, options) {
2438
3648
  // default chars
2439
3649
  options.open = options.open || '[';
2440
3650
  options.complete = options.complete || '▬';
2441
- options.incomplete = options.incomplete || '⋅';
3651
+ options.incomplete = options.incomplete || Base.symbols.dot;
2442
3652
  options.close = options.close || ']';
2443
3653
  options.verbose = false;
2444
3654
 
@@ -2450,13 +3660,14 @@ function Progress(runner, options) {
2450
3660
 
2451
3661
  // tests complete
2452
3662
  runner.on('test end', function(){
3663
+ complete++;
2453
3664
  var incomplete = total - complete
2454
- , percent = complete++ / total
3665
+ , percent = complete / total
2455
3666
  , n = width * percent | 0
2456
3667
  , i = width - n;
2457
3668
 
2458
3669
  cursor.CR();
2459
- process.stdout.write('\033[J');
3670
+ process.stdout.write('\u001b[J');
2460
3671
  process.stdout.write(color('progress', ' ' + options.open));
2461
3672
  process.stdout.write(Array(n).join(options.complete));
2462
3673
  process.stdout.write(Array(i).join(options.incomplete));
@@ -2479,7 +3690,9 @@ function Progress(runner, options) {
2479
3690
  * Inherit from `Base.prototype`.
2480
3691
  */
2481
3692
 
2482
- Progress.prototype = new Base;
3693
+ function F(){};
3694
+ F.prototype = Base.prototype;
3695
+ Progress.prototype = new F;
2483
3696
  Progress.prototype.constructor = Progress;
2484
3697
 
2485
3698
 
@@ -2546,13 +3759,13 @@ function Spec(runner) {
2546
3759
  runner.on('pass', function(test){
2547
3760
  if ('fast' == test.speed) {
2548
3761
  var fmt = indent()
2549
- + color('checkmark', ' ')
3762
+ + color('checkmark', ' ' + Base.symbols.ok)
2550
3763
  + color('pass', ' %s ');
2551
3764
  cursor.CR();
2552
3765
  console.log(fmt, test.title);
2553
3766
  } else {
2554
3767
  var fmt = indent()
2555
- + color('checkmark', ' ')
3768
+ + color('checkmark', ' ' + Base.symbols.ok)
2556
3769
  + color('pass', ' %s ')
2557
3770
  + color(test.speed, '(%dms)');
2558
3771
  cursor.CR();
@@ -2572,7 +3785,9 @@ function Spec(runner) {
2572
3785
  * Inherit from `Base.prototype`.
2573
3786
  */
2574
3787
 
2575
- Spec.prototype = new Base;
3788
+ function F(){};
3789
+ F.prototype = Base.prototype;
3790
+ Spec.prototype = new F;
2576
3791
  Spec.prototype.constructor = Spec;
2577
3792
 
2578
3793
 
@@ -2606,10 +3821,12 @@ function TAP(runner) {
2606
3821
 
2607
3822
  var self = this
2608
3823
  , stats = this.stats
2609
- , total = runner.total
2610
- , n = 1;
3824
+ , n = 1
3825
+ , passes = 0
3826
+ , failures = 0;
2611
3827
 
2612
3828
  runner.on('start', function(){
3829
+ var total = runner.grepTotal(runner.suite);
2613
3830
  console.log('%d..%d', 1, total);
2614
3831
  });
2615
3832
 
@@ -2622,12 +3839,20 @@ function TAP(runner) {
2622
3839
  });
2623
3840
 
2624
3841
  runner.on('pass', function(test){
3842
+ passes++;
2625
3843
  console.log('ok %d %s', n, title(test));
2626
3844
  });
2627
3845
 
2628
3846
  runner.on('fail', function(test, err){
3847
+ failures++;
2629
3848
  console.log('not ok %d %s', n, title(test));
2630
- console.log(err.stack.replace(/^/gm, ' '));
3849
+ if (err.stack) console.log(err.stack.replace(/^/gm, ' '));
3850
+ });
3851
+
3852
+ runner.on('end', function(){
3853
+ console.log('# tests ' + (passes + failures));
3854
+ console.log('# pass ' + passes);
3855
+ console.log('# fail ' + failures);
2631
3856
  });
2632
3857
  }
2633
3858
 
@@ -2675,23 +3900,23 @@ function Teamcity(runner) {
2675
3900
  });
2676
3901
 
2677
3902
  runner.on('test', function(test) {
2678
- console.log("##teamcity[testStarted name='%s']", escape(test.fullTitle()));
3903
+ console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']");
2679
3904
  });
2680
3905
 
2681
3906
  runner.on('fail', function(test, err) {
2682
- console.log("##teamcity[testFailed name='%s' message='%s']", escape(test.fullTitle()), escape(err.message));
3907
+ console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']");
2683
3908
  });
2684
3909
 
2685
3910
  runner.on('pending', function(test) {
2686
- console.log("##teamcity[testIgnored name='%s' message='pending']", escape(test.fullTitle()));
3911
+ console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']");
2687
3912
  });
2688
3913
 
2689
3914
  runner.on('test end', function(test) {
2690
- console.log("##teamcity[testFinished name='%s' duration='%s']", escape(test.fullTitle()), test.duration);
3915
+ console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']");
2691
3916
  });
2692
3917
 
2693
3918
  runner.on('end', function() {
2694
- console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='%s']", stats.duration);
3919
+ console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']");
2695
3920
  });
2696
3921
  }
2697
3922
 
@@ -2700,8 +3925,18 @@ function Teamcity(runner) {
2700
3925
  */
2701
3926
 
2702
3927
  function escape(str) {
2703
- return str.replace(/'/g, "|'");
3928
+ return str
3929
+ .replace(/\|/g, "||")
3930
+ .replace(/\n/g, "|n")
3931
+ .replace(/\r/g, "|r")
3932
+ .replace(/\[/g, "|[")
3933
+ .replace(/\]/g, "|]")
3934
+ .replace(/\u0085/g, "|x")
3935
+ .replace(/\u2028/g, "|l")
3936
+ .replace(/\u2029/g, "|p")
3937
+ .replace(/'/g, "|'");
2704
3938
  }
3939
+
2705
3940
  }); // module: reporters/teamcity.js
2706
3941
 
2707
3942
  require.register("reporters/xunit.js", function(module, exports, require){
@@ -2714,6 +3949,16 @@ var Base = require('./base')
2714
3949
  , utils = require('../utils')
2715
3950
  , escape = utils.escape;
2716
3951
 
3952
+ /**
3953
+ * Save timer references to avoid Sinon interfering (see GH-237).
3954
+ */
3955
+
3956
+ var Date = global.Date
3957
+ , setTimeout = global.setTimeout
3958
+ , setInterval = global.setInterval
3959
+ , clearTimeout = global.clearTimeout
3960
+ , clearInterval = global.clearInterval;
3961
+
2717
3962
  /**
2718
3963
  * Expose `XUnit`.
2719
3964
  */
@@ -2733,7 +3978,11 @@ function XUnit(runner) {
2733
3978
  , tests = []
2734
3979
  , self = this;
2735
3980
 
2736
- runner.on('test end', function(test){
3981
+ runner.on('pass', function(test){
3982
+ tests.push(test);
3983
+ });
3984
+
3985
+ runner.on('fail', function(test){
2737
3986
  tests.push(test);
2738
3987
  });
2739
3988
 
@@ -2743,13 +3992,13 @@ function XUnit(runner) {
2743
3992
  , tests: stats.tests
2744
3993
  , failures: stats.failures
2745
3994
  , errors: stats.failures
2746
- , skip: stats.tests - stats.failures - stats.passes
3995
+ , skipped: stats.tests - stats.failures - stats.passes
2747
3996
  , timestamp: (new Date).toUTCString()
2748
- , time: stats.duration / 1000
3997
+ , time: (stats.duration / 1000) || 0
2749
3998
  }, false));
2750
3999
 
2751
4000
  tests.forEach(test);
2752
- console.log('</testsuite>');
4001
+ console.log('</testsuite>');
2753
4002
  });
2754
4003
  }
2755
4004
 
@@ -2757,7 +4006,9 @@ function XUnit(runner) {
2757
4006
  * Inherit from `Base.prototype`.
2758
4007
  */
2759
4008
 
2760
- XUnit.prototype = new Base;
4009
+ function F(){};
4010
+ F.prototype = Base.prototype;
4011
+ XUnit.prototype = new F;
2761
4012
  XUnit.prototype.constructor = XUnit;
2762
4013
 
2763
4014
 
@@ -2818,7 +4069,24 @@ require.register("runnable.js", function(module, exports, require){
2818
4069
  */
2819
4070
 
2820
4071
  var EventEmitter = require('browser/events').EventEmitter
2821
- , debug = require('browser/debug')('runnable');
4072
+ , debug = require('browser/debug')('mocha:runnable')
4073
+ , milliseconds = require('./ms');
4074
+
4075
+ /**
4076
+ * Save timer references to avoid Sinon interfering (see GH-237).
4077
+ */
4078
+
4079
+ var Date = global.Date
4080
+ , setTimeout = global.setTimeout
4081
+ , setInterval = global.setInterval
4082
+ , clearTimeout = global.clearTimeout
4083
+ , clearInterval = global.clearInterval;
4084
+
4085
+ /**
4086
+ * Object#toString().
4087
+ */
4088
+
4089
+ var toString = Object.prototype.toString;
2822
4090
 
2823
4091
  /**
2824
4092
  * Expose `Runnable`.
@@ -2840,6 +4108,7 @@ function Runnable(title, fn) {
2840
4108
  this.async = fn && fn.length;
2841
4109
  this.sync = ! this.async;
2842
4110
  this._timeout = 2000;
4111
+ this._slow = 75;
2843
4112
  this.timedOut = false;
2844
4113
  }
2845
4114
 
@@ -2847,26 +4116,45 @@ function Runnable(title, fn) {
2847
4116
  * Inherit from `EventEmitter.prototype`.
2848
4117
  */
2849
4118
 
2850
- Runnable.prototype = new EventEmitter;
4119
+ function F(){};
4120
+ F.prototype = EventEmitter.prototype;
4121
+ Runnable.prototype = new F;
2851
4122
  Runnable.prototype.constructor = Runnable;
2852
4123
 
2853
4124
 
2854
4125
  /**
2855
4126
  * Set & get timeout `ms`.
2856
4127
  *
2857
- * @param {Number} ms
4128
+ * @param {Number|String} ms
2858
4129
  * @return {Runnable|Number} ms or self
2859
4130
  * @api private
2860
4131
  */
2861
4132
 
2862
4133
  Runnable.prototype.timeout = function(ms){
2863
4134
  if (0 == arguments.length) return this._timeout;
4135
+ if ('string' == typeof ms) ms = milliseconds(ms);
2864
4136
  debug('timeout %d', ms);
2865
4137
  this._timeout = ms;
2866
4138
  if (this.timer) this.resetTimeout();
2867
4139
  return this;
2868
4140
  };
2869
4141
 
4142
+ /**
4143
+ * Set & get slow `ms`.
4144
+ *
4145
+ * @param {Number|String} ms
4146
+ * @return {Runnable|Number} ms or self
4147
+ * @api private
4148
+ */
4149
+
4150
+ Runnable.prototype.slow = function(ms){
4151
+ if (0 === arguments.length) return this._slow;
4152
+ if ('string' == typeof ms) ms = milliseconds(ms);
4153
+ debug('timeout %d', ms);
4154
+ this._slow = ms;
4155
+ return this;
4156
+ };
4157
+
2870
4158
  /**
2871
4159
  * Return the full title generated by recursively
2872
4160
  * concatenating the parent's full title.
@@ -2889,6 +4177,22 @@ Runnable.prototype.clearTimeout = function(){
2889
4177
  clearTimeout(this.timer);
2890
4178
  };
2891
4179
 
4180
+ /**
4181
+ * Inspect the runnable void of private properties.
4182
+ *
4183
+ * @return {String}
4184
+ * @api private
4185
+ */
4186
+
4187
+ Runnable.prototype.inspect = function(){
4188
+ return JSON.stringify(this, function(key, val){
4189
+ if ('_' == key[0]) return;
4190
+ if ('parent' == key) return '#<Suite>';
4191
+ if ('ctx' == key) return '#<Context>';
4192
+ return val;
4193
+ }, 2);
4194
+ };
4195
+
2892
4196
  /**
2893
4197
  * Reset the timeout.
2894
4198
  *
@@ -2896,16 +4200,14 @@ Runnable.prototype.clearTimeout = function(){
2896
4200
  */
2897
4201
 
2898
4202
  Runnable.prototype.resetTimeout = function(){
2899
- var self = this
2900
- , ms = this.timeout();
4203
+ var self = this;
4204
+ var ms = this.timeout() || 1e9;
2901
4205
 
2902
4206
  this.clearTimeout();
2903
- if (ms) {
2904
- this.timer = setTimeout(function(){
2905
- self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
2906
- self.timedOut = true;
2907
- }, ms);
2908
- }
4207
+ this.timer = setTimeout(function(){
4208
+ self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
4209
+ self.timedOut = true;
4210
+ }, ms);
2909
4211
  };
2910
4212
 
2911
4213
  /**
@@ -2923,6 +4225,8 @@ Runnable.prototype.run = function(fn){
2923
4225
  , finished
2924
4226
  , emitted;
2925
4227
 
4228
+ if (ctx) ctx.runnable(this);
4229
+
2926
4230
  // timeout
2927
4231
  if (this.async) {
2928
4232
  if (ms) {
@@ -2934,16 +4238,16 @@ Runnable.prototype.run = function(fn){
2934
4238
  }
2935
4239
 
2936
4240
  // called multiple times
2937
- function multiple() {
4241
+ function multiple(err) {
2938
4242
  if (emitted) return;
2939
4243
  emitted = true;
2940
- self.emit('error', new Error('done() called multiple times'));
4244
+ self.emit('error', err || new Error('done() called multiple times'));
2941
4245
  }
2942
4246
 
2943
4247
  // finished
2944
4248
  function done(err) {
2945
4249
  if (self.timedOut) return;
2946
- if (finished) return multiple();
4250
+ if (finished) return multiple(err);
2947
4251
  self.clearTimeout();
2948
4252
  self.duration = new Date - start;
2949
4253
  finished = true;
@@ -2957,7 +4261,7 @@ Runnable.prototype.run = function(fn){
2957
4261
  if (this.async) {
2958
4262
  try {
2959
4263
  this.fn.call(ctx, function(err){
2960
- if (err instanceof Error) return done(err);
4264
+ if (err instanceof Error || toString.call(err) === "[object Error]") return done(err);
2961
4265
  if (null != err) return done(new Error('done() invoked with non-Error: ' + err));
2962
4266
  done();
2963
4267
  });
@@ -2966,7 +4270,11 @@ Runnable.prototype.run = function(fn){
2966
4270
  }
2967
4271
  return;
2968
4272
  }
2969
-
4273
+
4274
+ if (this.asyncOnly) {
4275
+ return done(new Error('--async-only option in use without declaring `done()`'));
4276
+ }
4277
+
2970
4278
  // sync
2971
4279
  try {
2972
4280
  if (!this.pending) this.fn.call(ctx);
@@ -2980,16 +4288,29 @@ Runnable.prototype.run = function(fn){
2980
4288
  }); // module: runnable.js
2981
4289
 
2982
4290
  require.register("runner.js", function(module, exports, require){
2983
-
2984
4291
  /**
2985
4292
  * Module dependencies.
2986
4293
  */
2987
4294
 
2988
4295
  var EventEmitter = require('browser/events').EventEmitter
2989
- , debug = require('browser/debug')('runner')
4296
+ , debug = require('browser/debug')('mocha:runner')
2990
4297
  , Test = require('./test')
2991
4298
  , utils = require('./utils')
2992
- , noop = function(){};
4299
+ , filter = utils.filter
4300
+ , keys = utils.keys;
4301
+
4302
+ /**
4303
+ * Non-enumerable globals.
4304
+ */
4305
+
4306
+ var globals = [
4307
+ 'setTimeout',
4308
+ 'clearTimeout',
4309
+ 'setInterval',
4310
+ 'clearInterval',
4311
+ 'XMLHttpRequest',
4312
+ 'Date'
4313
+ ];
2993
4314
 
2994
4315
  /**
2995
4316
  * Expose `Runner`.
@@ -3012,6 +4333,7 @@ module.exports = Runner;
3012
4333
  * - `hook end` (hook) hook complete
3013
4334
  * - `pass` (test) test passed
3014
4335
  * - `fail` (test, err) test failed
4336
+ * - `pending` (test) test pending
3015
4337
  *
3016
4338
  * @api public
3017
4339
  */
@@ -3025,31 +4347,87 @@ function Runner(suite) {
3025
4347
  this.on('test end', function(test){ self.checkGlobals(test); });
3026
4348
  this.on('hook end', function(hook){ self.checkGlobals(hook); });
3027
4349
  this.grep(/.*/);
3028
- this.globals(utils.keys(global).concat(['errno']));
4350
+ this.globals(this.globalProps().concat(['errno']));
3029
4351
  }
3030
4352
 
4353
+ /**
4354
+ * Wrapper for setImmediate, process.nextTick, or browser polyfill.
4355
+ *
4356
+ * @param {Function} fn
4357
+ * @api private
4358
+ */
4359
+
4360
+ Runner.immediately = global.setImmediate || process.nextTick;
4361
+
3031
4362
  /**
3032
4363
  * Inherit from `EventEmitter.prototype`.
3033
4364
  */
3034
4365
 
3035
- Runner.prototype = new EventEmitter;
4366
+ function F(){};
4367
+ F.prototype = EventEmitter.prototype;
4368
+ Runner.prototype = new F;
3036
4369
  Runner.prototype.constructor = Runner;
3037
4370
 
3038
4371
 
3039
4372
  /**
3040
- * Run tests with full titles matching `re`.
4373
+ * Run tests with full titles matching `re`. Updates runner.total
4374
+ * with number of tests matched.
3041
4375
  *
3042
4376
  * @param {RegExp} re
4377
+ * @param {Boolean} invert
3043
4378
  * @return {Runner} for chaining
3044
4379
  * @api public
3045
4380
  */
3046
4381
 
3047
- Runner.prototype.grep = function(re){
4382
+ Runner.prototype.grep = function(re, invert){
3048
4383
  debug('grep %s', re);
3049
4384
  this._grep = re;
4385
+ this._invert = invert;
4386
+ this.total = this.grepTotal(this.suite);
3050
4387
  return this;
3051
4388
  };
3052
4389
 
4390
+ /**
4391
+ * Returns the number of tests matching the grep search for the
4392
+ * given suite.
4393
+ *
4394
+ * @param {Suite} suite
4395
+ * @return {Number}
4396
+ * @api public
4397
+ */
4398
+
4399
+ Runner.prototype.grepTotal = function(suite) {
4400
+ var self = this;
4401
+ var total = 0;
4402
+
4403
+ suite.eachTest(function(test){
4404
+ var match = self._grep.test(test.fullTitle());
4405
+ if (self._invert) match = !match;
4406
+ if (match) total++;
4407
+ });
4408
+
4409
+ return total;
4410
+ };
4411
+
4412
+ /**
4413
+ * Return a list of global properties.
4414
+ *
4415
+ * @return {Array}
4416
+ * @api private
4417
+ */
4418
+
4419
+ Runner.prototype.globalProps = function() {
4420
+ var props = utils.keys(global);
4421
+
4422
+ // non-enumerables
4423
+ for (var i = 0; i < globals.length; ++i) {
4424
+ if (~utils.indexOf(props, globals[i])) continue;
4425
+ props.push(globals[i]);
4426
+ }
4427
+
4428
+ return props;
4429
+ };
4430
+
3053
4431
  /**
3054
4432
  * Allow the given `arr` of globals.
3055
4433
  *
@@ -3075,11 +4453,19 @@ Runner.prototype.globals = function(arr){
3075
4453
 
3076
4454
  Runner.prototype.checkGlobals = function(test){
3077
4455
  if (this.ignoreLeaks) return;
4456
+ var ok = this._globals;
4457
+ var globals = this.globalProps();
4458
+ var isNode = process.kill;
4459
+ var leaks;
3078
4460
 
3079
- var leaks = utils.filter(utils.keys(global), function(key){
3080
- return !~utils.indexOf(this._globals, key) && (!global.navigator || 'onerror' !== key);
3081
- }, this);
4461
+ // check length - 2 ('errno' and 'location' globals)
4462
+ if (isNode && 1 == ok.length - globals.length) return;
4463
+ else if (2 == ok.length - globals.length) return;
4464
+
4465
+ if(this.prevGlobalsLength == globals.length) return;
4466
+ this.prevGlobalsLength = globals.length;
3082
4467
 
4468
+ leaks = filterLeaks(ok, globals);
3083
4469
  this._globals = this._globals.concat(leaks);
3084
4470
 
3085
4471
  if (leaks.length > 1) {
@@ -3100,6 +4486,11 @@ Runner.prototype.checkGlobals = function(test){
3100
4486
  Runner.prototype.fail = function(test, err){
3101
4487
  ++this.failures;
3102
4488
  test.state = 'failed';
4489
+
4490
+ if ('string' == typeof err) {
4491
+ err = new Error('the string "' + err + '" was thrown, throw an Error :)');
4492
+ }
4493
+
3103
4494
  this.emit('fail', test, err);
3104
4495
  };
3105
4496
 
@@ -3132,15 +4523,16 @@ Runner.prototype.failHook = function(hook, err){
3132
4523
  Runner.prototype.hook = function(name, fn){
3133
4524
  var suite = this.suite
3134
4525
  , hooks = suite['_' + name]
3135
- , ms = suite._timeout
3136
4526
  , self = this
3137
4527
  , timer;
3138
4528
 
3139
4529
  function next(i) {
3140
4530
  var hook = hooks[i];
3141
4531
  if (!hook) return fn();
4532
+ if (self.failures && suite.bail()) return fn();
3142
4533
  self.currentRunnable = hook;
3143
- hook.ctx.test(self.test);
4534
+
4535
+ hook.ctx.currentTest = self.test;
3144
4536
 
3145
4537
  self.emit('hook', hook);
3146
4538
 
@@ -3150,13 +4542,16 @@ Runner.prototype.hook = function(name, fn){
3150
4542
 
3151
4543
  hook.run(function(err){
3152
4544
  hook.removeAllListeners('error');
4545
+ var testError = hook.error();
4546
+ if (testError) self.fail(self.test, testError);
3153
4547
  if (err) return self.failHook(hook, err);
3154
4548
  self.emit('hook end', hook);
4549
+ delete hook.ctx.currentTest;
3155
4550
  next(++i);
3156
4551
  });
3157
4552
  }
3158
4553
 
3159
- process.nextTick(function(){
4554
+ Runner.immediately(function(){
3160
4555
  next(0);
3161
4556
  });
3162
4557
  };
@@ -3248,8 +4643,9 @@ Runner.prototype.runTest = function(fn){
3248
4643
  var test = this.test
3249
4644
  , self = this;
3250
4645
 
4646
+ if (this.asyncOnly) test.asyncOnly = true;
4647
+
3251
4648
  try {
3252
- test.ctx.test(test);
3253
4649
  test.on('error', function(err){
3254
4650
  self.fail(test, err);
3255
4651
  });
@@ -3270,7 +4666,7 @@ Runner.prototype.runTest = function(fn){
3270
4666
 
3271
4667
  Runner.prototype.runTests = function(suite, fn){
3272
4668
  var self = this
3273
- , tests = suite.tests
4669
+ , tests = suite.tests.slice()
3274
4670
  , test;
3275
4671
 
3276
4672
  function next(err) {
@@ -3284,7 +4680,9 @@ Runner.prototype.runTests = function(suite, fn){
3284
4680
  if (!test) return fn();
3285
4681
 
3286
4682
  // grep
3287
- if (!self._grep.test(test.fullTitle())) return next();
4683
+ var match = self._grep.test(test.fullTitle());
4684
+ if (self._invert) match = !match;
4685
+ if (!match) return next();
3288
4686
 
3289
4687
  // pending
3290
4688
  if (test.pending) {
@@ -3328,10 +4726,14 @@ Runner.prototype.runTests = function(suite, fn){
3328
4726
  */
3329
4727
 
3330
4728
  Runner.prototype.runSuite = function(suite, fn){
3331
- var self = this
4729
+ var total = this.grepTotal(suite)
4730
+ , self = this
3332
4731
  , i = 0;
3333
4732
 
3334
4733
  debug('run suite %s', suite.fullTitle());
4734
+
4735
+ if (!total) return fn();
4736
+
3335
4737
  this.emit('suite', this.suite = suite);
3336
4738
 
3337
4739
  function next() {
@@ -3361,9 +4763,9 @@ Runner.prototype.runSuite = function(suite, fn){
3361
4763
  */
3362
4764
 
3363
4765
  Runner.prototype.uncaught = function(err){
3364
- debug('uncaught exception');
4766
+ debug('uncaught exception %s', err.message);
3365
4767
  var runnable = this.currentRunnable;
3366
- if ('failed' == runnable.state) return;
4768
+ if (!runnable || 'failed' == runnable.state) return;
3367
4769
  runnable.clearTimeout();
3368
4770
  err.uncaught = true;
3369
4771
  this.fail(runnable, err);
@@ -3392,12 +4794,16 @@ Runner.prototype.run = function(fn){
3392
4794
  var self = this
3393
4795
  , fn = fn || function(){};
3394
4796
 
4797
+ function uncaught(err){
4798
+ self.uncaught(err);
4799
+ }
4800
+
3395
4801
  debug('start');
3396
4802
 
3397
4803
  // callback
3398
4804
  this.on('end', function(){
3399
4805
  debug('end');
3400
- process.removeListener('uncaughtException', this.uncaught);
4806
+ process.removeListener('uncaughtException', uncaught);
3401
4807
  fn(self.failures);
3402
4808
  });
3403
4809
 
@@ -3409,13 +4815,45 @@ Runner.prototype.run = function(fn){
3409
4815
  });
3410
4816
 
3411
4817
  // uncaught exception
3412
- process.on('uncaughtException', function(err){
3413
- self.uncaught(err);
3414
- });
4818
+ process.on('uncaughtException', uncaught);
3415
4819
 
3416
4820
  return this;
3417
4821
  };
3418
4822
 
4823
+ /**
4824
+ * Filter leaks with the given globals flagged as `ok`.
4825
+ *
4826
+ * @param {Array} ok
4827
+ * @param {Array} globals
4828
+ * @return {Array}
4829
+ * @api private
4830
+ */
4831
+
4832
+ function filterLeaks(ok, globals) {
4833
+ return filter(globals, function(key){
4834
+ // Firefox and Chrome exposes iframes as index inside the window object
4835
+ if (/^d+/.test(key)) return false;
4836
+
4837
+ // in firefox
4838
+ // if runner runs in an iframe, this iframe's window.getInterface method not init at first
4839
+ // it is assigned in some seconds
4840
+ if (global.navigator && /^getInterface/.test(key)) return false;
4841
+
4842
+ // an iframe could be approached by window[iframeIndex]
4843
+ // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak
4844
+ if (global.navigator && /^\d+/.test(key)) return false;
4845
+
4846
+ // Opera and IE expose global variables for HTML element IDs (issue #243)
4847
+ if (/^mocha-/.test(key)) return false;
4848
+
4849
+ var matched = filter(ok, function(ok){
4850
+ if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]);
4851
+ return key == ok;
4852
+ });
4853
+ return matched.length == 0 && (!global.navigator || 'onerror' !== key);
4854
+ });
4855
+ }
4856
+
3419
4857
  }); // module: runner.js
3420
4858
 
3421
4859
  require.register("suite.js", function(module, exports, require){
@@ -3425,7 +4863,8 @@ require.register("suite.js", function(module, exports, require){
3425
4863
  */
3426
4864
 
3427
4865
  var EventEmitter = require('browser/events').EventEmitter
3428
- , debug = require('browser/debug')('suite')
4866
+ , debug = require('browser/debug')('mocha:suite')
4867
+ , milliseconds = require('./ms')
3429
4868
  , utils = require('./utils')
3430
4869
  , Hook = require('./hook');
3431
4870
 
@@ -3451,6 +4890,7 @@ exports = module.exports = Suite;
3451
4890
  exports.create = function(parent, title){
3452
4891
  var suite = new Suite(title, parent.ctx);
3453
4892
  suite.parent = parent;
4893
+ if (parent.pending) suite.pending = true;
3454
4894
  title = suite.fullTitle();
3455
4895
  parent.addSuite(suite);
3456
4896
  return suite;
@@ -3470,12 +4910,14 @@ function Suite(title, ctx) {
3470
4910
  this.ctx = ctx;
3471
4911
  this.suites = [];
3472
4912
  this.tests = [];
4913
+ this.pending = false;
3473
4914
  this._beforeEach = [];
3474
4915
  this._beforeAll = [];
3475
4916
  this._afterEach = [];
3476
4917
  this._afterAll = [];
3477
4918
  this.root = !title;
3478
4919
  this._timeout = 2000;
4920
+ this._slow = 75;
3479
4921
  this._bail = false;
3480
4922
  }
3481
4923
 
@@ -3483,7 +4925,9 @@ function Suite(title, ctx) {
3483
4925
  * Inherit from `EventEmitter.prototype`.
3484
4926
  */
3485
4927
 
3486
- Suite.prototype = new EventEmitter;
4928
+ function F(){};
4929
+ F.prototype = EventEmitter.prototype;
4930
+ Suite.prototype = new F;
3487
4931
  Suite.prototype.constructor = Suite;
3488
4932
 
3489
4933
 
@@ -3499,6 +4943,7 @@ Suite.prototype.clone = function(){
3499
4943
  debug('clone');
3500
4944
  suite.ctx = this.ctx;
3501
4945
  suite.timeout(this.timeout());
4946
+ suite.slow(this.slow());
3502
4947
  suite.bail(this.bail());
3503
4948
  return suite;
3504
4949
  };
@@ -3513,12 +4958,28 @@ Suite.prototype.clone = function(){
3513
4958
 
3514
4959
  Suite.prototype.timeout = function(ms){
3515
4960
  if (0 == arguments.length) return this._timeout;
3516
- if (String(ms).match(/s$/)) ms = parseFloat(ms) * 1000;
4961
+ if ('string' == typeof ms) ms = milliseconds(ms);
3517
4962
  debug('timeout %d', ms);
3518
4963
  this._timeout = parseInt(ms, 10);
3519
4964
  return this;
3520
4965
  };
3521
4966
 
4967
+ /**
4968
+ * Set slow `ms` or short-hand such as "2s".
4969
+ *
4970
+ * @param {Number|String} ms
4971
+ * @return {Suite|Number} for chaining
4972
+ * @api private
4973
+ */
4974
+
4975
+ Suite.prototype.slow = function(ms){
4976
+ if (0 === arguments.length) return this._slow;
4977
+ if ('string' == typeof ms) ms = milliseconds(ms);
4978
+ debug('slow %d', ms);
4979
+ this._slow = ms;
4980
+ return this;
4981
+ };
4982
+
3522
4983
  /**
3523
4984
  * Sets whether to bail after first error.
3524
4985
  *
@@ -3543,9 +5004,11 @@ Suite.prototype.bail = function(bail){
3543
5004
  */
3544
5005
 
3545
5006
  Suite.prototype.beforeAll = function(fn){
5007
+ if (this.pending) return this;
3546
5008
  var hook = new Hook('"before all" hook', fn);
3547
5009
  hook.parent = this;
3548
5010
  hook.timeout(this.timeout());
5011
+ hook.slow(this.slow());
3549
5012
  hook.ctx = this.ctx;
3550
5013
  this._beforeAll.push(hook);
3551
5014
  this.emit('beforeAll', hook);
@@ -3561,9 +5024,11 @@ Suite.prototype.beforeAll = function(fn){
3561
5024
  */
3562
5025
 
3563
5026
  Suite.prototype.afterAll = function(fn){
5027
+ if (this.pending) return this;
3564
5028
  var hook = new Hook('"after all" hook', fn);
3565
5029
  hook.parent = this;
3566
5030
  hook.timeout(this.timeout());
5031
+ hook.slow(this.slow());
3567
5032
  hook.ctx = this.ctx;
3568
5033
  this._afterAll.push(hook);
3569
5034
  this.emit('afterAll', hook);
@@ -3579,9 +5044,11 @@ Suite.prototype.afterAll = function(fn){
3579
5044
  */
3580
5045
 
3581
5046
  Suite.prototype.beforeEach = function(fn){
5047
+ if (this.pending) return this;
3582
5048
  var hook = new Hook('"before each" hook', fn);
3583
5049
  hook.parent = this;
3584
5050
  hook.timeout(this.timeout());
5051
+ hook.slow(this.slow());
3585
5052
  hook.ctx = this.ctx;
3586
5053
  this._beforeEach.push(hook);
3587
5054
  this.emit('beforeEach', hook);
@@ -3597,9 +5064,11 @@ Suite.prototype.beforeEach = function(fn){
3597
5064
  */
3598
5065
 
3599
5066
  Suite.prototype.afterEach = function(fn){
5067
+ if (this.pending) return this;
3600
5068
  var hook = new Hook('"after each" hook', fn);
3601
5069
  hook.parent = this;
3602
5070
  hook.timeout(this.timeout());
5071
+ hook.slow(this.slow());
3603
5072
  hook.ctx = this.ctx;
3604
5073
  this._afterEach.push(hook);
3605
5074
  this.emit('afterEach', hook);
@@ -3617,6 +5086,7 @@ Suite.prototype.afterEach = function(fn){
3617
5086
  Suite.prototype.addSuite = function(suite){
3618
5087
  suite.parent = this;
3619
5088
  suite.timeout(this.timeout());
5089
+ suite.slow(this.slow());
3620
5090
  suite.bail(this.bail());
3621
5091
  this.suites.push(suite);
3622
5092
  this.emit('suite', suite);
@@ -3634,6 +5104,7 @@ Suite.prototype.addSuite = function(suite){
3634
5104
  Suite.prototype.addTest = function(test){
3635
5105
  test.parent = this;
3636
5106
  test.timeout(this.timeout());
5107
+ test.slow(this.slow());
3637
5108
  test.ctx = this.ctx;
3638
5109
  this.tests.push(test);
3639
5110
  this.emit('test', test);
@@ -3669,6 +5140,24 @@ Suite.prototype.total = function(){
3669
5140
  }, 0) + this.tests.length;
3670
5141
  };
3671
5142
 
5143
+ /**
5144
+ * Iterates through each suite recursively to find
5145
+ * all tests. Applies a function in the format
5146
+ * `fn(test)`.
5147
+ *
5148
+ * @param {Function} fn
5149
+ * @return {Suite}
5150
+ * @api private
5151
+ */
5152
+
5153
+ Suite.prototype.eachTest = function(fn){
5154
+ utils.forEach(this.tests, fn);
5155
+ utils.forEach(this.suites, function(suite){
5156
+ suite.eachTest(fn);
5157
+ });
5158
+ return this;
5159
+ };
5160
+
3672
5161
  }); // module: suite.js
3673
5162
 
3674
5163
  require.register("test.js", function(module, exports, require){
@@ -3703,30 +5192,15 @@ function Test(title, fn) {
3703
5192
  * Inherit from `Runnable.prototype`.
3704
5193
  */
3705
5194
 
3706
- Test.prototype = new Runnable;
5195
+ function F(){};
5196
+ F.prototype = Runnable.prototype;
5197
+ Test.prototype = new F;
3707
5198
  Test.prototype.constructor = Test;
3708
5199
 
3709
5200
 
3710
- /**
3711
- * Inspect the context void of private properties.
3712
- *
3713
- * @return {String}
3714
- * @api private
3715
- */
3716
-
3717
- Test.prototype.inspect = function(){
3718
- return JSON.stringify(this, function(key, val){
3719
- return '_' == key[0]
3720
- ? undefined
3721
- : 'parent' == key
3722
- ? '#<Suite>'
3723
- : val;
3724
- }, 2);
3725
- };
3726
5201
  }); // module: test.js
3727
5202
 
3728
5203
  require.register("utils.js", function(module, exports, require){
3729
-
3730
5204
  /**
3731
5205
  * Module dependencies.
3732
5206
  */
@@ -3734,7 +5208,7 @@ require.register("utils.js", function(module, exports, require){
3734
5208
  var fs = require('browser/fs')
3735
5209
  , path = require('browser/path')
3736
5210
  , join = path.join
3737
- , debug = require('browser/debug')('watch');
5211
+ , debug = require('browser/debug')('mocha:watch');
3738
5212
 
3739
5213
  /**
3740
5214
  * Ignored directories.
@@ -3750,7 +5224,7 @@ var ignore = ['node_modules', '.git'];
3750
5224
  * @api private
3751
5225
  */
3752
5226
 
3753
- exports.escape = function(html) {
5227
+ exports.escape = function(html){
3754
5228
  return String(html)
3755
5229
  .replace(/&/g, '&amp;')
3756
5230
  .replace(/"/g, '&quot;')
@@ -3767,7 +5241,7 @@ exports.escape = function(html) {
3767
5241
  * @api private
3768
5242
  */
3769
5243
 
3770
- exports.forEach = function(arr, fn, scope) {
5244
+ exports.forEach = function(arr, fn, scope){
3771
5245
  for (var i = 0, l = arr.length; i < l; i++)
3772
5246
  fn.call(scope, arr[i], i);
3773
5247
  };
@@ -3781,7 +5255,7 @@ exports.forEach = function(arr, fn, scope) {
3781
5255
  * @api private
3782
5256
  */
3783
5257
 
3784
- exports.indexOf = function (arr, obj, start) {
5258
+ exports.indexOf = function(arr, obj, start){
3785
5259
  for (var i = start || 0, l = arr.length; i < l; i++) {
3786
5260
  if (arr[i] === obj)
3787
5261
  return i;
@@ -3791,19 +5265,18 @@ exports.indexOf = function (arr, obj, start) {
3791
5265
 
3792
5266
  /**
3793
5267
  * Array#reduce (<=IE8)
3794
- *
5268
+ *
3795
5269
  * @param {Array} array
3796
5270
  * @param {Function} fn
3797
5271
  * @param {Object} initial value
3798
- * @param {Object} scope
3799
5272
  * @api private
3800
5273
  */
3801
5274
 
3802
- exports.reduce = function(arr, fn, val, scope) {
5275
+ exports.reduce = function(arr, fn, val){
3803
5276
  var rval = val;
3804
5277
 
3805
5278
  for (var i = 0, l = arr.length; i < l; i++) {
3806
- rval = fn.call(scope, rval, arr[i], i, arr);
5279
+ rval = fn(rval, arr[i], i, arr);
3807
5280
  }
3808
5281
 
3809
5282
  return rval;
@@ -3814,17 +5287,15 @@ exports.reduce = function(arr, fn, val, scope) {
3814
5287
  *
3815
5288
  * @param {Array} array
3816
5289
  * @param {Function} fn
3817
- * @param {Object} scope
3818
5290
  * @api private
3819
5291
  */
3820
5292
 
3821
- exports.filter = function(arr, fn, scope) {
5293
+ exports.filter = function(arr, fn){
3822
5294
  var ret = [];
3823
5295
 
3824
5296
  for (var i = 0, l = arr.length; i < l; i++) {
3825
5297
  var val = arr[i];
3826
- if (fn.call(scope, val, i, arr))
3827
- ret.push(val);
5298
+ if (fn(val, i, arr)) ret.push(val);
3828
5299
  }
3829
5300
 
3830
5301
  return ret;
@@ -3894,7 +5365,7 @@ exports.files = function(dir, ret){
3894
5365
  path = join(dir, path);
3895
5366
  if (fs.statSync(path).isDirectory()) {
3896
5367
  exports.files(path, ret);
3897
- } else if (path.match(/\.(js|coffee)$/)) {
5368
+ } else if (path.match(/\.(js|coffee|litcoffee|coffee.md)$/)) {
3898
5369
  ret.push(path);
3899
5370
  }
3900
5371
  });
@@ -3907,6 +5378,7 @@ exports.files = function(dir, ret){
3907
5378
  *
3908
5379
  * @param {String} str
3909
5380
  * @return {String}
5381
+ * @api private
3910
5382
  */
3911
5383
 
3912
5384
  exports.slug = function(str){
@@ -3915,7 +5387,115 @@ exports.slug = function(str){
3915
5387
  .replace(/ +/g, '-')
3916
5388
  .replace(/[^-\w]/g, '');
3917
5389
  };
5390
+
5391
+ /**
5392
+ * Strip the function definition from `str`,
5393
+ * and re-indent for pre whitespace.
5394
+ */
5395
+
5396
+ exports.clean = function(str) {
5397
+ str = str
5398
+ .replace(/^function *\(.*\) *{/, '')
5399
+ .replace(/\s+\}$/, '');
5400
+
5401
+ var whitespace = str.match(/^\n?(\s*)/)[1]
5402
+ , re = new RegExp('^' + whitespace, 'gm');
5403
+
5404
+ str = str.replace(re, '');
5405
+
5406
+ return exports.trim(str);
5407
+ };
5408
+
5409
+ /**
5410
+ * Escape regular expression characters in `str`.
5411
+ *
5412
+ * @param {String} str
5413
+ * @return {String}
5414
+ * @api private
5415
+ */
5416
+
5417
+ exports.escapeRegexp = function(str){
5418
+ return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
5419
+ };
5420
+
5421
+ /**
5422
+ * Trim the given `str`.
5423
+ *
5424
+ * @param {String} str
5425
+ * @return {String}
5426
+ * @api private
5427
+ */
5428
+
5429
+ exports.trim = function(str){
5430
+ return str.replace(/^\s+|\s+$/g, '');
5431
+ };
5432
+
5433
+ /**
5434
+ * Parse the given `qs`.
5435
+ *
5436
+ * @param {String} qs
5437
+ * @return {Object}
5438
+ * @api private
5439
+ */
5440
+
5441
+ exports.parseQuery = function(qs){
5442
+ return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){
5443
+ var i = pair.indexOf('=')
5444
+ , key = pair.slice(0, i)
5445
+ , val = pair.slice(++i);
5446
+
5447
+ obj[key] = decodeURIComponent(val);
5448
+ return obj;
5449
+ }, {});
5450
+ };
5451
+
5452
+ /**
5453
+ * Highlight the given string of `js`.
5454
+ *
5455
+ * @param {String} js
5456
+ * @return {String}
5457
+ * @api private
5458
+ */
5459
+
5460
+ function highlight(js) {
5461
+ return js
5462
+ .replace(/</g, '&lt;')
5463
+ .replace(/>/g, '&gt;')
5464
+ .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
5465
+ .replace(/('.*?')/gm, '<span class="string">$1</span>')
5466
+ .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
5467
+ .replace(/(\d+)/gm, '<span class="number">$1</span>')
5468
+ .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
5469
+ .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
5470
+ }
5471
+
5472
+ /**
5473
+ * Highlight the contents of tag `name`.
5474
+ *
5475
+ * @param {String} name
5476
+ * @api private
5477
+ */
5478
+
5479
+ exports.highlightTags = function(name) {
5480
+ var code = document.getElementsByTagName(name);
5481
+ for (var i = 0, len = code.length; i < len; ++i) {
5482
+ code[i].innerHTML = highlight(code[i].innerHTML);
5483
+ }
5484
+ };
5485
+
3918
5486
  }); // module: utils.js
5487
+ // The global object is "self" in Web Workers.
5488
+ global = (function() { return this; })();
5489
+
5490
+ /**
5491
+ * Save timer references to avoid Sinon interfering (see GH-237).
5492
+ */
5493
+
5494
+ var Date = global.Date;
5495
+ var setTimeout = global.setTimeout;
5496
+ var setInterval = global.setInterval;
5497
+ var clearTimeout = global.clearTimeout;
5498
+ var clearInterval = global.clearInterval;
3919
5499
 
3920
5500
  /**
3921
5501
  * Node shims.
@@ -3926,37 +5506,9 @@ exports.slug = function(str){
3926
5506
  * the browser.
3927
5507
  */
3928
5508
 
3929
- process = {};
5509
+ var process = {};
3930
5510
  process.exit = function(status){};
3931
5511
  process.stdout = {};
3932
- global = window;
3933
-
3934
- /**
3935
- * next tick implementation.
3936
- */
3937
-
3938
- process.nextTick = (function(){
3939
- // postMessage behaves badly on IE8
3940
- if (window.ActiveXObject || !window.postMessage) {
3941
- return function(fn){ fn() };
3942
- }
3943
-
3944
- // based on setZeroTimeout by David Baron
3945
- // - http://dbaron.org/log/20100309-faster-timeouts
3946
- var timeouts = []
3947
- , name = 'mocha-zero-timeout'
3948
-
3949
- return function(fn){
3950
- timeouts.push(fn);
3951
- window.postMessage(name, '*');
3952
- window.addEventListener('message', function(e){
3953
- if (e.source == window && e.data == name) {
3954
- if (e.stopPropagation) e.stopPropagation();
3955
- if (timeouts.length) timeouts.shift()();
3956
- }
3957
- }, true);
3958
- }
3959
- })();
3960
5512
 
3961
5513
  /**
3962
5514
  * Remove uncaughtException listener.
@@ -3964,7 +5516,7 @@ process.nextTick = (function(){
3964
5516
 
3965
5517
  process.removeListener = function(e){
3966
5518
  if ('uncaughtException' == e) {
3967
- window.onerror = null;
5519
+ global.onerror = function() {};
3968
5520
  }
3969
5521
  };
3970
5522
 
@@ -3974,7 +5526,9 @@ process.removeListener = function(e){
3974
5526
 
3975
5527
  process.on = function(e, fn){
3976
5528
  if ('uncaughtException' == e) {
3977
- window.onerror = fn;
5529
+ global.onerror = function(err, url, line){
5530
+ fn(new Error(err + ' (' + url + ':' + line + ')'));
5531
+ };
3978
5532
  }
3979
5533
  };
3980
5534
 
@@ -3982,87 +5536,80 @@ process.on = function(e, fn){
3982
5536
  * Expose mocha.
3983
5537
  */
3984
5538
 
3985
- window.mocha = require('mocha');
5539
+ var Mocha = global.Mocha = require('mocha'),
5540
+ mocha = global.mocha = new Mocha({ reporter: 'html' });
3986
5541
 
3987
- // boot
3988
- ;(function(){
3989
- var suite = new mocha.Suite('', new mocha.Context)
3990
- , utils = mocha.utils
3991
- , options = {}
3992
-
3993
- /**
3994
- * Highlight the given string of `js`.
3995
- */
3996
-
3997
- function highlight(js) {
3998
- return js
3999
- .replace(/</g, '&lt;')
4000
- .replace(/>/g, '&gt;')
4001
- .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
4002
- .replace(/('.*?')/gm, '<span class="string">$1</span>')
4003
- .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
4004
- .replace(/(\d+)/gm, '<span class="number">$1</span>')
4005
- .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
4006
- .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
4007
- }
4008
-
4009
- /**
4010
- * Highlight code contents.
4011
- */
4012
-
4013
- function highlightCode() {
4014
- var code = document.getElementsByTagName('code');
4015
- for (var i = 0, len = code.length; i < len; ++i) {
4016
- code[i].innerHTML = highlight(code[i].innerHTML);
4017
- }
4018
- }
5542
+ var immediateQueue = []
5543
+ , immediateTimeout;
4019
5544
 
4020
- /**
4021
- * Parse the given `qs`.
4022
- */
5545
+ function timeslice() {
5546
+ var immediateStart = new Date().getTime();
5547
+ while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) {
5548
+ immediateQueue.shift()();
5549
+ }
5550
+ if (immediateQueue.length) {
5551
+ immediateTimeout = setTimeout(timeslice, 0);
5552
+ } else {
5553
+ immediateTimeout = null;
5554
+ }
5555
+ }
4023
5556
 
4024
- function parse(qs) {
4025
- return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){
4026
- var i = pair.indexOf('=')
4027
- , key = pair.slice(0, i)
4028
- , val = pair.slice(++i);
5557
+ /**
5558
+ * High-performance override of Runner.immediately.
5559
+ */
4029
5560
 
4030
- obj[key] = decodeURIComponent(val);
4031
- return obj;
4032
- }, {});
5561
+ Mocha.Runner.immediately = function(callback) {
5562
+ immediateQueue.push(callback);
5563
+ if (!immediateTimeout) {
5564
+ immediateTimeout = setTimeout(timeslice, 0);
4033
5565
  }
5566
+ };
4034
5567
 
4035
- /**
4036
- * Setup mocha with the given setting options.
4037
- */
5568
+ /**
5569
+ * Override ui to ensure that the ui functions are initialized.
5570
+ * Normally this would happen in Mocha.prototype.loadFiles.
5571
+ */
4038
5572
 
4039
- mocha.setup = function(opts){
4040
- if ('string' === typeof opts) options.ui = opts;
4041
- else options = opts;
5573
+ mocha.ui = function(ui){
5574
+ Mocha.prototype.ui.call(this, ui);
5575
+ this.suite.emit('pre-require', global, null, this);
5576
+ return this;
5577
+ };
4042
5578
 
4043
- ui = mocha.interfaces[options.ui];
4044
- if (!ui) throw new Error('invalid mocha interface "' + ui + '"');
4045
- if (options.timeout) suite.timeout(options.timeout);
4046
- ui(suite);
4047
- suite.emit('pre-require', window);
4048
- };
5579
+ /**
5580
+ * Setup mocha with the given setting options.
5581
+ */
4049
5582
 
4050
- /**
4051
- * Run mocha, returning the Runner.
4052
- */
4053
-
4054
- mocha.run = function(){
4055
- suite.emit('run');
4056
- var runner = new mocha.Runner(suite);
4057
- var Reporter = options.reporter || mocha.reporters.HTML;
4058
- var reporter = new Reporter(runner);
4059
- var query = parse(window.location.search || "");
4060
- if (query.grep) runner.grep(new RegExp(query.grep));
4061
- if (options.ignoreLeaks) runner.ignoreLeaks = true;
4062
- if (options.globals) runner.globals(options.globals);
4063
- runner.globals(['location']);
4064
- runner.on('end', highlightCode);
4065
- return runner.run();
4066
- };
4067
- })();
5583
+ mocha.setup = function(opts){
5584
+ if ('string' == typeof opts) opts = { ui: opts };
5585
+ for (var opt in opts) this[opt](opts[opt]);
5586
+ return this;
5587
+ };
5588
+
5589
+ /**
5590
+ * Run mocha, returning the Runner.
5591
+ */
5592
+
5593
+ mocha.run = function(fn){
5594
+ var options = mocha.options;
5595
+ mocha.globals('location');
5596
+
5597
+ var query = Mocha.utils.parseQuery(global.location.search || '');
5598
+ if (query.grep) mocha.grep(query.grep);
5599
+ if (query.invert) mocha.invert();
5600
+
5601
+ return Mocha.prototype.run.call(mocha, function(){
5602
+ // The DOM Document is not available in Web Workers.
5603
+ if (global.document) {
5604
+ Mocha.utils.highlightTags('code');
5605
+ }
5606
+ if (fn) fn();
5607
+ });
5608
+ };
5609
+
5610
+ /**
5611
+ * Expose the process shim.
5612
+ */
5613
+
5614
+ Mocha.process = process;
4068
5615
  })();