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/lib/runnable.js CHANGED
@@ -1,11 +1,11 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
5
4
 
6
5
  var EventEmitter = require('events').EventEmitter
7
6
  , debug = require('debug')('mocha:runnable')
8
- , milliseconds = require('./ms');
7
+ , milliseconds = require('./ms')
8
+ , utils = require('./utils');
9
9
 
10
10
  /**
11
11
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -46,6 +46,7 @@ function Runnable(title, fn) {
46
46
  this._slow = 75;
47
47
  this._enableTimeouts = true;
48
48
  this.timedOut = false;
49
+ this._trace = new Error('done() called multiple times')
49
50
  }
50
51
 
51
52
  /**
@@ -154,6 +155,7 @@ Runnable.prototype.resetTimeout = function(){
154
155
  if (!this._enableTimeouts) return;
155
156
  this.clearTimeout();
156
157
  this.timer = setTimeout(function(){
158
+ if (!self._enableTimeouts) return;
157
159
  self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
158
160
  self.timedOut = true;
159
161
  }, ms);
@@ -190,14 +192,14 @@ Runnable.prototype.run = function(fn){
190
192
  function multiple(err) {
191
193
  if (emitted) return;
192
194
  emitted = true;
193
- self.emit('error', err || new Error('done() called multiple times'));
195
+ self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate'));
194
196
  }
195
197
 
196
198
  // finished
197
199
  function done(err) {
198
200
  var ms = self.timeout();
199
201
  if (self.timedOut) return;
200
- if (finished) return multiple(err);
202
+ if (finished) return multiple(err || self._trace);
201
203
  self.clearTimeout();
202
204
  self.duration = new Date - start;
203
205
  finished = true;
@@ -225,7 +227,7 @@ Runnable.prototype.run = function(fn){
225
227
  done();
226
228
  });
227
229
  } catch (err) {
228
- done(err);
230
+ done(utils.getError(err));
229
231
  }
230
232
  return;
231
233
  }
@@ -242,7 +244,7 @@ Runnable.prototype.run = function(fn){
242
244
  callFn(this.fn);
243
245
  }
244
246
  } catch (err) {
245
- done(err);
247
+ done(utils.getError(err));
246
248
  }
247
249
 
248
250
  function callFn(fn) {
package/lib/runner.js CHANGED
@@ -19,7 +19,9 @@ var globals = [
19
19
  'setInterval',
20
20
  'clearInterval',
21
21
  'XMLHttpRequest',
22
- 'Date'
22
+ 'Date',
23
+ 'setImmediate',
24
+ 'clearImmediate'
23
25
  ];
24
26
 
25
27
  /**
@@ -244,7 +246,6 @@ Runner.prototype.hook = function(name, fn){
244
246
  function next(i) {
245
247
  var hook = hooks[i];
246
248
  if (!hook) return fn();
247
- if (self.failures && suite.bail()) return fn();
248
249
  self.currentRunnable = hook;
249
250
 
250
251
  hook.ctx.currentTest = self.test;
@@ -533,18 +534,25 @@ Runner.prototype.runSuite = function(suite, fn){
533
534
 
534
535
  Runner.prototype.uncaught = function(err){
535
536
  if (err) {
536
- debug('uncaught exception %s', err.message);
537
+ debug('uncaught exception %s', err !== function () {
538
+ return this;
539
+ }.call(err) ? err : ( err.message || err ));
537
540
  } else {
538
541
  debug('uncaught undefined exception');
539
- err = new Error('Catched undefined error, did you throw without specifying what?');
542
+ err = utils.undefinedError();
540
543
  }
541
-
542
- var runnable = this.currentRunnable;
543
- if (!runnable || 'failed' == runnable.state) return;
544
- runnable.clearTimeout();
545
544
  err.uncaught = true;
545
+
546
+ var runnable = this.currentRunnable;
547
+ if (!runnable) return;
548
+
549
+ var wasAlreadyDone = runnable.state;
546
550
  this.fail(runnable, err);
547
551
 
552
+ runnable.clearTimeout();
553
+
554
+ if (wasAlreadyDone) return;
555
+
548
556
  // recover from test
549
557
  if ('test' == runnable.type) {
550
558
  this.emit('test end', runnable);
@@ -604,7 +612,7 @@ Runner.prototype.run = function(fn){
604
612
  Runner.prototype.abort = function(){
605
613
  debug('aborting');
606
614
  this._abort = true;
607
- }
615
+ };
608
616
 
609
617
  /**
610
618
  * Filter leaks with the given globals flagged as `ok`.
package/lib/suite.js CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -99,6 +98,7 @@ Suite.prototype.clone = function(){
99
98
 
100
99
  Suite.prototype.timeout = function(ms){
101
100
  if (0 == arguments.length) return this._timeout;
101
+ if (ms.toString() === '0') this._enableTimeouts = false;
102
102
  if ('string' == typeof ms) ms = milliseconds(ms);
103
103
  debug('timeout %d', ms);
104
104
  this._timeout = parseInt(ms, 10);
@@ -118,7 +118,7 @@ Suite.prototype.enableTimeouts = function(enabled){
118
118
  debug('enableTimeouts %s', enabled);
119
119
  this._enableTimeouts = enabled;
120
120
  return this;
121
- }
121
+ };
122
122
 
123
123
  /**
124
124
  * Set slow `ms` or short-hand such as "2s".
@@ -139,7 +139,7 @@ Suite.prototype.slow = function(ms){
139
139
  /**
140
140
  * Sets whether to bail after first error.
141
141
  *
142
- * @parma {Boolean} bail
142
+ * @param {Boolean} bail
143
143
  * @return {Suite|Number} for chaining
144
144
  * @api private
145
145
  */
package/lib/test.js CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
package/lib/utils.js CHANGED
@@ -4,6 +4,9 @@
4
4
 
5
5
  var fs = require('fs')
6
6
  , path = require('path')
7
+ , basename = path.basename
8
+ , exists = fs.existsSync || path.existsSync
9
+ , glob = require('glob')
7
10
  , join = path.join
8
11
  , debug = require('debug')('mocha:watch');
9
12
 
@@ -224,18 +227,6 @@ exports.clean = function(str) {
224
227
  return exports.trim(str);
225
228
  };
226
229
 
227
- /**
228
- * Escape regular expression characters in `str`.
229
- *
230
- * @param {String} str
231
- * @return {String}
232
- * @api private
233
- */
234
-
235
- exports.escapeRegexp = function(str){
236
- return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
237
- };
238
-
239
230
  /**
240
231
  * Trim the given `str`.
241
232
  *
@@ -295,56 +286,263 @@ function highlight(js) {
295
286
  */
296
287
 
297
288
  exports.highlightTags = function(name) {
298
- var code = document.getElementsByTagName(name);
289
+ var code = document.getElementById('mocha').getElementsByTagName(name);
299
290
  for (var i = 0, len = code.length; i < len; ++i) {
300
291
  code[i].innerHTML = highlight(code[i].innerHTML);
301
292
  }
302
293
  };
303
294
 
295
+ /**
296
+ * If a value could have properties, and has none, this function is called, which returns
297
+ * a string representation of the empty value.
298
+ *
299
+ * Functions w/ no properties return `'[Function]'`
300
+ * Arrays w/ length === 0 return `'[]'`
301
+ * Objects w/ no properties return `'{}'`
302
+ * All else: return result of `value.toString()`
303
+ *
304
+ * @param {*} value Value to inspect
305
+ * @param {string} [type] The type of the value, if known.
306
+ * @returns {string}
307
+ */
308
+ var emptyRepresentation = function emptyRepresentation(value, type) {
309
+ type = type || exports.type(value);
310
+
311
+ switch(type) {
312
+ case 'function':
313
+ return '[Function]';
314
+ case 'object':
315
+ return '{}';
316
+ case 'array':
317
+ return '[]';
318
+ default:
319
+ return value.toString();
320
+ }
321
+ };
304
322
 
305
323
  /**
306
- * Stringify `obj`.
324
+ * Takes some variable and asks `{}.toString()` what it thinks it is.
325
+ * @param {*} value Anything
326
+ * @example
327
+ * type({}) // 'object'
328
+ * type([]) // 'array'
329
+ * type(1) // 'number'
330
+ * type(false) // 'boolean'
331
+ * type(Infinity) // 'number'
332
+ * type(null) // 'null'
333
+ * type(new Date()) // 'date'
334
+ * type(/foo/) // 'regexp'
335
+ * type('type') // 'string'
336
+ * type(global) // 'global'
337
+ * @api private
338
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
339
+ * @returns {string}
340
+ */
341
+ exports.type = function type(value) {
342
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
343
+ return 'buffer';
344
+ }
345
+ return Object.prototype.toString.call(value)
346
+ .replace(/^\[.+\s(.+?)\]$/, '$1')
347
+ .toLowerCase();
348
+ };
349
+
350
+ /**
351
+ * @summary Stringify `value`.
352
+ * @description Different behavior depending on type of value.
353
+ * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
354
+ * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
355
+ * - If `value` is an *empty* object, function, or array, return result of function
356
+ * {@link emptyRepresentation}.
357
+ * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
358
+ * JSON.stringify().
307
359
  *
308
- * @param {Object} obj
309
- * @return {String}
360
+ * @see exports.type
361
+ * @param {*} value
362
+ * @return {string}
310
363
  * @api private
311
364
  */
312
365
 
313
- exports.stringify = function(obj) {
314
- if (obj instanceof RegExp) return obj.toString();
315
- return JSON.stringify(exports.canonicalize(obj), null, 2).replace(/,(\n|$)/g, '$1');
316
- }
366
+ exports.stringify = function(value) {
367
+ var prop,
368
+ type = exports.type(value);
369
+
370
+ if (type === 'null' || type === 'undefined') {
371
+ return '[' + type + ']';
372
+ }
373
+
374
+ if (type === 'date') {
375
+ return '[Date: ' + value.toISOString() + ']';
376
+ }
377
+
378
+ if (!~exports.indexOf(['object', 'array', 'function'], type)) {
379
+ return value.toString();
380
+ }
381
+
382
+ for (prop in value) {
383
+ if (value.hasOwnProperty(prop)) {
384
+ return JSON.stringify(exports.canonicalize(value), null, 2).replace(/,(\n|$)/g, '$1');
385
+ }
386
+ }
387
+
388
+ return emptyRepresentation(value, type);
389
+ };
317
390
 
318
391
  /**
319
- * Return a new object that has the keys in sorted order.
320
- * @param {Object} obj
321
- * @return {Object}
392
+ * Return if obj is a Buffer
393
+ * @param {Object} arg
394
+ * @return {Boolean}
322
395
  * @api private
323
396
  */
397
+ exports.isBuffer = function (arg) {
398
+ return typeof Buffer !== 'undefined' && Buffer.isBuffer(arg);
399
+ };
400
+
401
+ /**
402
+ * @summary Return a new Thing that has the keys in sorted order. Recursive.
403
+ * @description If the Thing...
404
+ * - has already been seen, return string `'[Circular]'`
405
+ * - is `undefined`, return string `'[undefined]'`
406
+ * - is `null`, return value `null`
407
+ * - is some other primitive, return the value
408
+ * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
409
+ * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
410
+ * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
411
+ *
412
+ * @param {*} value Thing to inspect. May or may not have properties.
413
+ * @param {Array} [stack=[]] Stack of seen values
414
+ * @return {(Object|Array|Function|string|undefined)}
415
+ * @see {@link exports.stringify}
416
+ * @api private
417
+ */
418
+
419
+ exports.canonicalize = function(value, stack) {
420
+ var canonicalizedObj,
421
+ type = exports.type(value),
422
+ prop,
423
+ withStack = function withStack(value, fn) {
424
+ stack.push(value);
425
+ fn();
426
+ stack.pop();
427
+ };
428
+
429
+ stack = stack || [];
430
+
431
+ if (exports.indexOf(stack, value) !== -1) {
432
+ return '[Circular]';
433
+ }
434
+
435
+ switch(type) {
436
+ case 'undefined':
437
+ canonicalizedObj = '[undefined]';
438
+ break;
439
+ case 'buffer':
440
+ case 'null':
441
+ canonicalizedObj = value;
442
+ break;
443
+ case 'array':
444
+ withStack(value, function () {
445
+ canonicalizedObj = exports.map(value, function (item) {
446
+ return exports.canonicalize(item, stack);
447
+ });
448
+ });
449
+ break;
450
+ case 'date':
451
+ canonicalizedObj = '[Date: ' + value.toISOString() + ']';
452
+ break;
453
+ case 'function':
454
+ for (prop in value) {
455
+ canonicalizedObj = {};
456
+ break;
457
+ }
458
+ if (!canonicalizedObj) {
459
+ canonicalizedObj = emptyRepresentation(value, type);
460
+ break;
461
+ }
462
+ /* falls through */
463
+ case 'object':
464
+ canonicalizedObj = canonicalizedObj || {};
465
+ withStack(value, function () {
466
+ exports.forEach(exports.keys(value).sort(), function (key) {
467
+ canonicalizedObj[key] = exports.canonicalize(value[key], stack);
468
+ });
469
+ });
470
+ break;
471
+ case 'number':
472
+ case 'boolean':
473
+ canonicalizedObj = value;
474
+ break;
475
+ default:
476
+ canonicalizedObj = value.toString();
477
+ }
478
+
479
+ return canonicalizedObj;
480
+ };
481
+
482
+ /**
483
+ * Lookup file names at the given `path`.
484
+ */
485
+ exports.lookupFiles = function lookupFiles(path, extensions, recursive) {
486
+ var files = [];
487
+ var re = new RegExp('\\.(' + extensions.join('|') + ')$');
488
+
489
+ if (!exists(path)) {
490
+ if (exists(path + '.js')) {
491
+ path += '.js';
492
+ } else {
493
+ files = glob.sync(path);
494
+ if (!files.length) throw new Error("cannot resolve path (or pattern) '" + path + "'");
495
+ return files;
496
+ }
497
+ }
498
+
499
+ try {
500
+ var stat = fs.statSync(path);
501
+ if (stat.isFile()) return path;
502
+ }
503
+ catch (ignored) {
504
+ return;
505
+ }
506
+
507
+ fs.readdirSync(path).forEach(function(file){
508
+ file = join(path, file);
509
+ try {
510
+ var stat = fs.statSync(file);
511
+ if (stat.isDirectory()) {
512
+ if (recursive) {
513
+ files = files.concat(lookupFiles(file, extensions, recursive));
514
+ }
515
+ return;
516
+ }
517
+ }
518
+ catch (ignored) {
519
+ return;
520
+ }
521
+ if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') return;
522
+ files.push(file);
523
+ });
524
+
525
+ return files;
526
+ };
527
+
528
+ /**
529
+ * Generate an undefined error with a message warning the user.
530
+ *
531
+ * @return {Error}
532
+ */
533
+
534
+ exports.undefinedError = function(){
535
+ return new Error('Caught undefined error, did you throw without specifying what?');
536
+ };
537
+
538
+ /**
539
+ * Generate an undefined error if `err` is not defined.
540
+ *
541
+ * @param {Error} err
542
+ * @return {Error}
543
+ */
544
+
545
+ exports.getError = function(err){
546
+ return err || exports.undefinedError();
547
+ };
324
548
 
325
- exports.canonicalize = function(obj, stack) {
326
- stack = stack || [];
327
-
328
- if (exports.indexOf(stack, obj) !== -1) return '[Circular]';
329
-
330
- var canonicalizedObj;
331
-
332
- if ({}.toString.call(obj) === '[object Array]') {
333
- stack.push(obj);
334
- canonicalizedObj = exports.map(obj, function(item) {
335
- return exports.canonicalize(item, stack);
336
- });
337
- stack.pop();
338
- } else if (typeof obj === 'object' && obj !== null) {
339
- stack.push(obj);
340
- canonicalizedObj = {};
341
- exports.forEach(exports.keys(obj).sort(), function(key) {
342
- canonicalizedObj[key] = exports.canonicalize(obj[key], stack);
343
- });
344
- stack.pop();
345
- } else {
346
- canonicalizedObj = obj;
347
- }
348
-
349
- return canonicalizedObj;
350
- }