mocha 6.2.2 → 7.0.1

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.
package/lib/mocha.js CHANGED
@@ -69,18 +69,18 @@ exports.Test = require('./test');
69
69
  * @param {boolean} [options.allowUncaught] - Propagate uncaught errors?
70
70
  * @param {boolean} [options.asyncOnly] - Force `done` callback or promise?
71
71
  * @param {boolean} [options.bail] - Bail after first test failure?
72
- * @param {boolean} [options.checkLeaks] - If true, check leaks.
72
+ * @param {boolean} [options.checkLeaks] - Check for global variable leaks?
73
+ * @param {boolean} [options.color] - Color TTY output from reporter?
73
74
  * @param {boolean} [options.delay] - Delay root suite execution?
74
- * @param {boolean} [options.enableTimeouts] - Enable timeouts?
75
+ * @param {boolean} [options.diff] - Show diff on failure?
75
76
  * @param {string} [options.fgrep] - Test filter given string.
76
77
  * @param {boolean} [options.forbidOnly] - Tests marked `only` fail the suite?
77
78
  * @param {boolean} [options.forbidPending] - Pending tests fail the suite?
78
- * @param {boolean} [options.fullStackTrace] - Full stacktrace upon failure?
79
+ * @param {boolean} [options.fullTrace] - Full stacktrace upon failure?
79
80
  * @param {string[]} [options.global] - Variables expected in global scope.
80
81
  * @param {RegExp|string} [options.grep] - Test filter given regular expression.
81
82
  * @param {boolean} [options.growl] - Enable desktop notifications?
82
- * @param {boolean} [options.hideDiff] - Suppress diffs from failures?
83
- * @param {boolean} [options.ignoreLeaks] - Ignore global leaks?
83
+ * @param {boolean} [options.inlineDiffs] - Display inline diffs?
84
84
  * @param {boolean} [options.invert] - Invert test filter matches?
85
85
  * @param {boolean} [options.noHighlighting] - Disable syntax highlighting?
86
86
  * @param {string|constructor} [options.reporter] - Reporter name or constructor.
@@ -89,8 +89,6 @@ exports.Test = require('./test');
89
89
  * @param {number} [options.slow] - Slow threshold value.
90
90
  * @param {number|string} [options.timeout] - Timeout threshold value.
91
91
  * @param {string} [options.ui] - Interface name.
92
- * @param {boolean} [options.color] - Color TTY output from reporter?
93
- * @param {boolean} [options.useInlineDiffs] - Use inline diffs?
94
92
  */
95
93
  function Mocha(options) {
96
94
  options = utils.assign({}, mocharc, options || {});
@@ -99,35 +97,15 @@ function Mocha(options) {
99
97
  // root suite
100
98
  this.suite = new exports.Suite('', new exports.Context(), true);
101
99
 
102
- if ('useColors' in options) {
103
- utils.deprecate(
104
- 'useColors is DEPRECATED and will be removed from a future version of Mocha. Instead, use the "color" option'
105
- );
106
- options.color = 'color' in options ? options.color : options.useColors;
107
- }
108
-
109
- // Globals are passed in as options.global, with options.globals for backward compatibility.
110
- options.globals = options.global || options.globals || [];
111
- delete options.global;
112
-
113
100
  this.grep(options.grep)
114
101
  .fgrep(options.fgrep)
115
102
  .ui(options.ui)
116
- .bail(options.bail)
117
- .reporter(options.reporter, options.reporterOptions)
118
- .useColors(options.color)
103
+ .reporter(
104
+ options.reporter,
105
+ options.reporterOption || options.reporterOptions // reporterOptions was previously the only way to specify options to reporter
106
+ )
119
107
  .slow(options.slow)
120
- .useInlineDiffs(options.inlineDiffs)
121
- .globals(options.globals);
122
-
123
- if ('enableTimeouts' in options) {
124
- utils.deprecate(
125
- 'enableTimeouts is DEPRECATED and will be removed from a future version of Mocha. Instead, use "timeout: false" to disable timeouts.'
126
- );
127
- if (options.enableTimeouts === false) {
128
- this.timeout(0);
129
- }
130
- }
108
+ .global(options.global);
131
109
 
132
110
  // this guard exists because Suite#timeout does not consider `undefined` to be valid input
133
111
  if (typeof options.timeout !== 'undefined') {
@@ -138,19 +116,19 @@ function Mocha(options) {
138
116
  this.retries(options.retries);
139
117
  }
140
118
 
141
- if ('diff' in options) {
142
- this.hideDiff(!options.diff);
143
- }
144
-
145
119
  [
146
120
  'allowUncaught',
147
121
  'asyncOnly',
122
+ 'bail',
148
123
  'checkLeaks',
124
+ 'color',
149
125
  'delay',
126
+ 'diff',
150
127
  'forbidOnly',
151
128
  'forbidPending',
152
129
  'fullTrace',
153
130
  'growl',
131
+ 'inlineDiffs',
154
132
  'invert'
155
133
  ].forEach(function(opt) {
156
134
  if (options[opt]) {
@@ -163,16 +141,13 @@ function Mocha(options) {
163
141
  * Enables or disables bailing on the first failure.
164
142
  *
165
143
  * @public
166
- * @see {@link /#-bail-b|CLI option}
144
+ * @see [CLI option](../#-bail-b)
167
145
  * @param {boolean} [bail=true] - Whether to bail on first error.
168
146
  * @returns {Mocha} this
169
147
  * @chainable
170
148
  */
171
149
  Mocha.prototype.bail = function(bail) {
172
- if (!arguments.length) {
173
- bail = true;
174
- }
175
- this.suite.bail(bail);
150
+ this.suite.bail(bail !== false);
176
151
  return this;
177
152
  };
178
153
 
@@ -184,7 +159,7 @@ Mocha.prototype.bail = function(bail) {
184
159
  * Useful for generic setup code that must be included within test suite.
185
160
  *
186
161
  * @public
187
- * @see {@link /#-file-filedirectoryglob|CLI option}
162
+ * @see [CLI option](../#-file-filedirectoryglob)
188
163
  * @param {string} file - Pathname of file to be loaded.
189
164
  * @returns {Mocha} this
190
165
  * @chainable
@@ -198,8 +173,8 @@ Mocha.prototype.addFile = function(file) {
198
173
  * Sets reporter to `reporter`, defaults to "spec".
199
174
  *
200
175
  * @public
201
- * @see {@link /#-reporter-name-r-name|CLI option}
202
- * @see {@link /#reporters|Reporters}
176
+ * @see [CLI option](../#-reporter-name-r-name)
177
+ * @see [Reporters](../#reporters)
203
178
  * @param {String|Function} reporter - Reporter name or constructor.
204
179
  * @param {Object} [reporterOptions] - Options used to configure the reporter.
205
180
  * @returns {Mocha} this
@@ -257,6 +232,8 @@ Mocha.prototype.reporter = function(reporter, reporterOptions) {
257
232
  }
258
233
  this._reporter = _reporter;
259
234
  }
235
+ this.options.reporterOption = reporterOptions;
236
+ // alias option name is used in public reporters xunit/tap/progress
260
237
  this.options.reporterOptions = reporterOptions;
261
238
  return this;
262
239
  };
@@ -265,8 +242,8 @@ Mocha.prototype.reporter = function(reporter, reporterOptions) {
265
242
  * Sets test UI `name`, defaults to "bdd".
266
243
  *
267
244
  * @public
268
- * @see {@link /#-ui-name-u-name|CLI option}
269
- * @see {@link /#interfaces|Interface DSLs}
245
+ * @see [CLI option](../#-ui-name-u-name)
246
+ * @see [Interface DSLs](../#interfaces)
270
247
  * @param {string|Function} [ui=bdd] - Interface name or class.
271
248
  * @returns {Mocha} this
272
249
  * @chainable
@@ -359,8 +336,6 @@ Mocha.unloadFile = function(file) {
359
336
  * <strong>Intended for consumers &mdash; not used internally</strong>
360
337
  *
361
338
  * @public
362
- * @see {@link Mocha.unloadFile}
363
- * @see {@link Mocha#loadFiles}
364
339
  * @see {@link Mocha#run}
365
340
  * @returns {Mocha} this
366
341
  * @chainable
@@ -404,7 +379,7 @@ Mocha.prototype.fgrep = function(str) {
404
379
  * <strong>Previous filter value will be overwritten on each call!</strong>
405
380
  *
406
381
  * @public
407
- * @see {@link /#grep-regexp-g-regexp|CLI option}
382
+ * @see [CLI option](../#-grep-regexp-g-regexp)
408
383
  * @see {@link Mocha#fgrep}
409
384
  * @see {@link Mocha#invert}
410
385
  * @param {RegExp|String} re - Regular expression used to select tests.
@@ -455,32 +430,32 @@ Mocha.prototype.invert = function() {
455
430
  /**
456
431
  * Enables or disables ignoring global leaks.
457
432
  *
433
+ * @deprecated since v7.0.0
458
434
  * @public
459
435
  * @see {@link Mocha#checkLeaks}
460
- * @param {boolean} ignoreLeaks - Whether to ignore global leaks.
436
+ * @param {boolean} [ignoreLeaks=false] - Whether to ignore global leaks.
461
437
  * @return {Mocha} this
462
438
  * @chainable
463
- * @example
464
- *
465
- * // Ignore global leaks
466
- * mocha.ignoreLeaks(true);
467
439
  */
468
440
  Mocha.prototype.ignoreLeaks = function(ignoreLeaks) {
469
- this.options.ignoreLeaks = Boolean(ignoreLeaks);
441
+ utils.deprecate(
442
+ '"ignoreLeaks()" is DEPRECATED, please use "checkLeaks()" instead.'
443
+ );
444
+ this.options.checkLeaks = !ignoreLeaks;
470
445
  return this;
471
446
  };
472
447
 
473
448
  /**
474
- * Enables checking for global variables leaked while running tests.
449
+ * Enables or disables checking for global variables leaked while running tests.
475
450
  *
476
451
  * @public
477
- * @see {@link /#-check-leaks|CLI option}
478
- * @see {@link Mocha#ignoreLeaks}
452
+ * @see [CLI option](../#-check-leaks)
453
+ * @param {boolean} [checkLeaks=true] - Whether to check for global variable leaks.
479
454
  * @return {Mocha} this
480
455
  * @chainable
481
456
  */
482
- Mocha.prototype.checkLeaks = function() {
483
- this.options.ignoreLeaks = false;
457
+ Mocha.prototype.checkLeaks = function(checkLeaks) {
458
+ this.options.checkLeaks = checkLeaks !== false;
484
459
  return this;
485
460
  };
486
461
 
@@ -488,11 +463,13 @@ Mocha.prototype.checkLeaks = function() {
488
463
  * Displays full stack trace upon test failure.
489
464
  *
490
465
  * @public
466
+ * @see [CLI option](../#-full-trace)
467
+ * @param {boolean} [fullTrace=true] - Whether to print full stacktrace upon failure.
491
468
  * @return {Mocha} this
492
469
  * @chainable
493
470
  */
494
- Mocha.prototype.fullTrace = function() {
495
- this.options.fullStackTrace = true;
471
+ Mocha.prototype.fullTrace = function(fullTrace) {
472
+ this.options.fullTrace = fullTrace !== false;
496
473
  return this;
497
474
  };
498
475
 
@@ -500,8 +477,7 @@ Mocha.prototype.fullTrace = function() {
500
477
  * Enables desktop notification support if prerequisite software installed.
501
478
  *
502
479
  * @public
503
- * @see {@link Mocha#isGrowlCapable}
504
- * @see {@link Mocha#_growl}
480
+ * @see [CLI option](../#-growl-g)
505
481
  * @return {Mocha} this
506
482
  * @chainable
507
483
  */
@@ -544,65 +520,121 @@ Mocha.prototype._growl = growl.notify;
544
520
  * Specifies whitelist of variable names to be expected in global scope.
545
521
  *
546
522
  * @public
547
- * @see {@link /#-global-variable-name|CLI option}
523
+ * @see [CLI option](../#-global-variable-name)
548
524
  * @see {@link Mocha#checkLeaks}
549
- * @param {String[]|String} globals - Accepted global variable name(s).
525
+ * @param {String[]|String} global - Accepted global variable name(s).
550
526
  * @return {Mocha} this
551
527
  * @chainable
552
528
  * @example
553
529
  *
554
530
  * // Specify variables to be expected in global scope
555
- * mocha.globals(['jQuery', 'MyLib']);
531
+ * mocha.global(['jQuery', 'MyLib']);
556
532
  */
557
- Mocha.prototype.globals = function(globals) {
558
- this.options.globals = this.options.globals
559
- .concat(globals)
533
+ Mocha.prototype.global = function(global) {
534
+ this.options.global = (this.options.global || [])
535
+ .concat(global)
560
536
  .filter(Boolean)
561
537
  .filter(function(elt, idx, arr) {
562
538
  return arr.indexOf(elt) === idx;
563
539
  });
564
540
  return this;
565
541
  };
542
+ // for backwards compability, 'globals' is an alias of 'global'
543
+ Mocha.prototype.globals = Mocha.prototype.global;
566
544
 
567
545
  /**
568
546
  * Enables or disables TTY color output by screen-oriented reporters.
569
547
  *
548
+ * @deprecated since v7.0.0
570
549
  * @public
550
+ * @see {@link Mocha#color}
571
551
  * @param {boolean} colors - Whether to enable color output.
572
552
  * @return {Mocha} this
573
553
  * @chainable
574
554
  */
575
555
  Mocha.prototype.useColors = function(colors) {
556
+ utils.deprecate('"useColors()" is DEPRECATED, please use "color()" instead.');
576
557
  if (colors !== undefined) {
577
- this.options.useColors = colors;
558
+ this.options.color = colors;
578
559
  }
579
560
  return this;
580
561
  };
581
562
 
563
+ /**
564
+ * Enables or disables TTY color output by screen-oriented reporters.
565
+ *
566
+ * @public
567
+ * @see [CLI option](../#-color-c-colors)
568
+ * @param {boolean} [color=true] - Whether to enable color output.
569
+ * @return {Mocha} this
570
+ * @chainable
571
+ */
572
+ Mocha.prototype.color = function(color) {
573
+ this.options.color = color !== false;
574
+ return this;
575
+ };
576
+
582
577
  /**
583
578
  * Determines if reporter should use inline diffs (rather than +/-)
584
579
  * in test failure output.
585
580
  *
581
+ * @deprecated since v7.0.0
586
582
  * @public
587
- * @param {boolean} inlineDiffs - Whether to use inline diffs.
583
+ * @see {@link Mocha#inlineDiffs}
584
+ * @param {boolean} [inlineDiffs=false] - Whether to use inline diffs.
588
585
  * @return {Mocha} this
589
586
  * @chainable
590
587
  */
591
588
  Mocha.prototype.useInlineDiffs = function(inlineDiffs) {
592
- this.options.useInlineDiffs = inlineDiffs !== undefined && inlineDiffs;
589
+ utils.deprecate(
590
+ '"useInlineDiffs()" is DEPRECATED, please use "inlineDiffs()" instead.'
591
+ );
592
+ this.options.inlineDiffs = inlineDiffs !== undefined && inlineDiffs;
593
+ return this;
594
+ };
595
+
596
+ /**
597
+ * Enables or disables reporter to use inline diffs (rather than +/-)
598
+ * in test failure output.
599
+ *
600
+ * @public
601
+ * @see [CLI option](../#-inline-diffs)
602
+ * @param {boolean} [inlineDiffs=true] - Whether to use inline diffs.
603
+ * @return {Mocha} this
604
+ * @chainable
605
+ */
606
+ Mocha.prototype.inlineDiffs = function(inlineDiffs) {
607
+ this.options.inlineDiffs = inlineDiffs !== false;
593
608
  return this;
594
609
  };
595
610
 
596
611
  /**
597
612
  * Determines if reporter should include diffs in test failure output.
598
613
  *
614
+ * @deprecated since v7.0.0
599
615
  * @public
600
- * @param {boolean} hideDiff - Whether to hide diffs.
616
+ * @see {@link Mocha#diff}
617
+ * @param {boolean} [hideDiff=false] - Whether to hide diffs.
601
618
  * @return {Mocha} this
602
619
  * @chainable
603
620
  */
604
621
  Mocha.prototype.hideDiff = function(hideDiff) {
605
- this.options.hideDiff = hideDiff !== undefined && hideDiff;
622
+ utils.deprecate('"hideDiff()" is DEPRECATED, please use "diff()" instead.');
623
+ this.options.diff = !(hideDiff === true);
624
+ return this;
625
+ };
626
+
627
+ /**
628
+ * Enables or disables reporter to include diff in test failure output.
629
+ *
630
+ * @public
631
+ * @see [CLI option](../#-diff)
632
+ * @param {boolean} [diff=true] - Whether to show diff on failure.
633
+ * @return {Mocha} this
634
+ * @chainable
635
+ */
636
+ Mocha.prototype.diff = function(diff) {
637
+ this.options.diff = diff !== false;
606
638
  return this;
607
639
  };
608
640
 
@@ -615,8 +647,8 @@ Mocha.prototype.hideDiff = function(hideDiff) {
615
647
  * If the value is `0`, timeouts will be disabled.
616
648
  *
617
649
  * @public
618
- * @see {@link /#-timeout-ms-t-ms|CLI option}
619
- * @see {@link /#timeouts|Timeouts}
650
+ * @see [CLI option](../#-timeout-ms-t-ms)
651
+ * @see [Timeouts](../#timeouts)
620
652
  * @see {@link Mocha#enableTimeouts}
621
653
  * @param {number|string} msecs - Timeout threshold value.
622
654
  * @return {Mocha} this
@@ -639,7 +671,8 @@ Mocha.prototype.timeout = function(msecs) {
639
671
  * Sets the number of times to retry failed tests.
640
672
  *
641
673
  * @public
642
- * @see {@link /#retry-tests|Retry Tests}
674
+ * @see [CLI option](../#-retries-n)
675
+ * @see [Retry Tests](../#retry-tests)
643
676
  * @param {number} retry - Number of times to retry failed tests.
644
677
  * @return {Mocha} this
645
678
  * @chainable
@@ -657,7 +690,7 @@ Mocha.prototype.retries = function(n) {
657
690
  * Sets slowness threshold value.
658
691
  *
659
692
  * @public
660
- * @see {@link /#-slow-ms-s-ms|CLI option}
693
+ * @see [CLI option](../#-slow-ms-s-ms)
661
694
  * @param {number} msecs - Slowness threshold value.
662
695
  * @return {Mocha} this
663
696
  * @chainable
@@ -679,7 +712,7 @@ Mocha.prototype.slow = function(msecs) {
679
712
  * Enables or disables timeouts.
680
713
  *
681
714
  * @public
682
- * @see {@link /#-timeout-ms-t-ms|CLI option}
715
+ * @see [CLI option](../#-timeout-ms-t-ms)
683
716
  * @param {boolean} enableTimeouts - Whether to enable timeouts.
684
717
  * @return {Mocha} this
685
718
  * @chainable
@@ -695,11 +728,13 @@ Mocha.prototype.enableTimeouts = function(enableTimeouts) {
695
728
  * Forces all tests to either accept a `done` callback or return a promise.
696
729
  *
697
730
  * @public
731
+ * @see [CLI option](../#-async-only-a)
732
+ * @param {boolean} [asyncOnly=true] - Wether to force `done` callback or promise.
698
733
  * @return {Mocha} this
699
734
  * @chainable
700
735
  */
701
- Mocha.prototype.asyncOnly = function() {
702
- this.options.asyncOnly = true;
736
+ Mocha.prototype.asyncOnly = function(asyncOnly) {
737
+ this.options.asyncOnly = asyncOnly !== false;
703
738
  return this;
704
739
  };
705
740
 
@@ -716,14 +751,16 @@ Mocha.prototype.noHighlighting = function() {
716
751
  };
717
752
 
718
753
  /**
719
- * Enables uncaught errors to propagate (in browser).
754
+ * Enables or disables uncaught errors to propagate.
720
755
  *
721
756
  * @public
757
+ * @see [CLI option](../#-allow-uncaught)
758
+ * @param {boolean} [allowUncaught=true] - Whether to propagate uncaught errors.
722
759
  * @return {Mocha} this
723
760
  * @chainable
724
761
  */
725
- Mocha.prototype.allowUncaught = function() {
726
- this.options.allowUncaught = true;
762
+ Mocha.prototype.allowUncaught = function(allowUncaught) {
763
+ this.options.allowUncaught = allowUncaught !== false;
727
764
  return this;
728
765
  };
729
766
 
@@ -735,7 +772,7 @@ Mocha.prototype.allowUncaught = function() {
735
772
  * Used to perform asynch operations before any suites are run.
736
773
  *
737
774
  * @public
738
- * @see {@link /#delayed-root-suite|delayed root suite}
775
+ * @see [delayed root suite](../#delayed-root-suite)
739
776
  * @returns {Mocha} this
740
777
  * @chainable
741
778
  */
@@ -748,11 +785,13 @@ Mocha.prototype.delay = function delay() {
748
785
  * Causes tests marked `only` to fail the suite.
749
786
  *
750
787
  * @public
788
+ * @see [CLI option](../#-forbid-only)
789
+ * @param {boolean} [forbidOnly=true] - Whether tests marked `only` fail the suite.
751
790
  * @returns {Mocha} this
752
791
  * @chainable
753
792
  */
754
- Mocha.prototype.forbidOnly = function() {
755
- this.options.forbidOnly = true;
793
+ Mocha.prototype.forbidOnly = function(forbidOnly) {
794
+ this.options.forbidOnly = forbidOnly !== false;
756
795
  return this;
757
796
  };
758
797
 
@@ -760,11 +799,13 @@ Mocha.prototype.forbidOnly = function() {
760
799
  * Causes pending tests and tests marked `skip` to fail the suite.
761
800
  *
762
801
  * @public
802
+ * @see [CLI option](../#-forbid-pending)
803
+ * @param {boolean} [forbidPending=true] - Whether pending tests fail the suite.
763
804
  * @returns {Mocha} this
764
805
  * @chainable
765
806
  */
766
- Mocha.prototype.forbidPending = function() {
767
- this.options.forbidPending = true;
807
+ Mocha.prototype.forbidPending = function(forbidPending) {
808
+ this.options.forbidPending = forbidPending !== false;
768
809
  return this;
769
810
  };
770
811
 
@@ -798,7 +839,6 @@ Object.defineProperty(Mocha.prototype, 'version', {
798
839
  * the cache first!
799
840
  *
800
841
  * @public
801
- * @see {@link Mocha#loadFiles}
802
842
  * @see {@link Mocha#unloadFiles}
803
843
  * @see {@link Runner#run}
804
844
  * @param {DoneCB} [fn] - Callback invoked when test execution completed.
@@ -814,8 +854,8 @@ Mocha.prototype.run = function(fn) {
814
854
  var runner = new exports.Runner(suite, options.delay);
815
855
  createStatsCollector(runner);
816
856
  var reporter = new this._reporter(runner, options);
817
- runner.ignoreLeaks = options.ignoreLeaks !== false;
818
- runner.fullStackTrace = options.fullStackTrace;
857
+ runner.checkLeaks = options.checkLeaks === true;
858
+ runner.fullStackTrace = options.fullTrace;
819
859
  runner.asyncOnly = options.asyncOnly;
820
860
  runner.allowUncaught = options.allowUncaught;
821
861
  runner.forbidOnly = options.forbidOnly;
@@ -823,17 +863,17 @@ Mocha.prototype.run = function(fn) {
823
863
  if (options.grep) {
824
864
  runner.grep(options.grep, options.invert);
825
865
  }
826
- if (options.globals) {
827
- runner.globals(options.globals);
866
+ if (options.global) {
867
+ runner.globals(options.global);
828
868
  }
829
869
  if (options.growl) {
830
870
  this._growl(runner);
831
871
  }
832
- if (options.useColors !== undefined) {
833
- exports.reporters.Base.useColors = options.useColors;
872
+ if (options.color !== undefined) {
873
+ exports.reporters.Base.useColors = options.color;
834
874
  }
835
- exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
836
- exports.reporters.Base.hideDiff = options.hideDiff;
875
+ exports.reporters.Base.inlineDiffs = options.inlineDiffs;
876
+ exports.reporters.Base.hideDiff = !options.diff;
837
877
 
838
878
  function done(failures) {
839
879
  fn = fn || utils.noop;
package/lib/mocharc.json CHANGED
@@ -6,5 +6,6 @@
6
6
  "reporter": "spec",
7
7
  "slow": 75,
8
8
  "timeout": 2000,
9
- "ui": "bdd"
9
+ "ui": "bdd",
10
+ "watch-ignore": ["node_modules", ".git"]
10
11
  }
@@ -154,14 +154,14 @@ exports.cursor = {
154
154
  }
155
155
  };
156
156
 
157
- function showDiff(err) {
157
+ var showDiff = (exports.showDiff = function(err) {
158
158
  return (
159
159
  err &&
160
160
  err.showDiff !== false &&
161
161
  sameType(err.actual, err.expected) &&
162
162
  err.expected !== undefined
163
163
  );
164
- }
164
+ });
165
165
 
166
166
  function stringifyDiffObjs(err) {
167
167
  if (!utils.isString(err.actual) || !utils.isString(err.expected)) {
@@ -182,9 +182,19 @@ function stringifyDiffObjs(err) {
182
182
  * @return {string} Diff
183
183
  */
184
184
  var generateDiff = (exports.generateDiff = function(actual, expected) {
185
- return exports.inlineDiffs
186
- ? inlineDiff(actual, expected)
187
- : unifiedDiff(actual, expected);
185
+ try {
186
+ return exports.inlineDiffs
187
+ ? inlineDiff(actual, expected)
188
+ : unifiedDiff(actual, expected);
189
+ } catch (err) {
190
+ var msg =
191
+ '\n ' +
192
+ color('diff added', '+ expected') +
193
+ ' ' +
194
+ color('diff removed', '- actual: failed to generate Mocha diff') +
195
+ '\n';
196
+ return msg;
197
+ }
188
198
  });
189
199
 
190
200
  /**
@@ -163,9 +163,9 @@ XUnit.prototype.test = function(test) {
163
163
  if (test.state === STATE_FAILED) {
164
164
  var err = test.err;
165
165
  var diff =
166
- Base.hideDiff || !err.actual || !err.expected
167
- ? ''
168
- : '\n' + Base.generateDiff(err.actual, err.expected);
166
+ !Base.hideDiff && Base.showDiff(err)
167
+ ? '\n' + Base.generateDiff(err.actual, err.expected)
168
+ : '';
169
169
  this.write(
170
170
  tag(
171
171
  'testcase',
package/lib/runnable.js CHANGED
@@ -135,7 +135,8 @@ Runnable.prototype.enableTimeouts = function(enabled) {
135
135
  * @public
136
136
  */
137
137
  Runnable.prototype.skip = function() {
138
- throw new Pending('sync skip');
138
+ this.pending = true;
139
+ throw new Pending('sync skip; aborting execution');
139
140
  };
140
141
 
141
142
  /**
@@ -334,43 +335,45 @@ Runnable.prototype.run = function(fn) {
334
335
  fn(err);
335
336
  }
336
337
 
337
- // for .resetTimeout()
338
+ // for .resetTimeout() and Runner#uncaught()
338
339
  this.callback = done;
339
340
 
341
+ if (this.fn && typeof this.fn.call !== 'function') {
342
+ done(
343
+ new TypeError(
344
+ 'A runnable must be passed a function as its second argument.'
345
+ )
346
+ );
347
+ return;
348
+ }
349
+
340
350
  // explicit async with `done` argument
341
351
  if (this.async) {
342
352
  this.resetTimeout();
343
353
 
344
354
  // allows skip() to be used in an explicit async context
345
355
  this.skip = function asyncSkip() {
346
- done(new Pending('async skip call'));
347
- // halt execution. the Runnable will be marked pending
348
- // by the previous call, and the uncaught handler will ignore
349
- // the failure.
356
+ this.pending = true;
357
+ done();
358
+ // halt execution, the uncaught handler will ignore the failure.
350
359
  throw new Pending('async skip; aborting execution');
351
360
  };
352
361
 
353
- if (this.allowUncaught) {
354
- return callFnAsync(this.fn);
355
- }
356
362
  try {
357
363
  callFnAsync(this.fn);
358
364
  } catch (err) {
365
+ // handles async runnables which actually run synchronously
359
366
  emitted = true;
367
+ if (err instanceof Pending) {
368
+ return; // done() is already called in this.skip()
369
+ } else if (this.allowUncaught) {
370
+ throw err;
371
+ }
360
372
  done(Runnable.toValueOrError(err));
361
373
  }
362
374
  return;
363
375
  }
364
376
 
365
- if (this.allowUncaught) {
366
- if (this.isPending()) {
367
- done();
368
- } else {
369
- callFn(this.fn);
370
- }
371
- return;
372
- }
373
-
374
377
  // sync or promise-returning
375
378
  try {
376
379
  if (this.isPending()) {
@@ -380,6 +383,11 @@ Runnable.prototype.run = function(fn) {
380
383
  }
381
384
  } catch (err) {
382
385
  emitted = true;
386
+ if (err instanceof Pending) {
387
+ return done();
388
+ } else if (this.allowUncaught) {
389
+ throw err;
390
+ }
383
391
  done(Runnable.toValueOrError(err));
384
392
  }
385
393