mocha 1.21.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +226 -0
  2. package/bin/_mocha +26 -47
  3. package/bin/mocha +8 -1
  4. package/index.js +1 -2
  5. package/lib/browser/debug.js +0 -1
  6. package/lib/browser/diff.js +16 -1
  7. package/lib/browser/escape-string-regexp.js +11 -0
  8. package/lib/browser/events.js +1 -2
  9. package/lib/browser/glob.js +0 -0
  10. package/lib/browser/progress.js +6 -6
  11. package/lib/browser/tty.js +0 -1
  12. package/lib/context.js +0 -1
  13. package/lib/hook.js +0 -1
  14. package/lib/interfaces/bdd.js +4 -4
  15. package/lib/interfaces/exports.js +1 -2
  16. package/lib/interfaces/index.js +0 -1
  17. package/lib/interfaces/qunit.js +2 -2
  18. package/lib/interfaces/tdd.js +4 -4
  19. package/lib/mocha.js +32 -9
  20. package/lib/ms.js +1 -1
  21. package/lib/reporters/base.js +11 -13
  22. package/lib/reporters/doc.js +0 -1
  23. package/lib/reporters/dot.js +0 -1
  24. package/lib/reporters/html-cov.js +1 -2
  25. package/lib/reporters/html.js +13 -5
  26. package/lib/reporters/index.js +0 -1
  27. package/lib/reporters/json-cov.js +1 -2
  28. package/lib/reporters/json-stream.js +4 -3
  29. package/lib/reporters/json.js +7 -2
  30. package/lib/reporters/landing.js +3 -4
  31. package/lib/reporters/list.js +0 -1
  32. package/lib/reporters/markdown.js +15 -6
  33. package/lib/reporters/min.js +0 -1
  34. package/lib/reporters/nyan.js +14 -14
  35. package/lib/reporters/spec.js +0 -1
  36. package/lib/reporters/tap.js +0 -1
  37. package/lib/reporters/templates/coverage.jade +2 -1
  38. package/lib/reporters/templates/style.html +1 -1
  39. package/lib/reporters/xunit.js +41 -10
  40. package/lib/runnable.js +8 -6
  41. package/lib/runner.js +17 -9
  42. package/lib/suite.js +3 -3
  43. package/lib/test.js +0 -1
  44. package/lib/utils.js +247 -49
  45. package/mocha.js +487 -172
  46. package/package.json +20 -13
  47. package/Readme.md +0 -203
package/mocha.js CHANGED
@@ -48,7 +48,6 @@ require.relative = function (parent) {
48
48
 
49
49
 
50
50
  require.register("browser/debug.js", function(module, exports, require){
51
-
52
51
  module.exports = function(type){
53
52
  return function(){
54
53
  }
@@ -224,7 +223,22 @@ var JsDiff = (function() {
224
223
 
225
224
  var LineDiff = new Diff();
226
225
  LineDiff.tokenize = function(value) {
227
- return value.split(/^/m);
226
+ var retLines = [],
227
+ lines = value.split(/^/m);
228
+
229
+ for(var i = 0; i < lines.length; i++) {
230
+ var line = lines[i],
231
+ lastLine = lines[i - 1];
232
+
233
+ // Merge lines that may contain windows new lines
234
+ if (line == '\n' && lastLine && lastLine[lastLine.length - 1] === '\r') {
235
+ retLines[retLines.length - 1] += '\n';
236
+ } else if (line) {
237
+ retLines.push(line);
238
+ }
239
+ }
240
+
241
+ return retLines;
228
242
  };
229
243
 
230
244
  return {
@@ -414,8 +428,22 @@ if (typeof module !== 'undefined') {
414
428
 
415
429
  }); // module: browser/diff.js
416
430
 
417
- require.register("browser/events.js", function(module, exports, require){
431
+ require.register("browser/escape-string-regexp.js", function(module, exports, require){
432
+ 'use strict';
433
+
434
+ var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
435
+
436
+ module.exports = function (str) {
437
+ if (typeof str !== 'string') {
438
+ throw new TypeError('Expected a string');
439
+ }
418
440
 
441
+ return str.replace(matchOperatorsRe, '\\$&');
442
+ };
443
+
444
+ }); // module: browser/escape-string-regexp.js
445
+
446
+ require.register("browser/events.js", function(module, exports, require){
419
447
  /**
420
448
  * Module exports.
421
449
  */
@@ -593,12 +621,17 @@ EventEmitter.prototype.emit = function (name) {
593
621
 
594
622
  return true;
595
623
  };
624
+
596
625
  }); // module: browser/events.js
597
626
 
598
627
  require.register("browser/fs.js", function(module, exports, require){
599
628
 
600
629
  }); // module: browser/fs.js
601
630
 
631
+ require.register("browser/glob.js", function(module, exports, require){
632
+
633
+ }); // module: browser/glob.js
634
+
602
635
  require.register("browser/path.js", function(module, exports, require){
603
636
 
604
637
  }); // module: browser/path.js
@@ -700,28 +733,28 @@ Progress.prototype.draw = function(ctx){
700
733
  , y = half
701
734
  , rad = half - 1
702
735
  , fontSize = this._fontSize;
703
-
736
+
704
737
  ctx.font = fontSize + 'px ' + this._font;
705
-
738
+
706
739
  var angle = Math.PI * 2 * (percent / 100);
707
740
  ctx.clearRect(0, 0, size, size);
708
-
741
+
709
742
  // outer circle
710
743
  ctx.strokeStyle = '#9f9f9f';
711
744
  ctx.beginPath();
712
745
  ctx.arc(x, y, rad, 0, angle, false);
713
746
  ctx.stroke();
714
-
747
+
715
748
  // inner circle
716
749
  ctx.strokeStyle = '#eee';
717
750
  ctx.beginPath();
718
751
  ctx.arc(x, y, rad - 1, 0, angle, true);
719
752
  ctx.stroke();
720
-
753
+
721
754
  // text
722
755
  var text = this._text || (percent | 0) + '%'
723
756
  , w = ctx.measureText(text).width;
724
-
757
+
725
758
  ctx.fillText(
726
759
  text
727
760
  , x - w / 2 + 1
@@ -733,7 +766,6 @@ Progress.prototype.draw = function(ctx){
733
766
  }); // module: browser/progress.js
734
767
 
735
768
  require.register("browser/tty.js", function(module, exports, require){
736
-
737
769
  exports.isatty = function(){
738
770
  return true;
739
771
  };
@@ -750,7 +782,6 @@ exports.getWindowSize = function(){
750
782
  }); // module: browser/tty.js
751
783
 
752
784
  require.register("context.js", function(module, exports, require){
753
-
754
785
  /**
755
786
  * Expose `Context`.
756
787
  */
@@ -838,7 +869,6 @@ Context.prototype.inspect = function(){
838
869
  }); // module: context.js
839
870
 
840
871
  require.register("hook.js", function(module, exports, require){
841
-
842
872
  /**
843
873
  * Module dependencies.
844
874
  */
@@ -895,14 +925,14 @@ Hook.prototype.error = function(err){
895
925
  }); // module: hook.js
896
926
 
897
927
  require.register("interfaces/bdd.js", function(module, exports, require){
898
-
899
928
  /**
900
929
  * Module dependencies.
901
930
  */
902
931
 
903
932
  var Suite = require('../suite')
904
933
  , Test = require('../test')
905
- , utils = require('../utils');
934
+ , utils = require('../utils')
935
+ , escapeRe = require('browser/escape-string-regexp');
906
936
 
907
937
  /**
908
938
  * BDD-style interface:
@@ -1005,7 +1035,7 @@ module.exports = function(suite){
1005
1035
 
1006
1036
  context.it = context.specify = function(title, fn){
1007
1037
  var suite = suites[0];
1008
- if (suite.pending) var fn = null;
1038
+ if (suite.pending) fn = null;
1009
1039
  var test = new Test(title, fn);
1010
1040
  test.file = file;
1011
1041
  suite.addTest(test);
@@ -1018,7 +1048,7 @@ module.exports = function(suite){
1018
1048
 
1019
1049
  context.it.only = function(title, fn){
1020
1050
  var test = context.it(title, fn);
1021
- var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
1051
+ var reString = '^' + escapeRe(test.fullTitle()) + '$';
1022
1052
  mocha.grep(new RegExp(reString));
1023
1053
  return test;
1024
1054
  };
@@ -1038,7 +1068,6 @@ module.exports = function(suite){
1038
1068
  }); // module: interfaces/bdd.js
1039
1069
 
1040
1070
  require.register("interfaces/exports.js", function(module, exports, require){
1041
-
1042
1071
  /**
1043
1072
  * Module dependencies.
1044
1073
  */
@@ -1092,7 +1121,7 @@ module.exports = function(suite){
1092
1121
  suites[0].addTest(test);
1093
1122
  }
1094
1123
  } else {
1095
- var suite = Suite.create(suites[0], key);
1124
+ suite = Suite.create(suites[0], key);
1096
1125
  suites.unshift(suite);
1097
1126
  visit(obj[key]);
1098
1127
  suites.shift();
@@ -1104,7 +1133,6 @@ module.exports = function(suite){
1104
1133
  }); // module: interfaces/exports.js
1105
1134
 
1106
1135
  require.register("interfaces/index.js", function(module, exports, require){
1107
-
1108
1136
  exports.bdd = require('./bdd');
1109
1137
  exports.tdd = require('./tdd');
1110
1138
  exports.qunit = require('./qunit');
@@ -1113,13 +1141,13 @@ exports.exports = require('./exports');
1113
1141
  }); // module: interfaces/index.js
1114
1142
 
1115
1143
  require.register("interfaces/qunit.js", function(module, exports, require){
1116
-
1117
1144
  /**
1118
1145
  * Module dependencies.
1119
1146
  */
1120
1147
 
1121
1148
  var Suite = require('../suite')
1122
1149
  , Test = require('../test')
1150
+ , escapeRe = require('browser/escape-string-regexp')
1123
1151
  , utils = require('../utils');
1124
1152
 
1125
1153
  /**
@@ -1224,7 +1252,7 @@ module.exports = function(suite){
1224
1252
 
1225
1253
  context.test.only = function(title, fn){
1226
1254
  var test = context.test(title, fn);
1227
- var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
1255
+ var reString = '^' + escapeRe(test.fullTitle()) + '$';
1228
1256
  mocha.grep(new RegExp(reString));
1229
1257
  };
1230
1258
 
@@ -1241,14 +1269,14 @@ module.exports = function(suite){
1241
1269
  }); // module: interfaces/qunit.js
1242
1270
 
1243
1271
  require.register("interfaces/tdd.js", function(module, exports, require){
1244
-
1245
1272
  /**
1246
1273
  * Module dependencies.
1247
1274
  */
1248
1275
 
1249
1276
  var Suite = require('../suite')
1250
1277
  , Test = require('../test')
1251
- , utils = require('../utils');;
1278
+ , escapeRe = require('browser/escape-string-regexp')
1279
+ , utils = require('../utils');
1252
1280
 
1253
1281
  /**
1254
1282
  * TDD-style interface:
@@ -1355,7 +1383,7 @@ module.exports = function(suite){
1355
1383
 
1356
1384
  context.test = function(title, fn){
1357
1385
  var suite = suites[0];
1358
- if (suite.pending) var fn = null;
1386
+ if (suite.pending) fn = null;
1359
1387
  var test = new Test(title, fn);
1360
1388
  test.file = file;
1361
1389
  suite.addTest(test);
@@ -1368,7 +1396,7 @@ module.exports = function(suite){
1368
1396
 
1369
1397
  context.test.only = function(title, fn){
1370
1398
  var test = context.test(title, fn);
1371
- var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
1399
+ var reString = '^' + escapeRe(test.fullTitle()) + '$';
1372
1400
  mocha.grep(new RegExp(reString));
1373
1401
  };
1374
1402
 
@@ -1396,6 +1424,7 @@ require.register("mocha.js", function(module, exports, require){
1396
1424
  */
1397
1425
 
1398
1426
  var path = require('browser/path')
1427
+ , escapeRe = require('browser/escape-string-regexp')
1399
1428
  , utils = require('./utils');
1400
1429
 
1401
1430
  /**
@@ -1466,7 +1495,7 @@ function Mocha(options) {
1466
1495
  this.suite = new exports.Suite('', new exports.Context);
1467
1496
  this.ui(options.ui);
1468
1497
  this.bail(options.bail);
1469
- this.reporter(options.reporter);
1498
+ this.reporter(options.reporter, options.reporterOptions);
1470
1499
  if (null != options.timeout) this.timeout(options.timeout);
1471
1500
  this.useColors(options.useColors)
1472
1501
  if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts);
@@ -1517,10 +1546,10 @@ Mocha.prototype.addFile = function(file){
1517
1546
  * Set reporter to `reporter`, defaults to "spec".
1518
1547
  *
1519
1548
  * @param {String|Function} reporter name or constructor
1549
+ * @param {Object} reporterOptions optional options
1520
1550
  * @api public
1521
1551
  */
1522
-
1523
- Mocha.prototype.reporter = function(reporter){
1552
+ Mocha.prototype.reporter = function(reporter, reporterOptions){
1524
1553
  if ('function' == typeof reporter) {
1525
1554
  this._reporter = reporter;
1526
1555
  } else {
@@ -1535,6 +1564,7 @@ Mocha.prototype.reporter = function(reporter){
1535
1564
  if (!_reporter) throw new Error('invalid reporter "' + reporter + '"');
1536
1565
  this._reporter = _reporter;
1537
1566
  }
1567
+ this.options.reporterOptions = reporterOptions;
1538
1568
  return this;
1539
1569
  };
1540
1570
 
@@ -1607,7 +1637,7 @@ Mocha.prototype._growl = function(runner, reporter) {
1607
1637
 
1608
1638
  Mocha.prototype.grep = function(re){
1609
1639
  this.options.grep = 'string' == typeof re
1610
- ? new RegExp(utils.escapeRegexp(re))
1640
+ ? new RegExp(escapeRe(re))
1611
1641
  : re;
1612
1642
  return this;
1613
1643
  };
@@ -1683,9 +1713,9 @@ Mocha.prototype.globals = function(globals){
1683
1713
  */
1684
1714
 
1685
1715
  Mocha.prototype.useColors = function(colors){
1686
- this.options.useColors = arguments.length && colors != undefined
1687
- ? colors
1688
- : true;
1716
+ if (colors !== undefined) {
1717
+ this.options.useColors = colors;
1718
+ }
1689
1719
  return this;
1690
1720
  };
1691
1721
 
@@ -1757,6 +1787,16 @@ Mocha.prototype.asyncOnly = function(){
1757
1787
  return this;
1758
1788
  };
1759
1789
 
1790
+ /**
1791
+ * Disable syntax highlighting (in browser).
1792
+ * @returns {Mocha}
1793
+ * @api public
1794
+ */
1795
+ Mocha.prototype.noHighlighting = function() {
1796
+ this.options.noHighlighting = true;
1797
+ return this;
1798
+ };
1799
+
1760
1800
  /**
1761
1801
  * Run tests and invoke `fn()` when complete.
1762
1802
  *
@@ -1777,9 +1817,20 @@ Mocha.prototype.run = function(fn){
1777
1817
  if (options.grep) runner.grep(options.grep, options.invert);
1778
1818
  if (options.globals) runner.globals(options.globals);
1779
1819
  if (options.growl) this._growl(runner, reporter);
1780
- exports.reporters.Base.useColors = options.useColors;
1820
+ if (options.useColors !== undefined) {
1821
+ exports.reporters.Base.useColors = options.useColors;
1822
+ }
1781
1823
  exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
1782
- return runner.run(fn);
1824
+
1825
+ function done(failures) {
1826
+ if (reporter.done) {
1827
+ reporter.done(failures, fn);
1828
+ } else {
1829
+ fn(failures);
1830
+ }
1831
+ }
1832
+
1833
+ return runner.run(done);
1783
1834
  };
1784
1835
 
1785
1836
  }); // module: mocha.js
@@ -1811,7 +1862,7 @@ var y = d * 365.25;
1811
1862
  module.exports = function(val, options){
1812
1863
  options = options || {};
1813
1864
  if ('string' == typeof val) return parse(val);
1814
- return options.long ? longFormat(val) : shortFormat(val);
1865
+ return options['long'] ? longFormat(val) : shortFormat(val);
1815
1866
  };
1816
1867
 
1817
1868
  /**
@@ -1898,7 +1949,6 @@ function plural(ms, n, name) {
1898
1949
  }); // module: ms.js
1899
1950
 
1900
1951
  require.register("reporters/base.js", function(module, exports, require){
1901
-
1902
1952
  /**
1903
1953
  * Module dependencies.
1904
1954
  */
@@ -1998,7 +2048,7 @@ if ('win32' == process.platform) {
1998
2048
  */
1999
2049
 
2000
2050
  var color = exports.color = function(type, str) {
2001
- if (!exports.useColors) return str;
2051
+ if (!exports.useColors) return String(str);
2002
2052
  return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
2003
2053
  };
2004
2054
 
@@ -2055,7 +2105,7 @@ exports.cursor = {
2055
2105
  */
2056
2106
 
2057
2107
  exports.list = function(failures){
2058
- console.error();
2108
+ console.log();
2059
2109
  failures.forEach(function(test, i){
2060
2110
  // format
2061
2111
  var fmt = color('error title', ' %s) %s:\n')
@@ -2079,13 +2129,13 @@ exports.list = function(failures){
2079
2129
 
2080
2130
  // explicitly show diff
2081
2131
  if (err.showDiff && sameType(actual, expected)) {
2082
- escape = false;
2083
- err.actual = actual = utils.stringify(actual);
2084
- err.expected = expected = utils.stringify(expected);
2085
- }
2086
2132
 
2087
- // actual / expected diff
2088
- if ('string' == typeof actual && 'string' == typeof expected) {
2133
+ if ('string' !== typeof actual) {
2134
+ escape = false;
2135
+ err.actual = actual = utils.stringify(actual);
2136
+ err.expected = expected = utils.stringify(expected);
2137
+ }
2138
+
2089
2139
  fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n');
2090
2140
  var match = message.match(/^([^:]+): expected/);
2091
2141
  msg = '\n ' + color('error message', match ? match[1] : msg);
@@ -2101,7 +2151,7 @@ exports.list = function(failures){
2101
2151
  stack = stack.slice(index ? index + 1 : index)
2102
2152
  .replace(/^/gm, ' ');
2103
2153
 
2104
- console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
2154
+ console.log(fmt, (i + 1), test.fullTitle(), msg, stack);
2105
2155
  });
2106
2156
  };
2107
2157
 
@@ -2206,11 +2256,10 @@ Base.prototype.epilogue = function(){
2206
2256
  if (stats.failures) {
2207
2257
  fmt = color('fail', ' %d failing');
2208
2258
 
2209
- console.error(fmt,
2210
- stats.failures);
2259
+ console.log(fmt, stats.failures);
2211
2260
 
2212
2261
  Base.list(this.failures);
2213
- console.error();
2262
+ console.log();
2214
2263
  }
2215
2264
 
2216
2265
  console.log();
@@ -2361,7 +2410,6 @@ function sameType(a, b) {
2361
2410
  }); // module: reporters/base.js
2362
2411
 
2363
2412
  require.register("reporters/doc.js", function(module, exports, require){
2364
-
2365
2413
  /**
2366
2414
  * Module dependencies.
2367
2415
  */
@@ -2428,7 +2476,6 @@ function Doc(runner) {
2428
2476
  }); // module: reporters/doc.js
2429
2477
 
2430
2478
  require.register("reporters/dot.js", function(module, exports, require){
2431
-
2432
2479
  /**
2433
2480
  * Module dependencies.
2434
2481
  */
@@ -2499,7 +2546,6 @@ Dot.prototype.constructor = Dot;
2499
2546
  }); // module: reporters/dot.js
2500
2547
 
2501
2548
  require.register("reporters/html-cov.js", function(module, exports, require){
2502
-
2503
2549
  /**
2504
2550
  * Module dependencies.
2505
2551
  */
@@ -2550,10 +2596,10 @@ function coverageClass(n) {
2550
2596
  if (n >= 25) return 'low';
2551
2597
  return 'terrible';
2552
2598
  }
2599
+
2553
2600
  }); // module: reporters/html-cov.js
2554
2601
 
2555
2602
  require.register("reporters/html.js", function(module, exports, require){
2556
-
2557
2603
  /**
2558
2604
  * Module dependencies.
2559
2605
  */
@@ -2691,7 +2737,7 @@ function HTML(runner) {
2691
2737
  } else if (test.pending) {
2692
2738
  var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
2693
2739
  } else {
2694
- var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
2740
+ var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">‣</a></h2></li>', test.title, self.testURL(test));
2695
2741
  var str = test.err.stack || test.err.toString();
2696
2742
 
2697
2743
  // FF / Opera do not add the message
@@ -2732,14 +2778,23 @@ function HTML(runner) {
2732
2778
  });
2733
2779
  }
2734
2780
 
2781
+ /**
2782
+ * Makes a URL, preserving querystring ("search") parameters.
2783
+ * @param {string} s
2784
+ * @returns {string} your new URL
2785
+ */
2786
+ var makeUrl = function makeUrl(s) {
2787
+ var search = window.location.search;
2788
+ return window.location.pathname + (search ? search + '&' : '?' ) + 'grep=' + encodeURIComponent(s);
2789
+ };
2790
+
2735
2791
  /**
2736
2792
  * Provide suite URL
2737
2793
  *
2738
2794
  * @param {Object} [suite]
2739
2795
  */
2740
-
2741
2796
  HTML.prototype.suiteURL = function(suite){
2742
- return '?grep=' + encodeURIComponent(suite.fullTitle());
2797
+ return makeUrl(suite.fullTitle());
2743
2798
  };
2744
2799
 
2745
2800
  /**
@@ -2749,7 +2804,7 @@ HTML.prototype.suiteURL = function(suite){
2749
2804
  */
2750
2805
 
2751
2806
  HTML.prototype.testURL = function(test){
2752
- return '?grep=' + encodeURIComponent(test.fullTitle());
2807
+ return makeUrl(test.fullTitle());
2753
2808
  };
2754
2809
 
2755
2810
  /**
@@ -2830,7 +2885,6 @@ function on(el, event, fn) {
2830
2885
  }); // module: reporters/html.js
2831
2886
 
2832
2887
  require.register("reporters/index.js", function(module, exports, require){
2833
-
2834
2888
  exports.Base = require('./base');
2835
2889
  exports.Dot = require('./dot');
2836
2890
  exports.Doc = require('./doc');
@@ -2852,7 +2906,6 @@ exports.JSONStream = require('./json-stream');
2852
2906
  }); // module: reporters/index.js
2853
2907
 
2854
2908
  require.register("reporters/json-cov.js", function(module, exports, require){
2855
-
2856
2909
  /**
2857
2910
  * Module dependencies.
2858
2911
  */
@@ -2943,7 +2996,7 @@ function map(cov) {
2943
2996
  }
2944
2997
 
2945
2998
  return ret;
2946
- };
2999
+ }
2947
3000
 
2948
3001
  /**
2949
3002
  * Map jscoverage data for a single source file
@@ -3009,7 +3062,6 @@ function clean(test) {
3009
3062
  }); // module: reporters/json-cov.js
3010
3063
 
3011
3064
  require.register("reporters/json-stream.js", function(module, exports, require){
3012
-
3013
3065
  /**
3014
3066
  * Module dependencies.
3015
3067
  */
@@ -3046,7 +3098,9 @@ function List(runner) {
3046
3098
  });
3047
3099
 
3048
3100
  runner.on('fail', function(test, err){
3049
- console.log(JSON.stringify(['fail', clean(test)]));
3101
+ test = clean(test);
3102
+ test.err = err.message;
3103
+ console.log(JSON.stringify(['fail', test]));
3050
3104
  });
3051
3105
 
3052
3106
  runner.on('end', function(){
@@ -3070,10 +3124,10 @@ function clean(test) {
3070
3124
  , duration: test.duration
3071
3125
  }
3072
3126
  }
3127
+
3073
3128
  }); // module: reporters/json-stream.js
3074
3129
 
3075
3130
  require.register("reporters/json.js", function(module, exports, require){
3076
-
3077
3131
  /**
3078
3132
  * Module dependencies.
3079
3133
  */
@@ -3100,6 +3154,7 @@ function JSONReporter(runner) {
3100
3154
  Base.call(this, runner);
3101
3155
 
3102
3156
  var tests = []
3157
+ , pending = []
3103
3158
  , failures = []
3104
3159
  , passes = [];
3105
3160
 
@@ -3111,21 +3166,23 @@ function JSONReporter(runner) {
3111
3166
  passes.push(test);
3112
3167
  });
3113
3168
 
3114
- runner.on('fail', function(test, err){
3169
+ runner.on('fail', function(test){
3115
3170
  failures.push(test);
3116
- if (err === Object(err)) {
3117
- test.errMsg = err.message;
3118
- test.errStack = err.stack;
3119
- }
3171
+ });
3172
+
3173
+ runner.on('pending', function(test){
3174
+ pending.push(test);
3120
3175
  });
3121
3176
 
3122
3177
  runner.on('end', function(){
3123
3178
  var obj = {
3124
3179
  stats: self.stats,
3125
3180
  tests: tests.map(clean),
3181
+ pending: pending.map(clean),
3126
3182
  failures: failures.map(clean),
3127
3183
  passes: passes.map(clean)
3128
3184
  };
3185
+
3129
3186
  runner.testResults = obj;
3130
3187
 
3131
3188
  process.stdout.write(JSON.stringify(obj, null, 2));
@@ -3146,16 +3203,27 @@ function clean(test) {
3146
3203
  title: test.title,
3147
3204
  fullTitle: test.fullTitle(),
3148
3205
  duration: test.duration,
3149
- err: test.err,
3150
- errStack: test.err.stack,
3151
- errMessage: test.err.message
3206
+ err: errorJSON(test.err || {})
3152
3207
  }
3153
3208
  }
3154
3209
 
3210
+ /**
3211
+ * Transform `error` into a JSON object.
3212
+ * @param {Error} err
3213
+ * @return {Object}
3214
+ */
3215
+
3216
+ function errorJSON(err) {
3217
+ var res = {};
3218
+ Object.getOwnPropertyNames(err).forEach(function(key) {
3219
+ res[key] = err[key];
3220
+ }, err);
3221
+ return res;
3222
+ }
3223
+
3155
3224
  }); // module: reporters/json.js
3156
3225
 
3157
3226
  require.register("reporters/landing.js", function(module, exports, require){
3158
-
3159
3227
  /**
3160
3228
  * Module dependencies.
3161
3229
  */
@@ -3213,7 +3281,7 @@ function Landing(runner) {
3213
3281
  }
3214
3282
 
3215
3283
  runner.on('start', function(){
3216
- stream.write('\n ');
3284
+ stream.write('\n\n\n ');
3217
3285
  cursor.hide();
3218
3286
  });
3219
3287
 
@@ -3230,7 +3298,7 @@ function Landing(runner) {
3230
3298
  }
3231
3299
 
3232
3300
  // render landing strip
3233
- stream.write('\u001b[4F\n\n');
3301
+ stream.write('\u001b['+(width+1)+'D\u001b[2A');
3234
3302
  stream.write(runway());
3235
3303
  stream.write('\n ');
3236
3304
  stream.write(color('runway', Array(col).join('⋅')));
@@ -3256,10 +3324,10 @@ F.prototype = Base.prototype;
3256
3324
  Landing.prototype = new F;
3257
3325
  Landing.prototype.constructor = Landing;
3258
3326
 
3327
+
3259
3328
  }); // module: reporters/landing.js
3260
3329
 
3261
3330
  require.register("reporters/list.js", function(module, exports, require){
3262
-
3263
3331
  /**
3264
3332
  * Module dependencies.
3265
3333
  */
@@ -3338,6 +3406,12 @@ require.register("reporters/markdown.js", function(module, exports, require){
3338
3406
  var Base = require('./base')
3339
3407
  , utils = require('../utils');
3340
3408
 
3409
+ /**
3410
+ * Constants
3411
+ */
3412
+
3413
+ var SUITE_PREFIX = '$';
3414
+
3341
3415
  /**
3342
3416
  * Expose `Markdown`.
3343
3417
  */
@@ -3368,8 +3442,9 @@ function Markdown(runner) {
3368
3442
  }
3369
3443
 
3370
3444
  function mapTOC(suite, obj) {
3371
- var ret = obj;
3372
- obj = obj[suite.title] = obj[suite.title] || { suite: suite };
3445
+ var ret = obj,
3446
+ key = SUITE_PREFIX + suite.title;
3447
+ obj = obj[key] = obj[key] || { suite: suite };
3373
3448
  suite.suites.forEach(function(suite){
3374
3449
  mapTOC(suite, obj);
3375
3450
  });
@@ -3382,11 +3457,13 @@ function Markdown(runner) {
3382
3457
  var link;
3383
3458
  for (var key in obj) {
3384
3459
  if ('suite' == key) continue;
3385
- if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
3386
- if (key) buf += Array(level).join(' ') + link;
3460
+ if (key !== SUITE_PREFIX) {
3461
+ link = ' - [' + key.substring(1) + ']';
3462
+ link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
3463
+ buf += Array(level).join(' ') + link;
3464
+ }
3387
3465
  buf += stringifyTOC(obj[key], level);
3388
3466
  }
3389
- --level;
3390
3467
  return buf;
3391
3468
  }
3392
3469
 
@@ -3422,10 +3499,10 @@ function Markdown(runner) {
3422
3499
  process.stdout.write(buf);
3423
3500
  });
3424
3501
  }
3502
+
3425
3503
  }); // module: reporters/markdown.js
3426
3504
 
3427
3505
  require.register("reporters/min.js", function(module, exports, require){
3428
-
3429
3506
  /**
3430
3507
  * Module dependencies.
3431
3508
  */
@@ -3475,8 +3552,7 @@ require.register("reporters/nyan.js", function(module, exports, require){
3475
3552
  * Module dependencies.
3476
3553
  */
3477
3554
 
3478
- var Base = require('./base')
3479
- , color = Base.color;
3555
+ var Base = require('./base');
3480
3556
 
3481
3557
  /**
3482
3558
  * Expose `Dot`.
@@ -3553,17 +3629,16 @@ NyanCat.prototype.draw = function(){
3553
3629
 
3554
3630
  NyanCat.prototype.drawScoreboard = function(){
3555
3631
  var stats = this.stats;
3556
- var colors = Base.colors;
3557
3632
 
3558
- function draw(color, n) {
3633
+ function draw(type, n) {
3559
3634
  write(' ');
3560
- write('\u001b[' + color + 'm' + n + '\u001b[0m');
3635
+ write(Base.color(type, n));
3561
3636
  write('\n');
3562
3637
  }
3563
3638
 
3564
- draw(colors.green, stats.passes);
3565
- draw(colors.fail, stats.failures);
3566
- draw(colors.pending, stats.pending);
3639
+ draw('green', stats.passes);
3640
+ draw('fail', stats.failures);
3641
+ draw('pending', stats.pending);
3567
3642
  write('\n');
3568
3643
 
3569
3644
  this.cursorUp(this.numberOfLines);
@@ -3613,26 +3688,26 @@ NyanCat.prototype.drawRainbow = function(){
3613
3688
  NyanCat.prototype.drawNyanCat = function() {
3614
3689
  var self = this;
3615
3690
  var startWidth = this.scoreboardWidth + this.trajectories[0].length;
3616
- var color = '\u001b[' + startWidth + 'C';
3691
+ var dist = '\u001b[' + startWidth + 'C';
3617
3692
  var padding = '';
3618
3693
 
3619
- write(color);
3694
+ write(dist);
3620
3695
  write('_,------,');
3621
3696
  write('\n');
3622
3697
 
3623
- write(color);
3698
+ write(dist);
3624
3699
  padding = self.tick ? ' ' : ' ';
3625
3700
  write('_|' + padding + '/\\_/\\ ');
3626
3701
  write('\n');
3627
3702
 
3628
- write(color);
3703
+ write(dist);
3629
3704
  padding = self.tick ? '_' : '__';
3630
3705
  var tail = self.tick ? '~' : '^';
3631
3706
  var face;
3632
3707
  write(tail + '|' + padding + this.face() + ' ');
3633
3708
  write('\n');
3634
3709
 
3635
- write(color);
3710
+ write(dist);
3636
3711
  padding = self.tick ? ' ' : ' ';
3637
3712
  write(padding + '"" "" ');
3638
3713
  write('\n');
@@ -3658,7 +3733,7 @@ NyanCat.prototype.face = function() {
3658
3733
  } else {
3659
3734
  return '( - .-)';
3660
3735
  }
3661
- }
3736
+ };
3662
3737
 
3663
3738
  /**
3664
3739
  * Move cursor up `n`.
@@ -3713,6 +3788,8 @@ NyanCat.prototype.generateColors = function(){
3713
3788
  */
3714
3789
 
3715
3790
  NyanCat.prototype.rainbowify = function(str){
3791
+ if (!Base.useColors)
3792
+ return str;
3716
3793
  var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
3717
3794
  this.colorIndex += 1;
3718
3795
  return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
@@ -3839,7 +3916,6 @@ Progress.prototype.constructor = Progress;
3839
3916
  }); // module: reporters/progress.js
3840
3917
 
3841
3918
  require.register("reporters/spec.js", function(module, exports, require){
3842
-
3843
3919
  /**
3844
3920
  * Module dependencies.
3845
3921
  */
@@ -3930,7 +4006,6 @@ Spec.prototype.constructor = Spec;
3930
4006
  }); // module: reporters/spec.js
3931
4007
 
3932
4008
  require.register("reporters/tap.js", function(module, exports, require){
3933
-
3934
4009
  /**
3935
4010
  * Module dependencies.
3936
4011
  */
@@ -4007,13 +4082,13 @@ function title(test) {
4007
4082
  }); // module: reporters/tap.js
4008
4083
 
4009
4084
  require.register("reporters/xunit.js", function(module, exports, require){
4010
-
4011
4085
  /**
4012
4086
  * Module dependencies.
4013
4087
  */
4014
4088
 
4015
4089
  var Base = require('./base')
4016
4090
  , utils = require('../utils')
4091
+ , fs = require('browser/fs')
4017
4092
  , escape = utils.escape;
4018
4093
 
4019
4094
  /**
@@ -4039,12 +4114,19 @@ exports = module.exports = XUnit;
4039
4114
  * @api public
4040
4115
  */
4041
4116
 
4042
- function XUnit(runner) {
4117
+ function XUnit(runner, options) {
4043
4118
  Base.call(this, runner);
4044
4119
  var stats = this.stats
4045
4120
  , tests = []
4046
4121
  , self = this;
4047
4122
 
4123
+ if (options.reporterOptions && options.reporterOptions.output) {
4124
+ if (! fs.createWriteStream) {
4125
+ throw new Error('file output not supported in browser');
4126
+ }
4127
+ self.fileStream = fs.createWriteStream(options.reporterOptions.output);
4128
+ }
4129
+
4048
4130
  runner.on('pending', function(test){
4049
4131
  tests.push(test);
4050
4132
  });
@@ -4058,7 +4140,7 @@ function XUnit(runner) {
4058
4140
  });
4059
4141
 
4060
4142
  runner.on('end', function(){
4061
- console.log(tag('testsuite', {
4143
+ self.write(tag('testsuite', {
4062
4144
  name: 'Mocha Tests'
4063
4145
  , tests: stats.tests
4064
4146
  , failures: stats.failures
@@ -4068,11 +4150,24 @@ function XUnit(runner) {
4068
4150
  , time: (stats.duration / 1000) || 0
4069
4151
  }, false));
4070
4152
 
4071
- tests.forEach(test);
4072
- console.log('</testsuite>');
4153
+ tests.forEach(function(t) { self.test(t); });
4154
+ self.write('</testsuite>');
4073
4155
  });
4074
4156
  }
4075
4157
 
4158
+ /**
4159
+ * Override done to close the stream (if it's a file).
4160
+ */
4161
+ XUnit.prototype.done = function(failures, fn) {
4162
+ if (this.fileStream) {
4163
+ this.fileStream.end(function() {
4164
+ fn(failures);
4165
+ });
4166
+ } else {
4167
+ fn(failures);
4168
+ }
4169
+ };
4170
+
4076
4171
  /**
4077
4172
  * Inherit from `Base.prototype`.
4078
4173
  */
@@ -4083,11 +4178,22 @@ XUnit.prototype = new F;
4083
4178
  XUnit.prototype.constructor = XUnit;
4084
4179
 
4085
4180
 
4181
+ /**
4182
+ * Write out the given line
4183
+ */
4184
+ XUnit.prototype.write = function(line) {
4185
+ if (this.fileStream) {
4186
+ this.fileStream.write(line + '\n');
4187
+ } else {
4188
+ console.log(line);
4189
+ }
4190
+ };
4191
+
4086
4192
  /**
4087
4193
  * Output tag for the given `test.`
4088
4194
  */
4089
4195
 
4090
- function test(test) {
4196
+ XUnit.prototype.test = function(test, ostream) {
4091
4197
  var attrs = {
4092
4198
  classname: test.parent.fullTitle()
4093
4199
  , name: test.title
@@ -4096,13 +4202,13 @@ function test(test) {
4096
4202
 
4097
4203
  if ('failed' == test.state) {
4098
4204
  var err = test.err;
4099
- console.log(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack))));
4205
+ this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack))));
4100
4206
  } else if (test.pending) {
4101
- console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
4207
+ this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
4102
4208
  } else {
4103
- console.log(tag('testcase', attrs, true) );
4209
+ this.write(tag('testcase', attrs, true) );
4104
4210
  }
4105
- }
4211
+ };
4106
4212
 
4107
4213
  /**
4108
4214
  * HTML tag helper.
@@ -4133,14 +4239,14 @@ function cdata(str) {
4133
4239
  }); // module: reporters/xunit.js
4134
4240
 
4135
4241
  require.register("runnable.js", function(module, exports, require){
4136
-
4137
4242
  /**
4138
4243
  * Module dependencies.
4139
4244
  */
4140
4245
 
4141
4246
  var EventEmitter = require('browser/events').EventEmitter
4142
4247
  , debug = require('browser/debug')('mocha:runnable')
4143
- , milliseconds = require('./ms');
4248
+ , milliseconds = require('./ms')
4249
+ , utils = require('./utils');
4144
4250
 
4145
4251
  /**
4146
4252
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -4181,6 +4287,7 @@ function Runnable(title, fn) {
4181
4287
  this._slow = 75;
4182
4288
  this._enableTimeouts = true;
4183
4289
  this.timedOut = false;
4290
+ this._trace = new Error('done() called multiple times')
4184
4291
  }
4185
4292
 
4186
4293
  /**
@@ -4203,6 +4310,7 @@ Runnable.prototype.constructor = Runnable;
4203
4310
 
4204
4311
  Runnable.prototype.timeout = function(ms){
4205
4312
  if (0 == arguments.length) return this._timeout;
4313
+ if (ms === 0) this._enableTimeouts = false;
4206
4314
  if ('string' == typeof ms) ms = milliseconds(ms);
4207
4315
  debug('timeout %d', ms);
4208
4316
  this._timeout = ms;
@@ -4292,6 +4400,7 @@ Runnable.prototype.resetTimeout = function(){
4292
4400
  if (!this._enableTimeouts) return;
4293
4401
  this.clearTimeout();
4294
4402
  this.timer = setTimeout(function(){
4403
+ if (!self._enableTimeouts) return;
4295
4404
  self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
4296
4405
  self.timedOut = true;
4297
4406
  }, ms);
@@ -4328,14 +4437,14 @@ Runnable.prototype.run = function(fn){
4328
4437
  function multiple(err) {
4329
4438
  if (emitted) return;
4330
4439
  emitted = true;
4331
- self.emit('error', err || new Error('done() called multiple times'));
4440
+ self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate'));
4332
4441
  }
4333
4442
 
4334
4443
  // finished
4335
4444
  function done(err) {
4336
4445
  var ms = self.timeout();
4337
4446
  if (self.timedOut) return;
4338
- if (finished) return multiple(err);
4447
+ if (finished) return multiple(err || self._trace);
4339
4448
  self.clearTimeout();
4340
4449
  self.duration = new Date - start;
4341
4450
  finished = true;
@@ -4363,7 +4472,7 @@ Runnable.prototype.run = function(fn){
4363
4472
  done();
4364
4473
  });
4365
4474
  } catch (err) {
4366
- done(err);
4475
+ done(utils.getError(err));
4367
4476
  }
4368
4477
  return;
4369
4478
  }
@@ -4380,7 +4489,7 @@ Runnable.prototype.run = function(fn){
4380
4489
  callFn(this.fn);
4381
4490
  }
4382
4491
  } catch (err) {
4383
- done(err);
4492
+ done(utils.getError(err));
4384
4493
  }
4385
4494
 
4386
4495
  function callFn(fn) {
@@ -4424,7 +4533,9 @@ var globals = [
4424
4533
  'setInterval',
4425
4534
  'clearInterval',
4426
4535
  'XMLHttpRequest',
4427
- 'Date'
4536
+ 'Date',
4537
+ 'setImmediate',
4538
+ 'clearImmediate'
4428
4539
  ];
4429
4540
 
4430
4541
  /**
@@ -4653,7 +4764,6 @@ Runner.prototype.hook = function(name, fn){
4653
4764
  function next(i) {
4654
4765
  var hook = hooks[i];
4655
4766
  if (!hook) return fn();
4656
- if (self.failures && suite.bail()) return fn();
4657
4767
  self.currentRunnable = hook;
4658
4768
 
4659
4769
  hook.ctx.currentTest = self.test;
@@ -4942,18 +5052,25 @@ Runner.prototype.runSuite = function(suite, fn){
4942
5052
 
4943
5053
  Runner.prototype.uncaught = function(err){
4944
5054
  if (err) {
4945
- debug('uncaught exception %s', err.message);
5055
+ debug('uncaught exception %s', err !== function () {
5056
+ return this;
5057
+ }.call(err) ? err : ( err.message || err ));
4946
5058
  } else {
4947
5059
  debug('uncaught undefined exception');
4948
- err = new Error('Catched undefined error, did you throw without specifying what?');
5060
+ err = utils.undefinedError();
4949
5061
  }
4950
-
4951
- var runnable = this.currentRunnable;
4952
- if (!runnable || 'failed' == runnable.state) return;
4953
- runnable.clearTimeout();
4954
5062
  err.uncaught = true;
5063
+
5064
+ var runnable = this.currentRunnable;
5065
+ if (!runnable) return;
5066
+
5067
+ var wasAlreadyDone = runnable.state;
4955
5068
  this.fail(runnable, err);
4956
5069
 
5070
+ runnable.clearTimeout();
5071
+
5072
+ if (wasAlreadyDone) return;
5073
+
4957
5074
  // recover from test
4958
5075
  if ('test' == runnable.type) {
4959
5076
  this.emit('test end', runnable);
@@ -5013,7 +5130,7 @@ Runner.prototype.run = function(fn){
5013
5130
  Runner.prototype.abort = function(){
5014
5131
  debug('aborting');
5015
5132
  this._abort = true;
5016
- }
5133
+ };
5017
5134
 
5018
5135
  /**
5019
5136
  * Filter leaks with the given globals flagged as `ok`.
@@ -5077,7 +5194,6 @@ function filterLeaks(ok, globals) {
5077
5194
  }); // module: runner.js
5078
5195
 
5079
5196
  require.register("suite.js", function(module, exports, require){
5080
-
5081
5197
  /**
5082
5198
  * Module dependencies.
5083
5199
  */
@@ -5182,6 +5298,7 @@ Suite.prototype.clone = function(){
5182
5298
 
5183
5299
  Suite.prototype.timeout = function(ms){
5184
5300
  if (0 == arguments.length) return this._timeout;
5301
+ if (ms.toString() === '0') this._enableTimeouts = false;
5185
5302
  if ('string' == typeof ms) ms = milliseconds(ms);
5186
5303
  debug('timeout %d', ms);
5187
5304
  this._timeout = parseInt(ms, 10);
@@ -5201,7 +5318,7 @@ Suite.prototype.enableTimeouts = function(enabled){
5201
5318
  debug('enableTimeouts %s', enabled);
5202
5319
  this._enableTimeouts = enabled;
5203
5320
  return this;
5204
- }
5321
+ };
5205
5322
 
5206
5323
  /**
5207
5324
  * Set slow `ms` or short-hand such as "2s".
@@ -5222,7 +5339,7 @@ Suite.prototype.slow = function(ms){
5222
5339
  /**
5223
5340
  * Sets whether to bail after first error.
5224
5341
  *
5225
- * @parma {Boolean} bail
5342
+ * @param {Boolean} bail
5226
5343
  * @return {Suite|Number} for chaining
5227
5344
  * @api private
5228
5345
  */
@@ -5430,7 +5547,6 @@ Suite.prototype.eachTest = function(fn){
5430
5547
  }); // module: suite.js
5431
5548
 
5432
5549
  require.register("test.js", function(module, exports, require){
5433
-
5434
5550
  /**
5435
5551
  * Module dependencies.
5436
5552
  */
@@ -5476,6 +5592,9 @@ require.register("utils.js", function(module, exports, require){
5476
5592
 
5477
5593
  var fs = require('browser/fs')
5478
5594
  , path = require('browser/path')
5595
+ , basename = path.basename
5596
+ , exists = fs.existsSync || path.existsSync
5597
+ , glob = require('browser/glob')
5479
5598
  , join = path.join
5480
5599
  , debug = require('browser/debug')('mocha:watch');
5481
5600
 
@@ -5696,18 +5815,6 @@ exports.clean = function(str) {
5696
5815
  return exports.trim(str);
5697
5816
  };
5698
5817
 
5699
- /**
5700
- * Escape regular expression characters in `str`.
5701
- *
5702
- * @param {String} str
5703
- * @return {String}
5704
- * @api private
5705
- */
5706
-
5707
- exports.escapeRegexp = function(str){
5708
- return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
5709
- };
5710
-
5711
5818
  /**
5712
5819
  * Trim the given `str`.
5713
5820
  *
@@ -5767,59 +5874,266 @@ function highlight(js) {
5767
5874
  */
5768
5875
 
5769
5876
  exports.highlightTags = function(name) {
5770
- var code = document.getElementsByTagName(name);
5877
+ var code = document.getElementById('mocha').getElementsByTagName(name);
5771
5878
  for (var i = 0, len = code.length; i < len; ++i) {
5772
5879
  code[i].innerHTML = highlight(code[i].innerHTML);
5773
5880
  }
5774
5881
  };
5775
5882
 
5883
+ /**
5884
+ * If a value could have properties, and has none, this function is called, which returns
5885
+ * a string representation of the empty value.
5886
+ *
5887
+ * Functions w/ no properties return `'[Function]'`
5888
+ * Arrays w/ length === 0 return `'[]'`
5889
+ * Objects w/ no properties return `'{}'`
5890
+ * All else: return result of `value.toString()`
5891
+ *
5892
+ * @param {*} value Value to inspect
5893
+ * @param {string} [type] The type of the value, if known.
5894
+ * @returns {string}
5895
+ */
5896
+ var emptyRepresentation = function emptyRepresentation(value, type) {
5897
+ type = type || exports.type(value);
5898
+
5899
+ switch(type) {
5900
+ case 'function':
5901
+ return '[Function]';
5902
+ case 'object':
5903
+ return '{}';
5904
+ case 'array':
5905
+ return '[]';
5906
+ default:
5907
+ return value.toString();
5908
+ }
5909
+ };
5910
+
5911
+ /**
5912
+ * Takes some variable and asks `{}.toString()` what it thinks it is.
5913
+ * @param {*} value Anything
5914
+ * @example
5915
+ * type({}) // 'object'
5916
+ * type([]) // 'array'
5917
+ * type(1) // 'number'
5918
+ * type(false) // 'boolean'
5919
+ * type(Infinity) // 'number'
5920
+ * type(null) // 'null'
5921
+ * type(new Date()) // 'date'
5922
+ * type(/foo/) // 'regexp'
5923
+ * type('type') // 'string'
5924
+ * type(global) // 'global'
5925
+ * @api private
5926
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
5927
+ * @returns {string}
5928
+ */
5929
+ exports.type = function type(value) {
5930
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
5931
+ return 'buffer';
5932
+ }
5933
+ return Object.prototype.toString.call(value)
5934
+ .replace(/^\[.+\s(.+?)\]$/, '$1')
5935
+ .toLowerCase();
5936
+ };
5776
5937
 
5777
5938
  /**
5778
- * Stringify `obj`.
5939
+ * @summary Stringify `value`.
5940
+ * @description Different behavior depending on type of value.
5941
+ * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
5942
+ * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
5943
+ * - If `value` is an *empty* object, function, or array, return result of function
5944
+ * {@link emptyRepresentation}.
5945
+ * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
5946
+ * JSON.stringify().
5779
5947
  *
5780
- * @param {Object} obj
5781
- * @return {String}
5948
+ * @see exports.type
5949
+ * @param {*} value
5950
+ * @return {string}
5782
5951
  * @api private
5783
5952
  */
5784
5953
 
5785
- exports.stringify = function(obj) {
5786
- if (obj instanceof RegExp) return obj.toString();
5787
- return JSON.stringify(exports.canonicalize(obj), null, 2).replace(/,(\n|$)/g, '$1');
5788
- }
5954
+ exports.stringify = function(value) {
5955
+ var prop,
5956
+ type = exports.type(value);
5957
+
5958
+ if (type === 'null' || type === 'undefined') {
5959
+ return '[' + type + ']';
5960
+ }
5961
+
5962
+ if (type === 'date') {
5963
+ return '[Date: ' + value.toISOString() + ']';
5964
+ }
5965
+
5966
+ if (!~exports.indexOf(['object', 'array', 'function'], type)) {
5967
+ return value.toString();
5968
+ }
5969
+
5970
+ for (prop in value) {
5971
+ if (value.hasOwnProperty(prop)) {
5972
+ return JSON.stringify(exports.canonicalize(value), null, 2).replace(/,(\n|$)/g, '$1');
5973
+ }
5974
+ }
5975
+
5976
+ return emptyRepresentation(value, type);
5977
+ };
5789
5978
 
5790
5979
  /**
5791
- * Return a new object that has the keys in sorted order.
5792
- * @param {Object} obj
5793
- * @return {Object}
5980
+ * Return if obj is a Buffer
5981
+ * @param {Object} arg
5982
+ * @return {Boolean}
5794
5983
  * @api private
5795
5984
  */
5985
+ exports.isBuffer = function (arg) {
5986
+ return typeof Buffer !== 'undefined' && Buffer.isBuffer(arg);
5987
+ };
5796
5988
 
5797
- exports.canonicalize = function(obj, stack) {
5798
- stack = stack || [];
5989
+ /**
5990
+ * @summary Return a new Thing that has the keys in sorted order. Recursive.
5991
+ * @description If the Thing...
5992
+ * - has already been seen, return string `'[Circular]'`
5993
+ * - is `undefined`, return string `'[undefined]'`
5994
+ * - is `null`, return value `null`
5995
+ * - is some other primitive, return the value
5996
+ * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
5997
+ * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
5998
+ * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
5999
+ *
6000
+ * @param {*} value Thing to inspect. May or may not have properties.
6001
+ * @param {Array} [stack=[]] Stack of seen values
6002
+ * @return {(Object|Array|Function|string|undefined)}
6003
+ * @see {@link exports.stringify}
6004
+ * @api private
6005
+ */
5799
6006
 
5800
- if (exports.indexOf(stack, obj) !== -1) return '[Circular]';
6007
+ exports.canonicalize = function(value, stack) {
6008
+ var canonicalizedObj,
6009
+ type = exports.type(value),
6010
+ prop,
6011
+ withStack = function withStack(value, fn) {
6012
+ stack.push(value);
6013
+ fn();
6014
+ stack.pop();
6015
+ };
5801
6016
 
5802
- var canonicalizedObj;
6017
+ stack = stack || [];
5803
6018
 
5804
- if ({}.toString.call(obj) === '[object Array]') {
5805
- stack.push(obj);
5806
- canonicalizedObj = exports.map(obj, function(item) {
5807
- return exports.canonicalize(item, stack);
5808
- });
5809
- stack.pop();
5810
- } else if (typeof obj === 'object' && obj !== null) {
5811
- stack.push(obj);
5812
- canonicalizedObj = {};
5813
- exports.forEach(exports.keys(obj).sort(), function(key) {
5814
- canonicalizedObj[key] = exports.canonicalize(obj[key], stack);
5815
- });
5816
- stack.pop();
5817
- } else {
5818
- canonicalizedObj = obj;
5819
- }
6019
+ if (exports.indexOf(stack, value) !== -1) {
6020
+ return '[Circular]';
6021
+ }
6022
+
6023
+ switch(type) {
6024
+ case 'undefined':
6025
+ canonicalizedObj = '[undefined]';
6026
+ break;
6027
+ case 'buffer':
6028
+ case 'null':
6029
+ canonicalizedObj = value;
6030
+ break;
6031
+ case 'array':
6032
+ withStack(value, function () {
6033
+ canonicalizedObj = exports.map(value, function (item) {
6034
+ return exports.canonicalize(item, stack);
6035
+ });
6036
+ });
6037
+ break;
6038
+ case 'date':
6039
+ canonicalizedObj = '[Date: ' + value.toISOString() + ']';
6040
+ break;
6041
+ case 'function':
6042
+ for (prop in value) {
6043
+ canonicalizedObj = {};
6044
+ break;
6045
+ }
6046
+ if (!canonicalizedObj) {
6047
+ canonicalizedObj = emptyRepresentation(value, type);
6048
+ break;
6049
+ }
6050
+ /* falls through */
6051
+ case 'object':
6052
+ canonicalizedObj = canonicalizedObj || {};
6053
+ withStack(value, function () {
6054
+ exports.forEach(exports.keys(value).sort(), function (key) {
6055
+ canonicalizedObj[key] = exports.canonicalize(value[key], stack);
6056
+ });
6057
+ });
6058
+ break;
6059
+ case 'number':
6060
+ case 'boolean':
6061
+ canonicalizedObj = value;
6062
+ break;
6063
+ default:
6064
+ canonicalizedObj = value.toString();
6065
+ }
6066
+
6067
+ return canonicalizedObj;
6068
+ };
6069
+
6070
+ /**
6071
+ * Lookup file names at the given `path`.
6072
+ */
6073
+ exports.lookupFiles = function lookupFiles(path, extensions, recursive) {
6074
+ var files = [];
6075
+ var re = new RegExp('\\.(' + extensions.join('|') + ')$');
6076
+
6077
+ if (!exists(path)) {
6078
+ if (exists(path + '.js')) {
6079
+ path += '.js';
6080
+ } else {
6081
+ files = glob.sync(path);
6082
+ if (!files.length) throw new Error("cannot resolve path (or pattern) '" + path + "'");
6083
+ return files;
6084
+ }
6085
+ }
6086
+
6087
+ try {
6088
+ var stat = fs.statSync(path);
6089
+ if (stat.isFile()) return path;
6090
+ }
6091
+ catch (ignored) {
6092
+ return;
6093
+ }
6094
+
6095
+ fs.readdirSync(path).forEach(function(file){
6096
+ file = join(path, file);
6097
+ try {
6098
+ var stat = fs.statSync(file);
6099
+ if (stat.isDirectory()) {
6100
+ if (recursive) {
6101
+ files = files.concat(lookupFiles(file, extensions, recursive));
6102
+ }
6103
+ return;
6104
+ }
6105
+ }
6106
+ catch (ignored) {
6107
+ return;
6108
+ }
6109
+ if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') return;
6110
+ files.push(file);
6111
+ });
6112
+
6113
+ return files;
6114
+ };
6115
+
6116
+ /**
6117
+ * Generate an undefined error with a message warning the user.
6118
+ *
6119
+ * @return {Error}
6120
+ */
6121
+
6122
+ exports.undefinedError = function(){
6123
+ return new Error('Caught undefined error, did you throw without specifying what?');
6124
+ };
6125
+
6126
+ /**
6127
+ * Generate an undefined error if `err` is not defined.
6128
+ *
6129
+ * @param {Error} err
6130
+ * @return {Error}
6131
+ */
6132
+
6133
+ exports.getError = function(err){
6134
+ return err || exports.undefinedError();
6135
+ };
5820
6136
 
5821
- return canonicalizedObj;
5822
- }
5823
6137
 
5824
6138
  }); // module: utils.js
5825
6139
  // The global object is "self" in Web Workers.
@@ -5968,7 +6282,8 @@ mocha.run = function(fn){
5968
6282
 
5969
6283
  return Mocha.prototype.run.call(mocha, function(err){
5970
6284
  // The DOM Document is not available in Web Workers.
5971
- if (global.document) {
6285
+ var document = global.document;
6286
+ if (document && document.getElementById('mocha') && options.noHighlighting !== true) {
5972
6287
  Mocha.utils.highlightTags('code');
5973
6288
  }
5974
6289
  if (fn) fn(err);
@@ -5980,4 +6295,4 @@ mocha.run = function(fn){
5980
6295
  */
5981
6296
 
5982
6297
  Mocha.process = process;
5983
- })();
6298
+ })();