From 42385648e953c9b008cf258102dedf26669c61cc Mon Sep 17 00:00:00 2001 From: Nathan Houle Date: Mon, 15 Jun 2015 21:18:01 -0700 Subject: [PATCH 1/4] Linting: Add linter Follows @boneskull's `make test` suggestion in https://github.com/mochajs/mocha/pull/1534#issuecomment-73151037 --- .eslintrc | 131 +++++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 6 ++- bin/.eslintrc | 3 ++ package.json | 1 + test/.eslintrc | 3 ++ 5 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 .eslintrc create mode 100644 bin/.eslintrc create mode 100644 test/.eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000000..2e572a69ad --- /dev/null +++ b/.eslintrc @@ -0,0 +1,131 @@ +--- +env: + node: true + +rules: + brace-style: [2, 1tbs] + camelcase: 2 + comma-dangle: [2, never] + comma-spacing: [2, {before: false, after: true}] + comma-style: [2, last] + computed-property-spacing: [2, never] + consistent-return: 0 + consistent-this: [1, self] + curly: [2, all] + default-case: 2 + dot-location: [2, property] + dot-notation: [2, { allowKeywords: true }] + eol-last: 2 + eqeqeq: 2 + func-style: [2, declaration] + guard-for-in: 2 # TODO: Change to error + handle-callback-err: [2, ^(err|error)$] + indent: [2, 2] + key-spacing: [2, { beforeColon: false, afterColon: true }] + max-len: [0, 80, 2] # TODO: Change to error + max-params: [1, 4] + new-cap: 0 # TODO: Change to error + new-parens: 2 + no-alert: 2 + no-array-constructor: 0 + no-bitwise: 0 + no-caller: 2 + no-catch-shadow: 2 + no-cond-assign: [1, except-parens] # TODO: Change to error + no-console: 0 + no-constant-condition: 0 + no-control-regex: 2 + no-debugger: 1 + no-delete-var: 2 + no-dupe-args: 2 + no-dupe-keys: 2 + no-duplicate-case: 2 + no-else-return: 2 + no-empty: 2 + no-empty-character-class: 2 + no-eq-null: 0 + no-eval: 2 + no-ex-assign: 2 + no-extend-native: 2 + no-extra-bind: 2 + no-extra-boolean-cast: 2 + no-extra-semi: 2 + no-fallthrough: 2 + no-floating-decimal: 0 + no-func-assign: 2 + no-implied-eval: 2 + no-inner-declarations: [2, functions] + no-invalid-regexp: 2 + no-irregular-whitespace: 2 + no-iterator: 2 + no-labels: 2 + no-lone-blocks: 2 + no-lonely-if: 2 + no-loop-func: 2 + no-mixed-requires: [0, false] + no-mixed-spaces-and-tabs: [2, false] + no-multi-spaces: 2 + no-multi-str: 2 + no-multiple-empty-lines: [2, { max: 1 }] + no-native-reassign: 2 + no-negated-in-lhs: 2 + no-nested-ternary: 2 + no-new: 2 + no-new-func: 2 + no-new-object: 2 + no-new-require: 2 + no-new-wrappers: 2 + no-obj-calls: 2 + no-octal: 2 + no-octal-escape: 2 + no-path-concat: 2 + no-process-exit: 2 + no-proto: 1 # TODO: Change to error + no-redeclare: 2 + no-regex-spaces: 2 + no-reserved-keys: 2 + no-return-assign: 2 + no-script-url: 2 + no-self-compare: 2 + no-sequences: 2 + no-shadow: 0 + no-shadow-restricted-names: 2 + no-spaced-func: 2 + no-sparse-arrays: 2 + no-trailing-spaces: 2 + no-undef: 2 + no-undef-init: 2 + no-underscore-dangle: 0 # TODO: Change to error + no-unneeded-ternary: 2 + no-unreachable: 2 + no-unused-expressions: 0 + no-unused-vars: [2, { vars: all, args: after-used }] + no-use-before-define: 0 + no-void: 2 + no-with: 2 + object-curly-spacing: [2, always] + one-var: [2, never] + operator-assignment: [2, always] + operator-linebreak: [2, before] + padded-blocks: [2, never] + quote-props: [2, as-needed] + quotes: [2, single, avoid-escape] + radix: 2 + semi: [2, always] + semi-spacing: [2, { before: false, after: true }] + space-after-keywords: [2, always] + space-before-blocks: [2, always] + space-before-function-paren: [2, never] + space-in-parens: [2, never] + space-infix-ops: 2 + space-return-throw-case: 2 + space-unary-ops: [2, { words: true, nonwords: false }] + spaced-line-comment: 2 + strict: [0, global] # TODO: Change to error + use-isnan: 2 + valid-jsdoc: [0, { requireReturn: false }] # TODO: Change to warning + valid-typeof: 2 + vars-on-top: 0 + wrap-iife: 2 + wrap-regex: 2 + yoda: [2, never] diff --git a/Makefile b/Makefile index cde16486a1..d359b3e79f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ +ESLINT := node_modules/.bin/eslint REPORTER ?= spec TM_BUNDLE = JavaScript\ mocha.tmbundle SRC = $(shell find lib -name "*.js" -type f | sort) @@ -34,7 +35,10 @@ lib-cov: @rm -fr ./$@ @jscoverage lib $@ -test: test-unit +lint: + @$(ESLINT) --reset $(SRC) + +test: lint test-unit test-all: test-bdd test-tdd test-qunit test-exports test-unit test-integration test-jsapi test-compilers test-glob test-requires test-reporters test-only diff --git a/bin/.eslintrc b/bin/.eslintrc new file mode 100644 index 0000000000..db7424631c --- /dev/null +++ b/bin/.eslintrc @@ -0,0 +1,3 @@ +--- +rules: + no-process-exit: 0 diff --git a/package.json b/package.json index d5571824ce..b3ab7097cc 100644 --- a/package.json +++ b/package.json @@ -288,6 +288,7 @@ }, "devDependencies": { "coffee-script": "~1.8.0", + "eslint": "~0.23.0", "should": "~4.0.0" }, "files": [ diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100644 index 0000000000..6db2a46c53 --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,3 @@ +--- +env: + mocha: true From 3f78f10ca40dba63be10454c8e17dc9586416e10 Mon Sep 17 00:00:00 2001 From: Nathan Houle Date: Tue, 16 Jun 2015 11:55:48 -0700 Subject: [PATCH 2/4] Linting: Compliance --- .eslintrc | 2 +- lib/browser/debug.js | 6 +- lib/browser/escape-string-regexp.js | 16 +- lib/browser/events.js | 68 +++-- lib/browser/progress.js | 82 +++--- lib/browser/tty.js | 9 +- lib/context.js | 58 ++-- lib/hook.js | 9 +- lib/interfaces/bdd.js | 47 ++-- lib/interfaces/common.js | 48 +++- lib/interfaces/exports.js | 14 +- lib/interfaces/qunit.js | 33 ++- lib/interfaces/tdd.js | 52 ++-- lib/mocha.js | 255 +++++++++-------- lib/ms.js | 67 +++-- lib/pending.js | 5 +- lib/reporters/base.js | 284 ++++++++++--------- lib/reporters/doc.js | 26 +- lib/reporters/dot.js | 38 +-- lib/reporters/html-cov.js | 44 +-- lib/reporters/html.js | 194 +++++++------ lib/reporters/json-cov.js | 80 +++--- lib/reporters/json-stream.js | 30 +- lib/reporters/json.js | 35 ++- lib/reporters/landing.js | 40 ++- lib/reporters/list.js | 26 +- lib/reporters/markdown.js | 37 ++- lib/reporters/min.js | 5 +- lib/reporters/nyan.js | 85 +++--- lib/reporters/progress.js | 39 ++- lib/reporters/spec.js | 41 +-- lib/reporters/tap.js | 34 +-- lib/reporters/xunit.js | 133 +++++---- lib/runnable.js | 195 +++++++------ lib/runner.js | 387 ++++++++++++++------------ lib/suite.js | 196 ++++++------- lib/template.html | 2 +- lib/test.js | 3 +- lib/utils.js | 410 +++++++++++++++------------- 39 files changed, 1665 insertions(+), 1470 deletions(-) diff --git a/.eslintrc b/.eslintrc index 2e572a69ad..a89b22b26a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,7 +14,7 @@ rules: curly: [2, all] default-case: 2 dot-location: [2, property] - dot-notation: [2, { allowKeywords: true }] + dot-notation: [2, { allowKeywords: true, allowPattern: "^long$" }] eol-last: 2 eqeqeq: 2 func-style: [2, declaration] diff --git a/lib/browser/debug.js b/lib/browser/debug.js index 0d939e5c07..ba232896df 100644 --- a/lib/browser/debug.js +++ b/lib/browser/debug.js @@ -1,4 +1,4 @@ -module.exports = function(type){ - return function(){ - } +/* eslint-disable no-unused-vars */ +module.exports = function(type) { + return function() {}; }; diff --git a/lib/browser/escape-string-regexp.js b/lib/browser/escape-string-regexp.js index 21a95663ed..02ea365619 100644 --- a/lib/browser/escape-string-regexp.js +++ b/lib/browser/escape-string-regexp.js @@ -1,11 +1,21 @@ 'use strict'; +/** + * Expose `escape`. + */ + +module.exports = escape; + var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; -module.exports = function (str) { +/** + * @param {string} str + * @return {string} + */ +function escape(str) { if (typeof str !== 'string') { throw new TypeError('Expected a string'); } - return str.replace(matchOperatorsRe, '\\$&'); -}; + return str.replace(matchOperatorsRe, '\\$&'); +} diff --git a/lib/browser/events.js b/lib/browser/events.js index f708260896..314016910b 100644 --- a/lib/browser/events.js +++ b/lib/browser/events.js @@ -5,11 +5,19 @@ exports.EventEmitter = EventEmitter; /** - * Check if `obj` is an array. + * Object#hasOwnProperty reference. */ +var objToString = Object.prototype.toString; -function isArray(obj) { - return '[object Array]' == {}.toString.call(obj); +/** + * Check if a value is an array. + * + * @api private + * @param {*} val The value to test. + * @return {boolean} true if the value is a boolean, otherwise false. + */ +function isArray(val) { + return objToString.call(val) === '[object Array]'; } /** @@ -17,16 +25,17 @@ function isArray(obj) { * * @api public */ - -function EventEmitter(){}; +function EventEmitter() {} /** - * Adds a listener. + * Add a listener. * * @api public + * @param {string} name Event name. + * @param {Function} fn Event handler. + * @return {EventEmitter} Emitter instance. */ - -EventEmitter.prototype.on = function (name, fn) { +EventEmitter.prototype.on = function(name, fn) { if (!this.$events) { this.$events = {}; } @@ -48,15 +57,17 @@ EventEmitter.prototype.addListener = EventEmitter.prototype.on; * Adds a volatile listener. * * @api public + * @param {string} name Event name. + * @param {Function} fn Event handler. + * @return {EventEmitter} Emitter instance. */ - -EventEmitter.prototype.once = function (name, fn) { +EventEmitter.prototype.once = function(name, fn) { var self = this; - function on () { + function on() { self.removeListener(name, on); fn.apply(this, arguments); - }; + } on.listener = fn; this.on(name, on); @@ -65,12 +76,14 @@ EventEmitter.prototype.once = function (name, fn) { }; /** - * Removes a listener. + * Remove a listener. * * @api public + * @param {string} name Event name. + * @param {Function} fn Event handler. + * @return {EventEmitter} Emitter instance. */ - -EventEmitter.prototype.removeListener = function (name, fn) { +EventEmitter.prototype.removeListener = function(name, fn) { if (this.$events && this.$events[name]) { var list = this.$events[name]; @@ -102,12 +115,13 @@ EventEmitter.prototype.removeListener = function (name, fn) { }; /** - * Removes all listeners for an event. + * Remove all listeners for an event. * * @api public + * @param {string} name Event name. + * @return {EventEmitter} Emitter instance. */ - -EventEmitter.prototype.removeAllListeners = function (name) { +EventEmitter.prototype.removeAllListeners = function(name) { if (name === undefined) { this.$events = {}; return this; @@ -121,12 +135,13 @@ EventEmitter.prototype.removeAllListeners = function (name) { }; /** - * Gets all listeners for a certain event. + * Get all listeners for a given event. * * @api public + * @param {string} name Event name. + * @return {EventEmitter} Emitter instance. */ - -EventEmitter.prototype.listeners = function (name) { +EventEmitter.prototype.listeners = function(name) { if (!this.$events) { this.$events = {}; } @@ -143,12 +158,13 @@ EventEmitter.prototype.listeners = function (name) { }; /** - * Emits an event. + * Emit an event. * * @api public + * @param {string} name Event name. + * @return {boolean} true if at least one handler was invoked, else false. */ - -EventEmitter.prototype.emit = function (name) { +EventEmitter.prototype.emit = function(name) { if (!this.$events) { return false; } @@ -159,9 +175,9 @@ EventEmitter.prototype.emit = function (name) { return false; } - var args = [].slice.call(arguments, 1); + var args = Array.prototype.slice.call(arguments, 1); - if ('function' == typeof handler) { + if (typeof handler === 'function') { handler.apply(this, args); } else if (isArray(handler)) { var listeners = handler.slice(); diff --git a/lib/browser/progress.js b/lib/browser/progress.js index b30e5179ea..3186b6ec50 100644 --- a/lib/browser/progress.js +++ b/lib/browser/progress.js @@ -7,7 +7,6 @@ module.exports = Progress; /** * Initialize a new `Progress` indicator. */ - function Progress() { this.percent = 0; this.size(0); @@ -16,52 +15,48 @@ function Progress() { } /** - * Set progress size to `n`. + * Set progress size to `size`. * - * @param {Number} n - * @return {Progress} for chaining * @api public + * @param {number} size + * @return {Progress} Progress instance. */ - -Progress.prototype.size = function(n){ - this._size = n; +Progress.prototype.size = function(size) { + this._size = size; return this; }; /** - * Set text to `str`. + * Set text to `text`. * - * @param {String} str - * @return {Progress} for chaining * @api public + * @param {string} text + * @return {Progress} Progress instance. */ - -Progress.prototype.text = function(str){ - this._text = str; +Progress.prototype.text = function(text) { + this._text = text; return this; }; /** - * Set font size to `n`. + * Set font size to `size`. * - * @param {Number} n - * @return {Progress} for chaining * @api public + * @param {number} size + * @return {Progress} Progress instance. */ - -Progress.prototype.fontSize = function(n){ - this._fontSize = n; +Progress.prototype.fontSize = function(size) { + this._fontSize = size; return this; }; /** - * Set font `family`. + * Set font to `family`. * - * @param {String} family - * @return {Progress} for chaining + * @param {string} family + * @return {Progress} Progress instance. */ - -Progress.prototype.font = function(family){ +Progress.prototype.font = function(family) { this._font = family; return this; }; @@ -69,11 +64,10 @@ Progress.prototype.font = function(family){ /** * Update percentage to `n`. * - * @param {Number} n - * @return {Progress} for chaining + * @param {number} n + * @return {Progress} Progress instance. */ - -Progress.prototype.update = function(n){ +Progress.prototype.update = function(n) { this.percent = n; return this; }; @@ -82,18 +76,17 @@ Progress.prototype.update = function(n){ * Draw on `ctx`. * * @param {CanvasRenderingContext2d} ctx - * @return {Progress} for chaining + * @return {Progress} Progress instance. */ - -Progress.prototype.draw = function(ctx){ +Progress.prototype.draw = function(ctx) { try { - var percent = Math.min(this.percent, 100) - , size = this._size - , half = size / 2 - , x = half - , y = half - , rad = half - 1 - , fontSize = this._fontSize; + var percent = Math.min(this.percent, 100); + var size = this._size; + var half = size / 2; + var x = half; + var y = half; + var rad = half - 1; + var fontSize = this._fontSize; ctx.font = fontSize + 'px ' + this._font; @@ -113,13 +106,12 @@ Progress.prototype.draw = function(ctx){ ctx.stroke(); // text - var text = this._text || (percent | 0) + '%' - , w = ctx.measureText(text).width; + var text = this._text || (percent | 0) + '%'; + var w = ctx.measureText(text).width; - ctx.fillText( - text - , x - w / 2 + 1 - , y + fontSize / 2 - 1); - } catch (ex) {} //don't fail if we can't render progress + ctx.fillText(text, x - w / 2 + 1, y + fontSize / 2 - 1); + } catch (err) { + // don't fail if we can't render progress + } return this; }; diff --git a/lib/browser/tty.js b/lib/browser/tty.js index eab6388270..840d6699ee 100644 --- a/lib/browser/tty.js +++ b/lib/browser/tty.js @@ -1,12 +1,11 @@ -exports.isatty = function(){ +exports.isatty = function isatty() { return true; }; -exports.getWindowSize = function(){ +exports.getWindowSize = function getWindowSize() { if ('innerHeight' in global) { return [global.innerHeight, global.innerWidth]; - } else { - // In a Web Worker, the DOM Window is not available. - return [640, 480]; } + // In a Web Worker, the DOM Window is not available. + return [640, 480]; }; diff --git a/lib/context.js b/lib/context.js index 3885218db9..0b0242fee1 100644 --- a/lib/context.js +++ b/lib/context.js @@ -9,19 +9,19 @@ module.exports = Context; * * @api private */ - -function Context(){} +function Context() {} /** * Set or get the context `Runnable` to `runnable`. * + * @api private * @param {Runnable} runnable * @return {Context} - * @api private */ - -Context.prototype.runnable = function(runnable){ - if (0 == arguments.length) return this._runnable; +Context.prototype.runnable = function(runnable) { + if (!arguments.length) { + return this._runnable; + } this.test = this._runnable = runnable; return this; }; @@ -29,13 +29,14 @@ Context.prototype.runnable = function(runnable){ /** * Set test timeout `ms`. * - * @param {Number} ms - * @return {Context} self * @api private + * @param {number} ms + * @return {Context} self */ - -Context.prototype.timeout = function(ms){ - if (arguments.length === 0) return this.runnable().timeout(); +Context.prototype.timeout = function(ms) { + if (!arguments.length) { + return this.runnable().timeout(); + } this.runnable().timeout(ms); return this; }; @@ -43,26 +44,23 @@ Context.prototype.timeout = function(ms){ /** * Set test timeout `enabled`. * - * @param {Boolean} enabled - * @return {Context} self * @api private + * @param {boolean} enabled + * @return {Context} self */ - -Context.prototype.enableTimeouts = function (enabled) { +Context.prototype.enableTimeouts = function(enabled) { this.runnable().enableTimeouts(enabled); return this; }; - /** * Set test slowness threshold `ms`. * - * @param {Number} ms - * @return {Context} self * @api private + * @param {number} ms + * @return {Context} self */ - -Context.prototype.slow = function(ms){ +Context.prototype.slow = function(ms) { this.runnable().slow(ms); return this; }; @@ -70,26 +68,22 @@ Context.prototype.slow = function(ms){ /** * Mark a test as skipped. * - * @return {Context} self * @api private + * @return {Context} self */ - -Context.prototype.skip = function(){ - this.runnable().skip(); - return this; +Context.prototype.skip = function() { + this.runnable().skip(); + return this; }; /** * Inspect the context void of `._runnable`. * - * @return {String} * @api private + * @return {string} */ - -Context.prototype.inspect = function(){ - return JSON.stringify(this, function(key, val){ - if ('_runnable' == key) return; - if ('test' == key) return; - return val; +Context.prototype.inspect = function() { + return JSON.stringify(this, function(key, val) { + return key === 'runnable' || key === 'test' ? undefined : val; }, 2); }; diff --git a/lib/hook.js b/lib/hook.js index c2dc346b44..3dec54b795 100644 --- a/lib/hook.js +++ b/lib/hook.js @@ -17,7 +17,6 @@ module.exports = Hook; * @param {Function} fn * @api private */ - function Hook(title, fn) { Runnable.call(this, title, fn); this.type = 'hook'; @@ -26,7 +25,6 @@ function Hook(title, fn) { /** * Inherit from `Runnable.prototype`. */ - Hook.prototype.__proto__ = Runnable.prototype; /** @@ -36,10 +34,9 @@ Hook.prototype.__proto__ = Runnable.prototype; * @return {Error} * @api public */ - -Hook.prototype.error = function(err){ - if (0 == arguments.length) { - var err = this._error; +Hook.prototype.error = function(err) { + if (!arguments.length) { + err = this._error; this._error = null; return err; } diff --git a/lib/interfaces/bdd.js b/lib/interfaces/bdd.js index f9f08a3ed0..253f24e488 100644 --- a/lib/interfaces/bdd.js +++ b/lib/interfaces/bdd.js @@ -2,33 +2,31 @@ * Module dependencies. */ -var Suite = require('../suite') - , Test = require('../test') - , utils = require('../utils') - , escapeRe = require('escape-string-regexp'); +var Suite = require('../suite'); +var Test = require('../test'); +var escapeRe = require('escape-string-regexp'); /** * BDD-style interface: * - * describe('Array', function(){ - * describe('#indexOf()', function(){ - * it('should return -1 when not present', function(){ - * + * describe('Array', function() { + * describe('#indexOf()', function() { + * it('should return -1 when not present', function() { + * // ... * }); * - * it('should return the index when present', function(){ - * + * it('should return the index when present', function() { + * // ... * }); * }); * }); * + * @param {Suite} suite Root suite. */ - -module.exports = function(suite){ +module.exports = function(suite) { var suites = [suite]; - suite.on('pre-require', function(context, file, mocha){ - + suite.on('pre-require', function(context, file, mocha) { var common = require('./common')(suites, context); context.before = common.before; @@ -42,7 +40,7 @@ module.exports = function(suite){ * and/or tests. */ - context.describe = context.context = function(title, fn){ + context.describe = context.context = function(title, fn) { var suite = Suite.create(suites[0], title); suite.file = file; suites.unshift(suite); @@ -55,9 +53,7 @@ module.exports = function(suite){ * Pending describe. */ - context.xdescribe = - context.xcontext = - context.describe.skip = function(title, fn){ + context.xdescribe = context.xcontext = context.describe.skip = function(title, fn) { var suite = Suite.create(suites[0], title); suite.pending = true; suites.unshift(suite); @@ -69,7 +65,7 @@ module.exports = function(suite){ * Exclusive suite. */ - context.describe.only = function(title, fn){ + context.describe.only = function(title, fn) { var suite = context.describe(title, fn); mocha.grep(suite.fullTitle()); return suite; @@ -81,9 +77,11 @@ module.exports = function(suite){ * acting as a thunk. */ - context.it = context.specify = function(title, fn){ + context.it = context.specify = function(title, fn) { var suite = suites[0]; - if (suite.pending) fn = null; + if (suite.pending) { + fn = null; + } var test = new Test(title, fn); test.file = file; suite.addTest(test); @@ -94,7 +92,7 @@ module.exports = function(suite){ * Exclusive test-case. */ - context.it.only = function(title, fn){ + context.it.only = function(title, fn) { var test = context.it(title, fn); var reString = '^' + escapeRe(test.fullTitle()) + '$'; mocha.grep(new RegExp(reString)); @@ -105,11 +103,8 @@ module.exports = function(suite){ * Pending test case. */ - context.xit = - context.xspecify = - context.it.skip = function(title){ + context.xit = context.xspecify = context.it.skip = function(title) { context.it(title); }; - }); }; diff --git a/lib/interfaces/common.js b/lib/interfaces/common.js index 1ccd3390f7..4a21c16c69 100644 --- a/lib/interfaces/common.js +++ b/lib/interfaces/common.js @@ -1,16 +1,20 @@ -/** - * Functions common to more than one interface - * @module lib/interfaces/common - */ - 'use strict'; -module.exports = function (suites, context) { - +/** + * Functions common to more than one interface. + * + * @param {Suite[]} suites + * @param {Context} context + * @return {Object} An object containing common functions. + */ +module.exports = function(suites, context) { return { /** - * This is only present if flag --delay is passed into Mocha. It triggers - * root suite execution. Returns a function which runs the root suite. + * This is only present if flag --delay is passed into Mocha. It triggers + * root suite execution. + * + * @param {Suite} suite The root wuite. + * @return {Function} A function which runs the root suite */ runWithSuite: function runWithSuite(suite) { return function run() { @@ -20,39 +24,53 @@ module.exports = function (suites, context) { /** * Execute before running tests. + * + * @param {string} name + * @param {Function} fn */ - before: function (name, fn) { + before: function(name, fn) { suites[0].beforeAll(name, fn); }, /** * Execute after running tests. + * + * @param {string} name + * @param {Function} fn */ - after: function (name, fn) { + after: function(name, fn) { suites[0].afterAll(name, fn); }, /** * Execute before each test case. + * + * @param {string} name + * @param {Function} fn */ - beforeEach: function (name, fn) { + beforeEach: function(name, fn) { suites[0].beforeEach(name, fn); }, /** * Execute after each test case. + * + * @param {string} name + * @param {Function} fn */ - afterEach: function (name, fn) { + afterEach: function(name, fn) { suites[0].afterEach(name, fn); }, test: { /** * Pending test case. + * + * @param {string} title */ - skip: function (title) { + skip: function(title) { context.test(title); } } - } + }; }; diff --git a/lib/interfaces/exports.js b/lib/interfaces/exports.js index 95e8a07012..a64692ae5c 100644 --- a/lib/interfaces/exports.js +++ b/lib/interfaces/exports.js @@ -2,27 +2,27 @@ * Module dependencies. */ -var Suite = require('../suite') - , Test = require('../test'); +var Suite = require('../suite'); +var Test = require('../test'); /** * TDD-style interface: * * exports.Array = { * '#indexOf()': { - * 'should return -1 when the value is not present': function(){ + * 'should return -1 when the value is not present': function() { * * }, * - * 'should return the correct index when the value is present': function(){ + * 'should return the correct index when the value is present': function() { * * } * } * }; * + * @param {Suite} suite Root suite. */ - -module.exports = function(suite){ +module.exports = function(suite) { var suites = [suite]; suite.on('require', visit); @@ -30,7 +30,7 @@ module.exports = function(suite){ function visit(obj, file) { var suite; for (var key in obj) { - if ('function' == typeof obj[key]) { + if (typeof obj[key] === 'function') { var fn = obj[key]; switch (key) { case 'before': diff --git a/lib/interfaces/qunit.js b/lib/interfaces/qunit.js index 6668967ca3..be7f50fb40 100644 --- a/lib/interfaces/qunit.js +++ b/lib/interfaces/qunit.js @@ -2,22 +2,21 @@ * Module dependencies. */ -var Suite = require('../suite') - , Test = require('../test') - , escapeRe = require('escape-string-regexp') - , utils = require('../utils'); +var Suite = require('../suite'); +var Test = require('../test'); +var escapeRe = require('escape-string-regexp'); /** * QUnit-style interface: * * suite('Array'); * - * test('#length', function(){ + * test('#length', function() { * var arr = [1,2,3]; * ok(arr.length == 3); * }); * - * test('#indexOf()', function(){ + * test('#indexOf()', function() { * var arr = [1,2,3]; * ok(arr.indexOf(1) == 0); * ok(arr.indexOf(2) == 1); @@ -26,17 +25,16 @@ var Suite = require('../suite') * * suite('String'); * - * test('#length', function(){ + * test('#length', function() { * ok('foo'.length == 3); * }); * + * @param {Suite} suite Root suite. */ - -module.exports = function(suite){ +module.exports = function(suite) { var suites = [suite]; - suite.on('pre-require', function(context, file, mocha){ - + suite.on('pre-require', function(context, file, mocha) { var common = require('./common')(suites, context); context.before = common.before; @@ -48,8 +46,10 @@ module.exports = function(suite){ * Describe a "suite" with the given `title`. */ - context.suite = function(title){ - if (suites.length > 1) suites.shift(); + context.suite = function(title) { + if (suites.length > 1) { + suites.shift(); + } var suite = Suite.create(suites[0], title); suite.file = file; suites.unshift(suite); @@ -60,7 +60,7 @@ module.exports = function(suite){ * Exclusive test-case. */ - context.suite.only = function(title, fn){ + context.suite.only = function(title, fn) { var suite = context.suite(title, fn); mocha.grep(suite.fullTitle()); }; @@ -71,7 +71,7 @@ module.exports = function(suite){ * acting as a thunk. */ - context.test = function(title, fn){ + context.test = function(title, fn) { var test = new Test(title, fn); test.file = file; suites[0].addTest(test); @@ -82,13 +82,12 @@ module.exports = function(suite){ * Exclusive test-case. */ - context.test.only = function(title, fn){ + context.test.only = function(title, fn) { var test = context.test(title, fn); var reString = '^' + escapeRe(test.fullTitle()) + '$'; mocha.grep(new RegExp(reString)); }; context.test.skip = common.test.skip; - }); }; diff --git a/lib/interfaces/tdd.js b/lib/interfaces/tdd.js index 13bc2a33be..fb22a79190 100644 --- a/lib/interfaces/tdd.js +++ b/lib/interfaces/tdd.js @@ -2,41 +2,39 @@ * Module dependencies. */ -var Suite = require('../suite') - , Test = require('../test') - , escapeRe = require('escape-string-regexp') - , utils = require('../utils'); +var Suite = require('../suite'); +var Test = require('../test'); +var escapeRe = require('escape-string-regexp'); /** * TDD-style interface: * - * suite('Array', function(){ - * suite('#indexOf()', function(){ - * suiteSetup(function(){ + * suite('Array', function() { + * suite('#indexOf()', function() { + * suiteSetup(function() { * * }); * - * test('should return -1 when not present', function(){ + * test('should return -1 when not present', function() { * * }); * - * test('should return the index when present', function(){ + * test('should return the index when present', function() { * * }); * - * suiteTeardown(function(){ + * suiteTeardown(function() { * * }); * }); * }); * + * @param {Suite} suite Root suite. */ - -module.exports = function(suite){ +module.exports = function(suite) { var suites = [suite]; - suite.on('pre-require', function(context, file, mocha){ - + suite.on('pre-require', function(context, file, mocha) { var common = require('./common')(suites, context); context.setup = common.beforeEach; @@ -44,13 +42,12 @@ module.exports = function(suite){ context.suiteSetup = common.before; context.suiteTeardown = common.after; context.run = mocha.options.delay && common.runWithSuite(suite); + /** - * Describe a "suite" with the given `title` - * and callback `fn` containing nested suites - * and/or tests. + * Describe a "suite" with the given `title` and callback `fn` containing + * nested suites and/or tests. */ - - context.suite = function(title, fn){ + context.suite = function(title, fn) { var suite = Suite.create(suites[0], title); suite.file = file; suites.unshift(suite); @@ -73,21 +70,20 @@ module.exports = function(suite){ /** * Exclusive test-case. */ - - context.suite.only = function(title, fn){ + context.suite.only = function(title, fn) { var suite = context.suite(title, fn); mocha.grep(suite.fullTitle()); }; /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. + * Describe a specification or test-case with the given `title` and + * callback `fn` acting as a thunk. */ - - context.test = function(title, fn){ + context.test = function(title, fn) { var suite = suites[0]; - if (suite.pending) fn = null; + if (suite.pending) { + fn = null; + } var test = new Test(title, fn); test.file = file; suite.addTest(test); @@ -98,7 +94,7 @@ module.exports = function(suite){ * Exclusive test-case. */ - context.test.only = function(title, fn){ + context.test.only = function(title, fn) { var test = context.test(title, fn); var reString = '^' + escapeRe(test.fullTitle()) + '$'; mocha.grep(new RegExp(reString)); diff --git a/lib/mocha.js b/lib/mocha.js index 8a11124cb1..0d86f21132 100644 --- a/lib/mocha.js +++ b/lib/mocha.js @@ -8,9 +8,9 @@ * Module dependencies. */ -var path = require('path') - , escapeRe = require('escape-string-regexp') - , utils = require('./utils'); +var escapeRe = require('escape-string-regexp'); +var path = require('path'); +var utils = require('./utils'); /** * Expose `Mocha`. @@ -23,9 +23,8 @@ exports = module.exports = Mocha; */ if (typeof process !== 'undefined' && typeof process.cwd === 'function') { - var join = path.join - , cwd = process.cwd(); - module.paths.push(cwd, join(cwd, 'node_modules')); + var cwd = process.cwd(); + module.paths.push(cwd, path.join(cwd, 'node_modules')); } /** @@ -45,17 +44,16 @@ exports.Test = require('./test'); /** * Return image `name` path. * - * @param {String} name - * @return {String} * @api private + * @param {string} name + * @return {string} */ - function image(name) { - return __dirname + '/../images/' + name + '.png'; + return path.join(__dirname, '../images', name + '.png'); } /** - * Setup mocha with `options`. + * Set up mocha with `options`. * * Options: * @@ -69,26 +67,35 @@ function image(name) { * - `fullTrace` display the full stack-trace on failing * - `grep` string or regexp to filter tests with * - * @param {Object} options * @api public + * @param {Object} options */ - function Mocha(options) { options = options || {}; this.files = []; this.options = options; - if (options.grep) this.grep(new RegExp(options.grep)); - if (options.fgrep) this.grep(options.fgrep); - this.suite = new exports.Suite('', new exports.Context); + if (options.grep) { + this.grep(new RegExp(options.grep)); + } + if (options.fgrep) { + this.grep(options.fgrep); + } + this.suite = new exports.Suite('', new exports.Context()); this.ui(options.ui); this.bail(options.bail); this.reporter(options.reporter, options.reporterOptions); - if (null != options.timeout) this.timeout(options.timeout); + if (options.timeout != null) { + this.timeout(options.timeout); + } this.useColors(options.useColors); - if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts); - if (options.slow) this.slow(options.slow); + if (options.enableTimeouts !== null) { + this.enableTimeouts(options.enableTimeouts); + } + if (options.slow) { + this.slow(options.slow); + } - this.suite.on('pre-require', function (context) { + this.suite.on('pre-require', function(context) { exports.afterEach = context.afterEach || context.teardown; exports.after = context.after || context.suiteTeardown; exports.beforeEach = context.beforeEach || context.setup; @@ -108,12 +115,13 @@ function Mocha(options) { /** * Enable or disable bailing on the first failure. * - * @param {Boolean} [bail] * @api public + * @param {boolean} [bail] */ - -Mocha.prototype.bail = function(bail){ - if (0 == arguments.length) bail = true; +Mocha.prototype.bail = function(bail) { + if (!arguments.length) { + bail = true; + } this.suite.bail(bail); return this; }; @@ -121,11 +129,10 @@ Mocha.prototype.bail = function(bail){ /** * Add test `file`. * - * @param {String} file * @api public + * @param {string} file */ - -Mocha.prototype.addFile = function(file){ +Mocha.prototype.addFile = function(file) { this.files.push(file); return this; }; @@ -133,27 +140,38 @@ Mocha.prototype.addFile = function(file){ /** * Set reporter to `reporter`, defaults to "spec". * - * @param {String|Function} reporter name or constructor - * @param {Object} reporterOptions optional options * @api public + * @param {string|Function} reporter name or constructor + * @param {Object} reporterOptions optional options */ -Mocha.prototype.reporter = function(reporter, reporterOptions){ - if ('function' == typeof reporter) { +Mocha.prototype.reporter = function(reporter, reporterOptions) { + if (typeof reporter === 'function') { this._reporter = reporter; } else { reporter = reporter || 'spec'; var _reporter; - try { _reporter = require('./reporters/' + reporter); } catch (err) {} - if (!_reporter) try { _reporter = require(reporter); } catch (err) { - err.message.indexOf('Cannot find module') !== -1 - ? console.warn('"' + reporter + '" reporter not found') - : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack); + try { + _reporter = require('./reporters/' + reporter); + } catch (err) { + // Ignore + } + if (!_reporter) { + try { + _reporter = require(reporter); + } catch (err) { + err.message.indexOf('Cannot find module') !== -1 + ? console.warn('"' + reporter + '" reporter not found') + : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack); + } + } + if (!_reporter && reporter === 'teamcity') { + console.warn('The Teamcity reporter was moved to a package named ' + + 'mocha-teamcity-reporter ' + + '(https://npmjs.org/package/mocha-teamcity-reporter).'); + } + if (!_reporter) { + throw new Error('invalid reporter "' + reporter + '"'); } - if (!_reporter && reporter === 'teamcity') - console.warn('The Teamcity reporter was moved to a package named ' + - 'mocha-teamcity-reporter ' + - '(https://npmjs.org/package/mocha-teamcity-reporter).'); - if (!_reporter) throw new Error('invalid reporter "' + reporter + '"'); this._reporter = _reporter; } this.options.reporterOptions = reporterOptions; @@ -163,15 +181,19 @@ Mocha.prototype.reporter = function(reporter, reporterOptions){ /** * Set test UI `name`, defaults to "bdd". * - * @param {String} bdd * @api public + * @param {string} bdd */ - -Mocha.prototype.ui = function(name){ +Mocha.prototype.ui = function(name) { name = name || 'bdd'; this._ui = exports.interfaces[name]; - if (!this._ui) try { this._ui = require(name); } catch (err) {} - if (!this._ui) throw new Error('invalid interface "' + name + '"'); + if (!this._ui) { + try { + this._ui = require(name); + } catch (err) { + throw new Error('invalid interface "' + name + '"'); + } + } this._ui = this._ui(this.suite); return this; }; @@ -181,12 +203,11 @@ Mocha.prototype.ui = function(name){ * * @api private */ - -Mocha.prototype.loadFiles = function(fn){ +Mocha.prototype.loadFiles = function(fn) { var self = this; var suite = this.suite; var pending = this.files.length; - this.files.forEach(function(file){ + this.files.forEach(function(file) { file = path.resolve(file); suite.emit('pre-require', global, file, self); suite.emit('require', require(file), file, self); @@ -200,20 +221,19 @@ Mocha.prototype.loadFiles = function(fn){ * * @api private */ - Mocha.prototype._growl = function(runner, reporter) { var notify = require('growl'); - runner.on('end', function(){ + runner.on('end', function() { var stats = reporter.stats; if (stats.failures) { var msg = stats.failures + ' of ' + runner.total + ' tests failed'; notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); } else { notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { - name: 'mocha' - , title: 'Passed' - , image: image('ok') + name: 'mocha', + title: 'Passed', + image: image('ok') }); } }); @@ -222,26 +242,22 @@ Mocha.prototype._growl = function(runner, reporter) { /** * Add regexp to grep, if `re` is a string it is escaped. * - * @param {RegExp|String} re - * @return {Mocha} * @api public + * @param {RegExp|string} re + * @return {Mocha} */ - -Mocha.prototype.grep = function(re){ - this.options.grep = 'string' == typeof re - ? new RegExp(escapeRe(re)) - : re; +Mocha.prototype.grep = function(re) { + this.options.grep = typeof re === 'string' ? new RegExp(escapeRe(re)) : re; return this; }; /** * Invert `.grep()` matches. * - * @return {Mocha} * @api public + * @return {Mocha} */ - -Mocha.prototype.invert = function(){ +Mocha.prototype.invert = function() { this.options.invert = true; return this; }; @@ -249,24 +265,22 @@ Mocha.prototype.invert = function(){ /** * Ignore global leaks. * - * @param {Boolean} ignore - * @return {Mocha} * @api public + * @param {boolean} ignore + * @return {Mocha} */ - -Mocha.prototype.ignoreLeaks = function(ignore){ - this.options.ignoreLeaks = !!ignore; +Mocha.prototype.ignoreLeaks = function(ignore) { + this.options.ignoreLeaks = Boolean(ignore); return this; }; /** * Enable global leak checking. * - * @return {Mocha} * @api public + * @return {Mocha} */ - -Mocha.prototype.checkLeaks = function(){ +Mocha.prototype.checkLeaks = function() { this.options.ignoreLeaks = false; return this; }; @@ -274,10 +288,9 @@ Mocha.prototype.checkLeaks = function(){ /** * Display long stack-trace on failing * - * @return {Mocha} * @api public + * @return {Mocha} */ - Mocha.prototype.fullTrace = function() { this.options.fullStackTrace = true; return this; @@ -286,11 +299,10 @@ Mocha.prototype.fullTrace = function() { /** * Enable growl support. * - * @return {Mocha} * @api public + * @return {Mocha} */ - -Mocha.prototype.growl = function(){ +Mocha.prototype.growl = function() { this.options.growl = true; return this; }; @@ -298,12 +310,11 @@ Mocha.prototype.growl = function(){ /** * Ignore `globals` array or string. * - * @param {Array|String} globals - * @return {Mocha} * @api public + * @param {Array|string} globals + * @return {Mocha} */ - -Mocha.prototype.globals = function(globals){ +Mocha.prototype.globals = function(globals) { this.options.globals = (this.options.globals || []).concat(globals); return this; }; @@ -311,12 +322,11 @@ Mocha.prototype.globals = function(globals){ /** * Emit color output. * - * @param {Boolean} colors - * @return {Mocha} * @api public + * @param {boolean} colors + * @return {Mocha} */ - -Mocha.prototype.useColors = function(colors){ +Mocha.prototype.useColors = function(colors) { if (colors !== undefined) { this.options.useColors = colors; } @@ -326,27 +336,23 @@ Mocha.prototype.useColors = function(colors){ /** * Use inline diffs rather than +/-. * - * @param {Boolean} inlineDiffs - * @return {Mocha} * @api public + * @param {boolean} inlineDiffs + * @return {Mocha} */ - Mocha.prototype.useInlineDiffs = function(inlineDiffs) { - this.options.useInlineDiffs = arguments.length && inlineDiffs != undefined - ? inlineDiffs - : false; + this.options.useInlineDiffs = inlineDiffs !== undefined && inlineDiffs; return this; }; /** * Set the timeout in milliseconds. * - * @param {Number} timeout - * @return {Mocha} * @api public + * @param {number} timeout + * @return {Mocha} */ - -Mocha.prototype.timeout = function(timeout){ +Mocha.prototype.timeout = function(timeout) { this.suite.timeout(timeout); return this; }; @@ -354,12 +360,11 @@ Mocha.prototype.timeout = function(timeout){ /** * Set slowness threshold in milliseconds. * - * @param {Number} slow - * @return {Mocha} * @api public + * @param {number} slow + * @return {Mocha} */ - -Mocha.prototype.slow = function(slow){ +Mocha.prototype.slow = function(slow) { this.suite.slow(slow); return this; }; @@ -367,34 +372,31 @@ Mocha.prototype.slow = function(slow){ /** * Enable timeouts. * - * @param {Boolean} enabled - * @return {Mocha} * @api public + * @param {boolean} enabled + * @return {Mocha} */ - Mocha.prototype.enableTimeouts = function(enabled) { - this.suite.enableTimeouts(arguments.length && enabled !== undefined - ? enabled - : true); - return this + this.suite.enableTimeouts(arguments.length && enabled !== undefined ? enabled : true); + return this; }; /** * Makes all tests async (accepting a callback) * - * @return {Mocha} * @api public + * @return {Mocha} */ - -Mocha.prototype.asyncOnly = function(){ +Mocha.prototype.asyncOnly = function() { this.options.asyncOnly = true; return this; }; /** * Disable syntax highlighting (in browser). - * @returns {Mocha} + * * @api public + * @returns {Mocha} */ Mocha.prototype.noHighlighting = function() { this.options.noHighlighting = true; @@ -403,8 +405,9 @@ Mocha.prototype.noHighlighting = function() { /** * Delay root suite execution. - * @returns {Mocha} + * * @api public + * @returns {Mocha} */ Mocha.prototype.delay = function delay() { this.options.delay = true; @@ -414,32 +417,42 @@ Mocha.prototype.delay = function delay() { /** * Run tests and invoke `fn()` when complete. * + * @api public * @param {Function} fn * @return {Runner} - * @api public */ -Mocha.prototype.run = function(fn){ - if (this.files.length) this.loadFiles(); +Mocha.prototype.run = function(fn) { + if (this.files.length) { + this.loadFiles(); + } var suite = this.suite; var options = this.options; options.files = this.files; var runner = new exports.Runner(suite, options.delay); var reporter = new this._reporter(runner, options); - runner.ignoreLeaks = false !== options.ignoreLeaks; + runner.ignoreLeaks = options.ignoreLeaks !== false; runner.fullStackTrace = options.fullStackTrace; runner.asyncOnly = options.asyncOnly; - if (options.grep) runner.grep(options.grep, options.invert); - if (options.globals) runner.globals(options.globals); - if (options.growl) this._growl(runner, reporter); + if (options.grep) { + runner.grep(options.grep, options.invert); + } + if (options.globals) { + runner.globals(options.globals); + } + if (options.growl) { + this._growl(runner, reporter); + } if (options.useColors !== undefined) { exports.reporters.Base.useColors = options.useColors; } exports.reporters.Base.inlineDiffs = options.useInlineDiffs; function done(failures) { - if (reporter.done) { - reporter.done(failures, fn); - } else fn && fn(failures); + if (reporter.done) { + reporter.done(failures, fn); + } else { + fn && fn(failures); + } } return runner.run(done); diff --git a/lib/ms.js b/lib/ms.js index ba451fab6c..12fddc18ae 100644 --- a/lib/ms.js +++ b/lib/ms.js @@ -15,29 +15,32 @@ var y = d * 365.25; * * - `long` verbose formatting [false] * - * @param {String|Number} val - * @param {Object} options - * @return {String|Number} * @api public + * @param {string|number} val + * @param {Object} options + * @return {string|number} */ - -module.exports = function(val, options){ +module.exports = function(val, options) { options = options || {}; - if ('string' == typeof val) return parse(val); + if (typeof val === 'string') { + return parse(val); + } + // https://github.com/mochajs/mocha/pull/1035 return options['long'] ? longFormat(val) : shortFormat(val); }; /** * Parse the given `str` and return milliseconds. * - * @param {String} str - * @return {Number} * @api private + * @param {string} str + * @return {number} */ - function parse(str) { - var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); - if (!match) return; + var match = (/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i).exec(str); + if (!match) { + return; + } var n = parseFloat(match[1]); var type = (match[2] || 'ms').toLowerCase(); switch (type) { @@ -63,33 +66,41 @@ function parse(str) { return n * s; case 'ms': return n; + default: + // No default case } } /** * Short format for `ms`. * - * @param {Number} ms - * @return {String} * @api private + * @param {number} ms + * @return {string} */ - function shortFormat(ms) { - if (ms >= d) return Math.round(ms / d) + 'd'; - if (ms >= h) return Math.round(ms / h) + 'h'; - if (ms >= m) return Math.round(ms / m) + 'm'; - if (ms >= s) return Math.round(ms / s) + 's'; + if (ms >= d) { + return Math.round(ms / d) + 'd'; + } + if (ms >= h) { + return Math.round(ms / h) + 'h'; + } + if (ms >= m) { + return Math.round(ms / m) + 'm'; + } + if (ms >= s) { + return Math.round(ms / s) + 's'; + } return ms + 'ms'; } /** * Long format for `ms`. * - * @param {Number} ms - * @return {String} * @api private + * @param {number} ms + * @return {string} */ - function longFormat(ms) { return plural(ms, d, 'day') || plural(ms, h, 'hour') @@ -100,10 +111,18 @@ function longFormat(ms) { /** * Pluralization helper. + * + * @api private + * @param {number} ms + * @param {number} n + * @param {string} name */ - function plural(ms, n, name) { - if (ms < n) return; - if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; + if (ms < n) { + return; + } + if (ms < n * 1.5) { + return Math.floor(ms / n) + ' ' + name; + } return Math.ceil(ms / n) + ' ' + name + 's'; } diff --git a/lib/pending.js b/lib/pending.js index 265ec73c18..c847e04e3f 100644 --- a/lib/pending.js +++ b/lib/pending.js @@ -8,9 +8,8 @@ module.exports = Pending; /** * Initialize a new `Pending` error with the given message. * - * @param {String} message + * @param {string} message */ - function Pending(message) { - this.message = message; + this.message = message; } diff --git a/lib/reporters/base.js b/lib/reporters/base.js index 9b719a80e7..3c57d01a0b 100644 --- a/lib/reporters/base.js +++ b/lib/reporters/base.js @@ -2,33 +2,36 @@ * Module dependencies. */ -var tty = require('tty') - , diff = require('diff') - , ms = require('../ms') - , utils = require('../utils') - , supportsColor = process.env ? require('supports-color') : null; +var tty = require('tty'); +var diff = require('diff'); +var ms = require('../ms'); +var utils = require('../utils'); +var supportsColor = process.env ? require('supports-color') : null; /** - * Save timer references to avoid Sinon interfering (see GH-237). + * Expose `Base`. */ -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; +exports = module.exports = Base; /** - * Check if both stdio streams are associated with a tty. + * Save timer references to avoid Sinon interfering. + * See: https://github.com/mochajs/mocha/issues/237 */ -var isatty = tty.isatty(1) && tty.isatty(2); +/* eslint-disable no-unused-vars, no-native-reassign */ +var Date = global.Date; +var setTimeout = global.setTimeout; +var setInterval = global.setInterval; +var clearTimeout = global.clearTimeout; +var clearInterval = global.clearInterval; +/* eslint-enable no-unused-vars, no-native-reassign */ /** - * Expose `Base`. + * Check if both stdio streams are associated with a tty. */ -exports = module.exports = Base; +var isatty = tty.isatty(1) && tty.isatty(2); /** * Enable coloring by default, except in the browser interface. @@ -49,25 +52,25 @@ exports.inlineDiffs = false; */ exports.colors = { - 'pass': 90 - , 'fail': 31 - , 'bright pass': 92 - , 'bright fail': 91 - , 'bright yellow': 93 - , 'pending': 36 - , 'suite': 0 - , 'error title': 0 - , 'error message': 31 - , 'error stack': 90 - , 'checkmark': 32 - , 'fast': 90 - , 'medium': 33 - , 'slow': 31 - , 'green': 32 - , 'light': 90 - , 'diff gutter': 90 - , 'diff added': 32 - , 'diff removed': 31 + pass: 90, + fail: 31, + 'bright pass': 92, + 'bright fail': 91, + 'bright yellow': 93, + pending: 36, + suite: 0, + 'error title': 0, + 'error message': 31, + 'error stack': 90, + checkmark: 32, + fast: 90, + medium: 33, + slow: 31, + green: 32, + light: 90, + 'diff gutter': 90, + 'diff added': 32, + 'diff removed': 31 }; /** @@ -81,7 +84,7 @@ exports.symbols = { }; // With node.js on Windows: use symbols available in terminal default fonts -if ('win32' == process.platform) { +if (process.platform === 'win32') { exports.symbols.ok = '\u221A'; exports.symbols.err = '\u00D7'; exports.symbols.dot = '.'; @@ -93,53 +96,54 @@ if ('win32' == process.platform) { * as well as user-defined color * schemes. * - * @param {String} type - * @param {String} str - * @return {String} + * @param {string} type + * @param {string} str + * @return {string} * @api private */ - var color = exports.color = function(type, str) { - if (!exports.useColors) return String(str); + if (!exports.useColors) { + return String(str); + } return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; }; /** - * Expose term window size, with some - * defaults for when stderr is not a tty. + * Expose term window size, with some defaults for when stderr is not a tty. */ exports.window = { - width: isatty - ? process.stdout.getWindowSize - ? process.stdout.getWindowSize(1)[0] - : tty.getWindowSize()[1] - : 75 + width: 75 }; +if (isatty) { + exports.window.width = process.stdout.getWindowSize + ? process.stdout.getWindowSize(1)[0] + : tty.getWindowSize()[1]; +} + /** - * Expose some basic cursor interactions - * that are common among reporters. + * Expose some basic cursor interactions that are common among reporters. */ exports.cursor = { - hide: function(){ + hide: function() { isatty && process.stdout.write('\u001b[?25l'); }, - show: function(){ + show: function() { isatty && process.stdout.write('\u001b[?25h'); }, - deleteLine: function(){ + deleteLine: function() { isatty && process.stdout.write('\u001b[2K'); }, - beginningOfLine: function(){ + beginningOfLine: function() { isatty && process.stdout.write('\u001b[0G'); }, - CR: function(){ + CR: function() { if (isatty) { exports.cursor.deleteLine(); exports.cursor.beginningOfLine(); @@ -156,22 +160,24 @@ exports.cursor = { * @api public */ -exports.list = function(failures){ +exports.list = function(failures) { console.log(); - failures.forEach(function(test, i){ + failures.forEach(function(test, i) { // format var fmt = color('error title', ' %s) %s:\n') + color('error message', ' %s') + color('error stack', '\n%s\n'); // msg - var err = test.err - , message = err.message || '' - , stack = err.stack || message - , index = stack.indexOf(message) - , actual = err.actual - , expected = err.expected - , escape = true; + var msg; + var err = test.err; + var message = err.message || ''; + var stack = err.stack || message; + var index = stack.indexOf(message); + var actual = err.actual; + var expected = err.expected; + var escape = true; + if (index === -1) { msg = message; } else { @@ -186,9 +192,7 @@ exports.list = function(failures){ msg = 'Uncaught ' + msg; } // explicitly show diff - if (err.showDiff !== false && sameType(actual, expected) - && expected !== undefined) { - + if (err.showDiff !== false && sameType(actual, expected) && expected !== undefined) { escape = false; if (!(utils.isString(actual) && utils.isString(expected))) { err.actual = actual = utils.stringify(actual); @@ -226,55 +230,57 @@ exports.list = function(failures){ */ function Base(runner) { - var self = this - , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } - , failures = this.failures = []; + var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; + var failures = this.failures = []; - if (!runner) return; + if (!runner) { + return; + } this.runner = runner; runner.stats = stats; - runner.on('start', function(){ - stats.start = new Date; + runner.on('start', function() { + stats.start = new Date(); }); - runner.on('suite', function(suite){ + runner.on('suite', function(suite) { stats.suites = stats.suites || 0; suite.root || stats.suites++; }); - runner.on('test end', function(test){ + runner.on('test end', function() { stats.tests = stats.tests || 0; stats.tests++; }); - runner.on('pass', function(test){ + runner.on('pass', function(test) { stats.passes = stats.passes || 0; - var medium = test.slow() / 2; - test.speed = test.duration > test.slow() - ? 'slow' - : test.duration > medium - ? 'medium' - : 'fast'; + if (test.duration > test.slow()) { + test.speed = 'slow'; + } else if (test.duration > test.slow() / 2) { + test.speed = 'medium'; + } else { + test.speed = 'fast'; + } stats.passes++; }); - runner.on('fail', function(test, err){ + runner.on('fail', function(test, err) { stats.failures = stats.failures || 0; stats.failures++; test.err = err; failures.push(test); }); - runner.on('end', function(){ - stats.end = new Date; - stats.duration = new Date - stats.start; + runner.on('end', function() { + stats.end = new Date(); + stats.duration = new Date() - stats.start; }); - runner.on('pending', function(){ + runner.on('pending', function() { stats.pending++; }); } @@ -285,10 +291,8 @@ function Base(runner) { * * @api public */ - -Base.prototype.epilogue = function(){ +Base.prototype.epilogue = function() { var stats = this.stats; - var tests; var fmt; console.log(); @@ -326,26 +330,24 @@ Base.prototype.epilogue = function(){ /** * Pad the given `str` to `len`. * - * @param {String} str - * @param {String} len - * @return {String} * @api private + * @param {string} str + * @param {string} len + * @return {string} */ - function pad(str, len) { str = String(str); return Array(len - str.length + 1).join(' ') + str; } - /** * Returns an inline diff between 2 strings with coloured ANSI output * - * @param {Error} Error with actual/expected - * @return {String} Diff * @api private + * @param {Error} err with actual/expected + * @param {boolean} escape + * @return {string} Diff */ - function inlineDiff(err, escape) { var msg = errorDiff(err, 'WordsWithSpace', escape); @@ -353,7 +355,7 @@ function inlineDiff(err, escape) { var lines = msg.split('\n'); if (lines.length > 4) { var width = String(lines.length).length; - msg = lines.map(function(str, i){ + msg = lines.map(function(str, i) { return pad(++i, width) + ' |' + ' ' + str; }).join('\n'); } @@ -373,24 +375,32 @@ function inlineDiff(err, escape) { } /** - * Returns a unified diff between 2 strings + * Returns a unified diff between two strings. * - * @param {Error} Error with actual/expected - * @return {String} Diff * @api private + * @param {Error} err with actual/expected + * @param {boolean} escape + * @return {string} The diff. */ - function unifiedDiff(err, escape) { var indent = ' '; function cleanUp(line) { if (escape) { line = escapeInvisibles(line); } - if (line[0] === '+') return indent + colorLines('diff added', line); - if (line[0] === '-') return indent + colorLines('diff removed', line); - if (line.match(/\@\@/)) return null; - if (line.match(/\\ No newline/)) return null; - else return indent + line; + if (line[0] === '+') { + return indent + colorLines('diff added', line); + } + if (line[0] === '-') { + return indent + colorLines('diff removed', line); + } + if (line.match(/\@\@/)) { + return null; + } + if (line.match(/\\ No newline/)) { + return null; + } + return indent + line; } function notBlank(line) { return line != null; @@ -398,26 +408,31 @@ function unifiedDiff(err, escape) { var msg = diff.createPatch('string', err.actual, err.expected); var lines = msg.split('\n').splice(4); return '\n ' - + colorLines('diff added', '+ expected') + ' ' - + colorLines('diff removed', '- actual') - + '\n\n' - + lines.map(cleanUp).filter(notBlank).join('\n'); + + colorLines('diff added', '+ expected') + ' ' + + colorLines('diff removed', '- actual') + + '\n\n' + + lines.map(cleanUp).filter(notBlank).join('\n'); } /** * Return a character diff for `err`. * - * @param {Error} err - * @return {String} * @api private + * @param {Error} err + * @param {string} type + * @param {boolean} escape + * @return {string} */ - function errorDiff(err, type, escape) { - var actual = escape ? escapeInvisibles(err.actual) : err.actual; + var actual = escape ? escapeInvisibles(err.actual) : err.actual; var expected = escape ? escapeInvisibles(err.expected) : err.expected; - return diff['diff' + type](actual, expected).map(function(str){ - if (str.added) return colorLines('diff added', str.value); - if (str.removed) return colorLines('diff removed', str.value); + return diff['diff' + type](actual, expected).map(function(str) { + if (str.added) { + return colorLines('diff added', str.value); + } + if (str.removed) { + return colorLines('diff removed', str.value); + } return str.value; }).join(''); } @@ -425,42 +440,43 @@ function errorDiff(err, type, escape) { /** * Returns a string with all invisible characters in plain text * - * @param {String} line - * @return {String} * @api private + * @param {string} line + * @return {string} */ function escapeInvisibles(line) { - return line.replace(/\t/g, '') - .replace(/\r/g, '') - .replace(/\n/g, '\n'); + return line.replace(/\t/g, '') + .replace(/\r/g, '') + .replace(/\n/g, '\n'); } /** * Color lines for `str`, using the color `name`. * - * @param {String} name - * @param {String} str - * @return {String} * @api private + * @param {string} name + * @param {string} str + * @return {string} */ - function colorLines(name, str) { - return str.split('\n').map(function(str){ + return str.split('\n').map(function(str) { return color(name, str); }).join('\n'); } +/** + * Object#toString reference. + */ +var objToString = Object.prototype.toString; + /** * Check that a / b have the same type. * + * @api private * @param {Object} a * @param {Object} b - * @return {Boolean} - * @api private + * @return {boolean} */ - function sameType(a, b) { - a = Object.prototype.toString.call(a); - b = Object.prototype.toString.call(b); - return a == b; + return objToString.call(a) === objToString.call(b); } diff --git a/lib/reporters/doc.js b/lib/reporters/doc.js index d194eb0e69..8c1fd3adf7 100644 --- a/lib/reporters/doc.js +++ b/lib/reporters/doc.js @@ -2,8 +2,8 @@ * Module dependencies. */ -var Base = require('./base') - , utils = require('../utils'); +var Base = require('./base'); +var utils = require('../utils'); /** * Expose `Doc`. @@ -17,21 +17,19 @@ exports = module.exports = Doc; * @param {Runner} runner * @api public */ - function Doc(runner) { Base.call(this, runner); - var self = this - , stats = this.stats - , total = runner.total - , indents = 2; + var indents = 2; function indent() { return Array(indents).join(' '); } - runner.on('suite', function(suite){ - if (suite.root) return; + runner.on('suite', function(suite) { + if (suite.root) { + return; + } ++indents; console.log('%s
', indent()); ++indents; @@ -39,21 +37,23 @@ function Doc(runner) { console.log('%s
', indent()); }); - runner.on('suite end', function(suite){ - if (suite.root) return; + runner.on('suite end', function(suite) { + if (suite.root) { + return; + } console.log('%s
', indent()); --indents; console.log('%s
', indent()); --indents; }); - runner.on('pass', function(test){ + runner.on('pass', function(test) { console.log('%s
%s
', indent(), utils.escape(test.title)); var code = utils.escape(utils.clean(test.fn.toString())); console.log('%s
%s
', indent(), code); }); - runner.on('fail', function(test, err){ + runner.on('fail', function(test, err) { console.log('%s
%s
', indent(), utils.escape(test.title)); var code = utils.escape(utils.clean(test.fn.toString())); console.log('%s
%s
', indent(), code); diff --git a/lib/reporters/dot.js b/lib/reporters/dot.js index 42a45ee2b5..b9cb785b25 100644 --- a/lib/reporters/dot.js +++ b/lib/reporters/dot.js @@ -2,8 +2,8 @@ * Module dependencies. */ -var Base = require('./base') - , color = Base.color; +var Base = require('./base'); +var color = Base.color; /** * Expose `Dot`. @@ -14,42 +14,46 @@ exports = module.exports = Dot; /** * Initialize a new `Dot` matrix test reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function Dot(runner) { Base.call(this, runner); - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , n = -1; + var self = this; + var width = Base.window.width * .75 | 0; + var n = -1; - runner.on('start', function(){ + runner.on('start', function() { process.stdout.write('\n'); }); - runner.on('pending', function(test){ - if (++n % width == 0) process.stdout.write('\n '); + runner.on('pending', function() { + if (++n % width === 0) { + process.stdout.write('\n '); + } process.stdout.write(color('pending', Base.symbols.dot)); }); - runner.on('pass', function(test){ - if (++n % width == 0) process.stdout.write('\n '); - if ('slow' == test.speed) { + runner.on('pass', function(test) { + if (++n % width === 0) { + process.stdout.write('\n '); + } + if (test.speed === 'slow') { process.stdout.write(color('bright yellow', Base.symbols.dot)); } else { process.stdout.write(color(test.speed, Base.symbols.dot)); } }); - runner.on('fail', function(test, err){ - if (++n % width == 0) process.stdout.write('\n '); + runner.on('fail', function() { + if (++n % width === 0) { + process.stdout.write('\n '); + } process.stdout.write(color('fail', Base.symbols.dot)); }); - runner.on('end', function(){ + runner.on('end', function() { console.log(); self.epilogue(); }); diff --git a/lib/reporters/html-cov.js b/lib/reporters/html-cov.js index 74b46adcd9..f45feb5d70 100644 --- a/lib/reporters/html-cov.js +++ b/lib/reporters/html-cov.js @@ -2,8 +2,9 @@ * Module dependencies. */ -var JSONCov = require('./json-cov') - , fs = require('fs'); +var JSONCov = require('./json-cov'); +var readFileSync = require('fs').readFileSync; +var join = require('path').join; /** * Expose `HTMLCov`. @@ -14,37 +15,42 @@ exports = module.exports = HTMLCov; /** * Initialize a new `JsCoverage` reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function HTMLCov(runner) { - var jade = require('jade') - , file = __dirname + '/templates/coverage.jade' - , str = fs.readFileSync(file, 'utf8') - , fn = jade.compile(str, { filename: file }) - , self = this; + var jade = require('jade'); + var file = join(__dirname, '/templates/coverage.jade'); + var fn = jade.compile(str, { filename: file }); + var self = this; + var str = readFileSync(file, 'utf8'); JSONCov.call(this, runner, false); - runner.on('end', function(){ + runner.on('end', function() { process.stdout.write(fn({ - cov: self.cov - , coverageClass: coverageClass + cov: self.cov, + coverageClass: coverageClass })); }); } /** - * Return coverage class for `n`. + * Return coverage class for a given coverage percentage. * - * @return {String} * @api private + * @param {number} coveragePctg + * @return {string} */ - -function coverageClass(n) { - if (n >= 75) return 'high'; - if (n >= 50) return 'medium'; - if (n >= 25) return 'low'; +function coverageClass(coveragePctg) { + if (coveragePctg >= 75) { + return 'high'; + } + if (coveragePctg >= 50) { + return 'medium'; + } + if (coveragePctg >= 25) { + return 'low'; + } return 'terrible'; } diff --git a/lib/reporters/html.js b/lib/reporters/html.js index f0e4e6f011..00e9d58fe5 100644 --- a/lib/reporters/html.js +++ b/lib/reporters/html.js @@ -1,21 +1,25 @@ +/* eslint-env browser */ + /** * Module dependencies. */ -var Base = require('./base') - , utils = require('../utils') - , Progress = require('../browser/progress') - , escape = utils.escape; +var Base = require('./base'); +var utils = require('../utils'); +var Progress = require('../browser/progress'); +var escape = utils.escape; /** * Save timer references to avoid Sinon interfering (see GH-237). */ -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; +/* eslint-disable no-unused-vars, no-native-reassign */ +var Date = global.Date; +var setTimeout = global.setTimeout; +var setInterval = global.setInterval; +var clearTimeout = global.clearTimeout; +var clearInterval = global.clearInterval; +/* eslint-enable no-unused-vars, no-native-reassign */ /** * Expose `HTML`. @@ -37,29 +41,27 @@ var statsTemplate = '
    ' /** * Initialize a new `HTML` reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function HTML(runner) { Base.call(this, runner); - var self = this - , stats = this.stats - , total = runner.total - , stat = fragment(statsTemplate) - , items = stat.getElementsByTagName('li') - , passes = items[1].getElementsByTagName('em')[0] - , passesLink = items[1].getElementsByTagName('a')[0] - , failures = items[2].getElementsByTagName('em')[0] - , failuresLink = items[2].getElementsByTagName('a')[0] - , duration = items[3].getElementsByTagName('em')[0] - , canvas = stat.getElementsByTagName('canvas')[0] - , report = fragment('
      ') - , stack = [report] - , progress - , ctx - , root = document.getElementById('mocha'); + var self = this; + var stats = this.stats; + var stat = fragment(statsTemplate); + var items = stat.getElementsByTagName('li'); + var passes = items[1].getElementsByTagName('em')[0]; + var passesLink = items[1].getElementsByTagName('a')[0]; + var failures = items[2].getElementsByTagName('em')[0]; + var failuresLink = items[2].getElementsByTagName('a')[0]; + var duration = items[3].getElementsByTagName('em')[0]; + var canvas = stat.getElementsByTagName('canvas')[0]; + var report = fragment('
        '); + var stack = [report]; + var progress; + var ctx; + var root = document.getElementById('mocha'); if (canvas.getContext) { var ratio = window.devicePixelRatio || 1; @@ -69,34 +71,44 @@ function HTML(runner) { canvas.height *= ratio; ctx = canvas.getContext('2d'); ctx.scale(ratio, ratio); - progress = new Progress; + progress = new Progress(); } - if (!root) return error('#mocha div missing, add it to your document'); + if (!root) { + return error('#mocha div missing, add it to your document'); + } // pass toggle - on(passesLink, 'click', function(){ + on(passesLink, 'click', function() { unhide(); - var name = /pass/.test(report.className) ? '' : ' pass'; + var name = (/pass/).test(report.className) ? '' : ' pass'; report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) hideSuitesWithout('test pass'); + if (report.className.trim()) { + hideSuitesWithout('test pass'); + } }); // failure toggle - on(failuresLink, 'click', function(){ + on(failuresLink, 'click', function() { unhide(); - var name = /fail/.test(report.className) ? '' : ' fail'; + var name = (/fail/).test(report.className) ? '' : ' fail'; report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) hideSuitesWithout('test fail'); + if (report.className.trim()) { + hideSuitesWithout('test fail'); + } }); root.appendChild(stat); root.appendChild(report); - if (progress) progress.size(40); + if (progress) { + progress.size(40); + } - runner.on('suite', function(suite){ - if (suite.root) return; + runner.on('suite', function(suite) { + if (suite.root) { + return; + } // suite var url = self.suiteURL(suite); @@ -108,40 +120,49 @@ function HTML(runner) { el.appendChild(stack[0]); }); - runner.on('suite end', function(suite){ - if (suite.root) return; + runner.on('suite end', function(suite) { + if (suite.root) { + return; + } stack.shift(); }); - runner.on('fail', function(test, err){ - if ('hook' == test.type) runner.emit('test end', test); + runner.on('fail', function(test) { + if (test.type === 'hook') { + runner.emit('test end', test); + } }); - runner.on('test end', function(test){ + runner.on('test end', function(test) { // TODO: add to stats var percent = stats.tests / this.total * 100 | 0; - if (progress) progress.update(percent).draw(ctx); + if (progress) { + progress.update(percent).draw(ctx); + } // update stats - var ms = new Date - stats.start; + var ms = new Date() - stats.start; text(passes, stats.passes); text(failures, stats.failures); text(duration, (ms / 1000).toFixed(2)); // test - if ('passed' == test.state) { + var el; + if (test.state === 'passed') { var url = self.testURL(test); - var el = fragment('
      • %e%ems ‣

      • ', test.speed, test.title, test.duration, url); + el = fragment('
      • %e%ems ‣

      • ', test.speed, test.title, test.duration, url); } else if (test.pending) { - var el = fragment('
      • %e

      • ', test.title); + el = fragment('
      • %e

      • ', test.title); } else { - var el = fragment('
      • %e ‣

      • ', test.title, self.testURL(test)); - var stackString, // Note: Includes leading newline - message = test.err.toString(); + el = fragment('
      • %e ‣

      • ', test.title, self.testURL(test)); + var stackString; // Note: Includes leading newline + var message = test.err.toString(); // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we // check for the result of the stringifying. - if ('[object Error]' === message) message = test.err.message; + if (message === '[object Error]') { + message = test.err.message; + } if (test.err.stack) { var indexOfMessage = test.err.stack.indexOf(test.err.message); @@ -152,7 +173,7 @@ function HTML(runner) { } } else if (test.err.sourceURL && test.err.line !== undefined) { // Safari doesn't give you a stack. Let's at least provide a source line. - stackString = "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; + stackString = '\n(' + test.err.sourceURL + ':' + test.err.line + ')'; } stackString = stackString || ''; @@ -171,10 +192,8 @@ function HTML(runner) { if (!test.pending) { var h2 = el.getElementsByTagName('h2')[0]; - on(h2, 'click', function(){ - pre.style.display = 'none' == pre.style.display - ? 'block' - : 'none'; + on(h2, 'click', function() { + pre.style.display = pre.style.display === 'none' ? 'block' : 'none'; }); var pre = fragment('
        %e
        ', utils.clean(test.fn.toString())); @@ -183,16 +202,19 @@ function HTML(runner) { } // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. - if (stack[0]) stack[0].appendChild(el); + if (stack[0]) { + stack[0].appendChild(el); + } }); } /** * Makes a URL, preserving querystring ("search") parameters. + * * @param {string} s - * @returns {string} your new URL + * @return {string} A new URL. */ -var makeUrl = function makeUrl(s) { +function makeUrl(s) { var search = window.location.search; // Remove previous grep query parameter if present @@ -200,49 +222,51 @@ var makeUrl = function makeUrl(s) { search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?'); } - return window.location.pathname + (search ? search + '&' : '?' ) + 'grep=' + encodeURIComponent(s); -}; + return window.location.pathname + (search ? search + '&' : '?') + 'grep=' + encodeURIComponent(s); +} /** - * Provide suite URL + * Provide suite URL. * * @param {Object} [suite] */ -HTML.prototype.suiteURL = function(suite){ +HTML.prototype.suiteURL = function(suite) { return makeUrl(suite.fullTitle()); }; /** - * Provide test URL + * Provide test URL. * * @param {Object} [test] */ - -HTML.prototype.testURL = function(test){ +HTML.prototype.testURL = function(test) { return makeUrl(test.fullTitle()); }; /** * Display error `msg`. + * + * @param {string} msg */ - function error(msg) { document.body.appendChild(fragment('
        %s
        ', msg)); } /** * Return a DOM fragment from `html`. + * + * @param {string} html */ - function fragment(html) { - var args = arguments - , div = document.createElement('div') - , i = 1; + var args = arguments; + var div = document.createElement('div'); + var i = 1; - div.innerHTML = html.replace(/%([se])/g, function(_, type){ + div.innerHTML = html.replace(/%([se])/g, function(_, type) { switch (type) { case 's': return String(args[i++]); case 'e': return escape(args[i++]); + // no default } }); @@ -250,22 +274,23 @@ function fragment(html) { } /** - * Check for suites that do not have elements - * with `classname`, and hide them. + * Check for suites that do not have elements with `classname`, and hide them. + * + * @param {text} classname */ - function hideSuitesWithout(classname) { var suites = document.getElementsByClassName('suite'); for (var i = 0; i < suites.length; i++) { var els = suites[i].getElementsByClassName(classname); - if (0 == els.length) suites[i].className += ' hidden'; + if (!els.length) { + suites[i].className += ' hidden'; + } } } /** * Unhide .hidden suites. */ - function unhide() { var els = document.getElementsByClassName('suite hidden'); for (var i = 0; i < els.length; ++i) { @@ -274,21 +299,22 @@ function unhide() { } /** - * Set `el` text to `str`. + * Set an element's text contents. + * + * @param {HTMLElement} el + * @param {string} contents */ - -function text(el, str) { +function text(el, contents) { if (el.textContent) { - el.textContent = str; + el.textContent = contents; } else { - el.innerText = str; + el.innerText = contents; } } /** * Listen on `event` with callback `fn`. */ - function on(el, event, fn) { if (el.addEventListener) { el.addEventListener(event, fn, false); diff --git a/lib/reporters/json-cov.js b/lib/reporters/json-cov.js index 309c0ef54a..ed444e4117 100644 --- a/lib/reporters/json-cov.js +++ b/lib/reporters/json-cov.js @@ -13,42 +13,42 @@ exports = module.exports = JSONCov; /** * Initialize a new `JsCoverage` reporter. * - * @param {Runner} runner - * @param {Boolean} output * @api public + * @param {Runner} runner + * @param {boolean} output */ - function JSONCov(runner, output) { - var self = this - , output = 1 == arguments.length ? true : output; - Base.call(this, runner); - var tests = [] - , failures = [] - , passes = []; + output = arguments.length === 1 || output; + var self = this; + var tests = []; + var failures = []; + var passes = []; - runner.on('test end', function(test){ + runner.on('test end', function(test) { tests.push(test); }); - runner.on('pass', function(test){ + runner.on('pass', function(test) { passes.push(test); }); - runner.on('fail', function(test){ + runner.on('fail', function(test) { failures.push(test); }); - runner.on('end', function(){ + runner.on('end', function() { var cov = global._$jscoverage || {}; var result = self.cov = map(cov); result.stats = self.stats; result.tests = tests.map(clean); result.failures = failures.map(clean); result.passes = passes.map(clean); - if (!output) return; - process.stdout.write(JSON.stringify(result, null, 2 )); + if (!output) { + return; + } + process.stdout.write(JSON.stringify(result, null, 2)); }); } @@ -56,27 +56,29 @@ function JSONCov(runner, output) { * Map jscoverage data to a JSON structure * suitable for reporting. * + * @api private * @param {Object} cov * @return {Object} - * @api private */ function map(cov) { var ret = { - instrumentation: 'node-jscoverage' - , sloc: 0 - , hits: 0 - , misses: 0 - , coverage: 0 - , files: [] + instrumentation: 'node-jscoverage', + sloc: 0, + hits: 0, + misses: 0, + coverage: 0, + files: [] }; for (var filename in cov) { - var data = coverage(filename, cov[filename]); - ret.files.push(data); - ret.hits += data.hits; - ret.misses += data.misses; - ret.sloc += data.sloc; + if (Object.prototype.hasOwnProperty.call(cov, filename)) { + var data = coverage(filename, cov[filename]); + ret.files.push(data); + ret.hits += data.hits; + ret.misses += data.misses; + ret.sloc += data.sloc; + } } ret.files.sort(function(a, b) { @@ -94,12 +96,11 @@ function map(cov) { * Map jscoverage data for a single source file * to a JSON structure suitable for reporting. * - * @param {String} filename name of the source file + * @api private + * @param {string} filename name of the source file * @param {Object} data jscoverage coverage data * @return {Object} - * @api private */ - function coverage(filename, data) { var ret = { filename: filename, @@ -110,7 +111,7 @@ function coverage(filename, data) { source: {} }; - data.source.forEach(function(line, num){ + data.source.forEach(function(line, num) { num++; if (data[num] === 0) { @@ -122,10 +123,8 @@ function coverage(filename, data) { } ret.source[num] = { - source: line - , coverage: data[num] === undefined - ? '' - : data[num] + source: line, + coverage: data[num] === undefined ? '' : data[num] }; }); @@ -138,15 +137,14 @@ function coverage(filename, data) { * Return a plain-object representation of `test` * free of cyclic properties etc. * + * @api private * @param {Object} test * @return {Object} - * @api private */ - function clean(test) { return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } + duration: test.duration, + fullTitle: test.fullTitle(), + title: test.title + }; } diff --git a/lib/reporters/json-stream.js b/lib/reporters/json-stream.js index 8fd91ce72c..c8f0e11302 100644 --- a/lib/reporters/json-stream.js +++ b/lib/reporters/json-stream.js @@ -2,8 +2,7 @@ * Module dependencies. */ -var Base = require('./base') - , color = Base.color; +var Base = require('./base'); /** * Expose `List`. @@ -14,33 +13,31 @@ exports = module.exports = List; /** * Initialize a new `List` test reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function List(runner) { Base.call(this, runner); - var self = this - , stats = this.stats - , total = runner.total; + var self = this; + var total = runner.total; - runner.on('start', function(){ + runner.on('start', function() { console.log(JSON.stringify(['start', { total: total }])); }); - runner.on('pass', function(test){ + runner.on('pass', function(test) { console.log(JSON.stringify(['pass', clean(test)])); }); - runner.on('fail', function(test, err){ + runner.on('fail', function(test, err) { test = clean(test); test.err = err.message; test.stack = err.stack || null; console.log(JSON.stringify(['fail', test])); }); - runner.on('end', function(){ + runner.on('end', function() { process.stdout.write(JSON.stringify(['end', self.stats])); }); } @@ -49,15 +46,14 @@ function List(runner) { * Return a plain-object representation of `test` * free of cyclic properties etc. * + * @api private * @param {Object} test * @return {Object} - * @api private */ - function clean(test) { return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } + title: test.title, + fullTitle: test.fullTitle(), + duration: test.duration + }; } diff --git a/lib/reporters/json.js b/lib/reporters/json.js index f565506c6e..35b760e25a 100644 --- a/lib/reporters/json.js +++ b/lib/reporters/json.js @@ -2,9 +2,7 @@ * Module dependencies. */ -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; +var Base = require('./base'); /** * Expose `JSON`. @@ -15,36 +13,35 @@ exports = module.exports = JSONReporter; /** * Initialize a new `JSON` reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function JSONReporter(runner) { - var self = this; Base.call(this, runner); - var tests = [] - , pending = [] - , failures = [] - , passes = []; + var self = this; + var tests = []; + var pending = []; + var failures = []; + var passes = []; - runner.on('test end', function(test){ + runner.on('test end', function(test) { tests.push(test); }); - runner.on('pass', function(test){ + runner.on('pass', function(test) { passes.push(test); }); - runner.on('fail', function(test){ + runner.on('fail', function(test) { failures.push(test); }); - runner.on('pending', function(test){ + runner.on('pending', function(test) { pending.push(test); }); - runner.on('end', function(){ + runner.on('end', function() { var obj = { stats: self.stats, tests: tests.map(clean), @@ -63,26 +60,26 @@ function JSONReporter(runner) { * Return a plain-object representation of `test` * free of cyclic properties etc. * + * @api private * @param {Object} test * @return {Object} - * @api private */ - function clean(test) { return { title: test.title, fullTitle: test.fullTitle(), duration: test.duration, err: errorJSON(test.err || {}) - } + }; } /** * Transform `error` into a JSON object. + * + * @api private * @param {Error} err * @return {Object} */ - function errorJSON(err) { var res = {}; Object.getOwnPropertyNames(err).forEach(function(key) { diff --git a/lib/reporters/landing.js b/lib/reporters/landing.js index ee004a20aa..1dd952cb7d 100644 --- a/lib/reporters/landing.js +++ b/lib/reporters/landing.js @@ -2,9 +2,9 @@ * Module dependencies. */ -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; +var Base = require('./base'); +var cursor = Base.cursor; +var color = Base.color; /** * Expose `Landing`. @@ -33,56 +33,52 @@ Base.colors.runway = 90; /** * Initialize a new `Landing` reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function Landing(runner) { Base.call(this, runner); - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , total = runner.total - , stream = process.stdout - , plane = color('plane', '✈') - , crashed = -1 - , n = 0; + var self = this; + var width = Base.window.width * .75 | 0; + var total = runner.total; + var stream = process.stdout; + var plane = color('plane', '✈'); + var crashed = -1; + var n = 0; function runway() { var buf = Array(width).join('-'); return ' ' + color('runway', buf); } - runner.on('start', function(){ + runner.on('start', function() { stream.write('\n\n\n '); cursor.hide(); }); - runner.on('test end', function(test){ + runner.on('test end', function(test) { // check if the plane crashed - var col = -1 == crashed - ? width * ++n / total | 0 - : crashed; + var col = crashed === -1 ? width * ++n / total | 0 : crashed; // show the crash - if ('failed' == test.state) { + if (test.state === 'failed') { plane = color('plane crash', '✈'); crashed = col; } // render landing strip - stream.write('\u001b['+(width+1)+'D\u001b[2A'); + stream.write('\u001b[' + (width + 1) + 'D\u001b[2A'); stream.write(runway()); stream.write('\n '); stream.write(color('runway', Array(col).join('⋅'))); - stream.write(plane) + stream.write(plane); stream.write(color('runway', Array(width - col).join('⋅') + '\n')); stream.write(runway()); stream.write('\u001b[0m'); }); - runner.on('end', function(){ + runner.on('end', function() { cursor.show(); console.log(); self.epilogue(); diff --git a/lib/reporters/list.js b/lib/reporters/list.js index f64367a410..5f6d37e8b1 100644 --- a/lib/reporters/list.js +++ b/lib/reporters/list.js @@ -2,9 +2,9 @@ * Module dependencies. */ -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; +var Base = require('./base'); +var color = Base.color; +var cursor = Base.cursor; /** * Expose `List`. @@ -15,40 +15,38 @@ exports = module.exports = List; /** * Initialize a new `List` test reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function List(runner) { Base.call(this, runner); - var self = this - , stats = this.stats - , n = 0; + var self = this; + var n = 0; - runner.on('start', function(){ + runner.on('start', function() { console.log(); }); - runner.on('test', function(test){ + runner.on('test', function(test) { process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); }); - runner.on('pending', function(test){ + runner.on('pending', function(test) { var fmt = color('checkmark', ' -') + color('pending', ' %s'); console.log(fmt, test.fullTitle()); }); - runner.on('pass', function(test){ - var fmt = color('checkmark', ' '+Base.symbols.dot) + runner.on('pass', function(test) { + var fmt = color('checkmark', ' ' + Base.symbols.dot) + color('pass', ' %s: ') + color(test.speed, '%dms'); cursor.CR(); console.log(fmt, test.fullTitle(), test.duration); }); - runner.on('fail', function(test, err){ + runner.on('fail', function(test) { cursor.CR(); console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); }); diff --git a/lib/reporters/markdown.js b/lib/reporters/markdown.js index e14174c30e..ac054506b7 100644 --- a/lib/reporters/markdown.js +++ b/lib/reporters/markdown.js @@ -2,8 +2,8 @@ * Module dependencies. */ -var Base = require('./base') - , utils = require('../utils'); +var Base = require('./base'); +var utils = require('../utils'); /** * Constants @@ -20,33 +20,28 @@ exports = module.exports = Markdown; /** * Initialize a new `Markdown` reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function Markdown(runner) { Base.call(this, runner); - var self = this - , stats = this.stats - , level = 0 - , buf = ''; + var level = 0; + var buf = ''; function title(str) { return Array(level).join('#') + ' ' + str; } - function indent() { - return Array(level).join(' '); - } - function mapTOC(suite, obj) { - var ret = obj, - key = SUITE_PREFIX + suite.title; + var ret = obj; + var key = SUITE_PREFIX + suite.title; + obj = obj[key] = obj[key] || { suite: suite }; - suite.suites.forEach(function(suite){ + suite.suites.forEach(function() { mapTOC(suite, obj); }); + return ret; } @@ -55,7 +50,9 @@ function Markdown(runner) { var buf = ''; var link; for (var key in obj) { - if ('suite' == key) continue; + if (key === 'suite') { + continue; + } if (key !== SUITE_PREFIX) { link = ' - [' + key.substring(1) + ']'; link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; @@ -73,18 +70,18 @@ function Markdown(runner) { generateTOC(runner.suite); - runner.on('suite', function(suite){ + runner.on('suite', function(suite) { ++level; var slug = utils.slug(suite.fullTitle()); buf += '' + '\n'; buf += title(suite.title) + '\n'; }); - runner.on('suite end', function(suite){ + runner.on('suite end', function() { --level; }); - runner.on('pass', function(test){ + runner.on('pass', function(test) { var code = utils.clean(test.fn.toString()); buf += test.title + '.\n'; buf += '\n```js\n'; @@ -92,7 +89,7 @@ function Markdown(runner) { buf += '```\n\n'; }); - runner.on('end', function(){ + runner.on('end', function() { process.stdout.write('# TOC\n'); process.stdout.write(generateTOC(runner.suite)); process.stdout.write(buf); diff --git a/lib/reporters/min.js b/lib/reporters/min.js index ce1a3fef12..f0b85578d0 100644 --- a/lib/reporters/min.js +++ b/lib/reporters/min.js @@ -13,14 +13,13 @@ exports = module.exports = Min; /** * Initialize a new `Min` minimal test reporter (best used with --watch). * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function Min(runner) { Base.call(this, runner); - runner.on('start', function(){ + runner.on('start', function() { // clear screen process.stdout.write('\u001b[2J'); // set cursor position diff --git a/lib/reporters/nyan.js b/lib/reporters/nyan.js index 63056b1777..21b7749868 100644 --- a/lib/reporters/nyan.js +++ b/lib/reporters/nyan.js @@ -19,39 +19,41 @@ exports = module.exports = NyanCat; function NyanCat(runner) { Base.call(this, runner); - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , rainbowColors = this.rainbowColors = self.generateColors() - , colorIndex = this.colorIndex = 0 - , numerOfLines = this.numberOfLines = 4 - , trajectories = this.trajectories = [[], [], [], []] - , nyanCatWidth = this.nyanCatWidth = 11 - , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) - , scoreboardWidth = this.scoreboardWidth = 5 - , tick = this.tick = 0 - , n = 0; - - runner.on('start', function(){ + + var self = this; + var width = Base.window.width * .75 | 0; + var nyanCatWidth = this.nyanCatWidth = 11; + + this.colorIndex = 0; + this.numberOfLines = 4; + this.rainbowColors = self.generateColors(); + this.scoreboardWidth = 5; + this.tick = 0; + this.trajectories = [[], [], [], []]; + this.trajectoryWidthMax = (width - nyanCatWidth); + + runner.on('start', function() { Base.cursor.hide(); self.draw(); }); - runner.on('pending', function(test){ + runner.on('pending', function() { self.draw(); }); - runner.on('pass', function(test){ + runner.on('pass', function() { self.draw(); }); - runner.on('fail', function(test, err){ + runner.on('fail', function() { self.draw(); }); - runner.on('end', function(){ + runner.on('end', function() { Base.cursor.show(); - for (var i = 0; i < self.numberOfLines; i++) write('\n'); + for (var i = 0; i < self.numberOfLines; i++) { + write('\n'); + } self.epilogue(); }); } @@ -62,7 +64,7 @@ function NyanCat(runner) { * @api private */ -NyanCat.prototype.draw = function(){ +NyanCat.prototype.draw = function() { this.appendRainbow(); this.drawScoreboard(); this.drawRainbow(); @@ -77,7 +79,7 @@ NyanCat.prototype.draw = function(){ * @api private */ -NyanCat.prototype.drawScoreboard = function(){ +NyanCat.prototype.drawScoreboard = function() { var stats = this.stats; function draw(type, n) { @@ -100,13 +102,15 @@ NyanCat.prototype.drawScoreboard = function(){ * @api private */ -NyanCat.prototype.appendRainbow = function(){ +NyanCat.prototype.appendRainbow = function() { var segment = this.tick ? '_' : '-'; var rainbowified = this.rainbowify(segment); for (var index = 0; index < this.numberOfLines; index++) { var trajectory = this.trajectories[index]; - if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); + if (trajectory.length >= this.trajectoryWidthMax) { + trajectory.shift(); + } trajectory.push(rainbowified); } }; @@ -117,10 +121,10 @@ NyanCat.prototype.appendRainbow = function(){ * @api private */ -NyanCat.prototype.drawRainbow = function(){ +NyanCat.prototype.drawRainbow = function() { var self = this; - this.trajectories.forEach(function(line, index) { + this.trajectories.forEach(function(line) { write('\u001b[' + self.scoreboardWidth + 'C'); write(line.join('')); write('\n'); @@ -134,7 +138,6 @@ NyanCat.prototype.drawRainbow = function(){ * * @api private */ - NyanCat.prototype.drawNyanCat = function() { var self = this; var startWidth = this.scoreboardWidth + this.trajectories[0].length; @@ -153,7 +156,6 @@ NyanCat.prototype.drawNyanCat = function() { write(dist); padding = self.tick ? '_' : '__'; var tail = self.tick ? '~' : '^'; - var face; write(tail + '|' + padding + this.face() + ' '); write('\n'); @@ -168,8 +170,8 @@ NyanCat.prototype.drawNyanCat = function() { /** * Draw nyan cat face. * - * @return {String} * @api private + * @return {string} */ NyanCat.prototype.face = function() { @@ -178,18 +180,17 @@ NyanCat.prototype.face = function() { return '( x .x)'; } else if (stats.pending) { return '( o .o)'; - } else if(stats.passes) { + } else if (stats.passes) { return '( ^ .^)'; - } else { - return '( - .-)'; } + return '( - .-)'; }; /** * Move cursor up `n`. * - * @param {Number} n * @api private + * @param {number} n */ NyanCat.prototype.cursorUp = function(n) { @@ -199,8 +200,8 @@ NyanCat.prototype.cursorUp = function(n) { /** * Move cursor down `n`. * - * @param {Number} n * @api private + * @param {number} n */ NyanCat.prototype.cursorDown = function(n) { @@ -210,11 +211,10 @@ NyanCat.prototype.cursorDown = function(n) { /** * Generate rainbow colors. * - * @return {Array} * @api private + * @return {Array} */ - -NyanCat.prototype.generateColors = function(){ +NyanCat.prototype.generateColors = function() { var colors = []; for (var i = 0; i < (6 * 7); i++) { @@ -232,14 +232,14 @@ NyanCat.prototype.generateColors = function(){ /** * Apply rainbow to the given `str`. * - * @param {String} str - * @return {String} * @api private + * @param {string} str + * @return {string} */ - -NyanCat.prototype.rainbowify = function(str){ - if (!Base.useColors) +NyanCat.prototype.rainbowify = function(str) { + if (!Base.useColors) { return str; + } var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; this.colorIndex += 1; return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; @@ -247,8 +247,9 @@ NyanCat.prototype.rainbowify = function(str){ /** * Stdout helper. + * + * @param {string} string A message to write to stdout. */ - function write(string) { process.stdout.write(string); } diff --git a/lib/reporters/progress.js b/lib/reporters/progress.js index 2debb94541..29c6785451 100644 --- a/lib/reporters/progress.js +++ b/lib/reporters/progress.js @@ -2,9 +2,9 @@ * Module dependencies. */ -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; +var Base = require('./base'); +var color = Base.color; +var cursor = Base.cursor; /** * Expose `Progress`. @@ -21,24 +21,21 @@ Base.colors.progress = 90; /** * Initialize a new `Progress` bar test reporter. * + * @api public * @param {Runner} runner * @param {Object} options - * @api public */ - function Progress(runner, options) { Base.call(this, runner); - var self = this - , options = options || {} - , stats = this.stats - , width = Base.window.width * .50 | 0 - , total = runner.total - , complete = 0 - , max = Math.max - , lastN = -1; + var self = this; + var width = Base.window.width * .50 | 0; + var total = runner.total; + var complete = 0; + var lastN = -1; // default chars + options = options || {}; options.open = options.open || '['; options.complete = options.complete || '▬'; options.incomplete = options.incomplete || Base.symbols.dot; @@ -46,20 +43,20 @@ function Progress(runner, options) { options.verbose = false; // tests started - runner.on('start', function(){ + runner.on('start', function() { console.log(); cursor.hide(); }); // tests complete - runner.on('test end', function(){ + runner.on('test end', function() { complete++; - var incomplete = total - complete - , percent = complete / total - , n = width * percent | 0 - , i = width - n; - if (lastN === n && !options.verbose) { + var percent = complete / total; + var n = width * percent | 0; + var i = width - n; + + if (n === lastN && !options.verbose) { // Don't re-render the line if it hasn't changed return; } @@ -78,7 +75,7 @@ function Progress(runner, options) { // tests are complete, output some stats // and the failures if any - runner.on('end', function(){ + runner.on('end', function() { cursor.show(); console.log(); self.epilogue(); diff --git a/lib/reporters/spec.js b/lib/reporters/spec.js index 3debffe26f..1b447c1738 100644 --- a/lib/reporters/spec.js +++ b/lib/reporters/spec.js @@ -2,9 +2,9 @@ * Module dependencies. */ -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; +var Base = require('./base'); +var color = Base.color; +var cursor = Base.cursor; /** * Expose `Spec`. @@ -15,50 +15,51 @@ exports = module.exports = Spec; /** * Initialize a new `Spec` test reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function Spec(runner) { Base.call(this, runner); - var self = this - , stats = this.stats - , indents = 0 - , n = 0; + var self = this; + var indents = 0; + var n = 0; function indent() { - return Array(indents).join(' ') + return Array(indents).join(' '); } - runner.on('start', function(){ + runner.on('start', function() { console.log(); }); - runner.on('suite', function(suite){ + runner.on('suite', function(suite) { ++indents; console.log(color('suite', '%s%s'), indent(), suite.title); }); - runner.on('suite end', function(suite){ + runner.on('suite end', function() { --indents; - if (1 == indents) console.log(); + if (indents === 1) { + console.log(); + } }); - runner.on('pending', function(test){ + runner.on('pending', function(test) { var fmt = indent() + color('pending', ' - %s'); console.log(fmt, test.title); }); - runner.on('pass', function(test){ - if ('fast' == test.speed) { - var fmt = indent() + runner.on('pass', function(test) { + var fmt; + if (test.speed === 'fast') { + fmt = indent() + color('checkmark', ' ' + Base.symbols.ok) + color('pass', ' %s'); cursor.CR(); console.log(fmt, test.title); } else { - var fmt = indent() + fmt = indent() + color('checkmark', ' ' + Base.symbols.ok) + color('pass', ' %s') + color(test.speed, ' (%dms)'); @@ -67,7 +68,7 @@ function Spec(runner) { } }); - runner.on('fail', function(test, err){ + runner.on('fail', function(test) { cursor.CR(); console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); }); diff --git a/lib/reporters/tap.js b/lib/reporters/tap.js index 01a92eb076..d9b1b953aa 100644 --- a/lib/reporters/tap.js +++ b/lib/reporters/tap.js @@ -2,9 +2,7 @@ * Module dependencies. */ -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; +var Base = require('./base'); /** * Expose `TAP`. @@ -15,44 +13,43 @@ exports = module.exports = TAP; /** * Initialize a new `TAP` reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function TAP(runner) { Base.call(this, runner); - var self = this - , stats = this.stats - , n = 1 - , passes = 0 - , failures = 0; + var n = 1; + var passes = 0; + var failures = 0; - runner.on('start', function(){ + runner.on('start', function() { var total = runner.grepTotal(runner.suite); console.log('%d..%d', 1, total); }); - runner.on('test end', function(){ + runner.on('test end', function() { ++n; }); - runner.on('pending', function(test){ + runner.on('pending', function(test) { console.log('ok %d %s # SKIP -', n, title(test)); }); - runner.on('pass', function(test){ + runner.on('pass', function(test) { passes++; console.log('ok %d %s', n, title(test)); }); - runner.on('fail', function(test, err){ + runner.on('fail', function(test, err) { failures++; console.log('not ok %d %s', n, title(test)); - if (err.stack) console.log(err.stack.replace(/^/gm, ' ')); + if (err.stack) { + console.log(err.stack.replace(/^/gm, ' ')); + } }); - runner.on('end', function(){ + runner.on('end', function() { console.log('# tests ' + (passes + failures)); console.log('# pass ' + passes); console.log('# fail ' + failures); @@ -62,11 +59,10 @@ function TAP(runner) { /** * Return a TAP-safe title of `test` * + * @api private * @param {Object} test * @return {String} - * @api private */ - function title(test) { return test.fullTitle().replace(/#/g, ''); } diff --git a/lib/reporters/xunit.js b/lib/reporters/xunit.js index 77cd347094..8286cd3f52 100644 --- a/lib/reporters/xunit.js +++ b/lib/reporters/xunit.js @@ -2,20 +2,21 @@ * Module dependencies. */ -var Base = require('./base') - , utils = require('../utils') - , fs = require('fs') - , escape = utils.escape; +var Base = require('./base'); +var fs = require('fs'); +var escape = require('../utils').escape; /** * Save timer references to avoid Sinon interfering (see GH-237). */ -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; +/* eslint-disable no-unused-vars, no-native-reassign */ +var Date = global.Date; +var setTimeout = global.setTimeout; +var setInterval = global.setInterval; +var clearTimeout = global.clearTimeout; +var clearInterval = global.clearInterval; +/* eslint-enable no-unused-vars, no-native-reassign */ /** * Expose `XUnit`. @@ -26,62 +27,68 @@ exports = module.exports = XUnit; /** * Initialize a new `XUnit` reporter. * - * @param {Runner} runner * @api public + * @param {Runner} runner */ - function XUnit(runner, options) { Base.call(this, runner); - var stats = this.stats - , tests = [] - , self = this; + + var stats = this.stats; + var tests = []; + var self = this; if (options.reporterOptions && options.reporterOptions.output) { - if (! fs.createWriteStream) { - throw new Error('file output not supported in browser'); - } - self.fileStream = fs.createWriteStream(options.reporterOptions.output); + if (!fs.createWriteStream) { + throw new Error('file output not supported in browser'); + } + self.fileStream = fs.createWriteStream(options.reporterOptions.output); } - runner.on('pending', function(test){ + runner.on('pending', function(test) { tests.push(test); }); - runner.on('pass', function(test){ + runner.on('pass', function(test) { tests.push(test); }); - runner.on('fail', function(test){ + runner.on('fail', function(test) { tests.push(test); }); - runner.on('end', function(){ + runner.on('end', function() { self.write(tag('testsuite', { - name: 'Mocha Tests' - , tests: stats.tests - , failures: stats.failures - , errors: stats.failures - , skipped: stats.tests - stats.failures - stats.passes - , timestamp: (new Date).toUTCString() - , time: (stats.duration / 1000) || 0 + name: 'Mocha Tests', + tests: stats.tests, + failures: stats.failures, + errors: stats.failures, + skipped: stats.tests - stats.failures - stats.passes, + timestamp: (new Date()).toUTCString(), + time: (stats.duration / 1000) || 0 }, false)); - tests.forEach(function(t) { self.test(t); }); + tests.forEach(function(t) { + self.test(t); + }); + self.write(''); }); } /** * Override done to close the stream (if it's a file). + * + * @param failures + * @param {Function} fn */ XUnit.prototype.done = function(failures, fn) { - if (this.fileStream) { - this.fileStream.end(function() { - fn(failures); - }); - } else { - fn(failures); - } + if (this.fileStream) { + this.fileStream.end(function() { + fn(failures); + }); + } else { + fn(failures); + } }; /** @@ -91,52 +98,64 @@ XUnit.prototype.done = function(failures, fn) { XUnit.prototype.__proto__ = Base.prototype; /** - * Write out the given line + * Write out the given line. + * + * @param {string} line */ XUnit.prototype.write = function(line) { - if (this.fileStream) { - this.fileStream.write(line + '\n'); - } else { - console.log(line); - } + if (this.fileStream) { + this.fileStream.write(line + '\n'); + } else { + console.log(line); + } }; /** * Output tag for the given `test.` + * + * @param {Test} test */ - -XUnit.prototype.test = function(test, ostream) { +XUnit.prototype.test = function(test) { var attrs = { - classname: test.parent.fullTitle() - , name: test.title - , time: (test.duration / 1000) || 0 + classname: test.parent.fullTitle(), + name: test.title, + time: (test.duration / 1000) || 0 }; - if ('failed' == test.state) { + if (test.state === 'failed') { var err = test.err; - this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack)))); + this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + '\n' + err.stack)))); } else if (test.pending) { this.write(tag('testcase', attrs, false, tag('skipped', {}, true))); } else { - this.write(tag('testcase', attrs, true) ); + this.write(tag('testcase', attrs, true)); } }; /** * HTML tag helper. + * + * @param name + * @param attrs + * @param close + * @param content + * @return {string} */ - function tag(name, attrs, close, content) { - var end = close ? '/>' : '>' - , pairs = [] - , tag; + var end = close ? '/>' : '>'; + var pairs = []; + var tag; for (var key in attrs) { - pairs.push(key + '="' + escape(attrs[key]) + '"'); + if (Object.prototype.hasOwnProperty.call(attrs, key)) { + pairs.push(key + '="' + escape(attrs[key]) + '"'); + } } tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; - if (content) tag += content + ''; - if ('ctx' == key) return '#'; +Runnable.prototype.inspect = function() { + return JSON.stringify(this, function(key, val) { + if (key[0] === '_') { + return; + } + if (key === 'parent') { + return '#'; + } + if (key === 'ctx') { + return '#'; + } return val; }, 2); }; @@ -158,50 +172,56 @@ Runnable.prototype.inspect = function(){ * * @api private */ - -Runnable.prototype.resetTimeout = function(){ +Runnable.prototype.resetTimeout = function() { var self = this; var ms = this.timeout() || 1e9; - if (!this._enableTimeouts) return; + if (!this._enableTimeouts) { + return; + } this.clearTimeout(); - this.timer = setTimeout(function(){ - if (!self._enableTimeouts) return; + this.timer = setTimeout(function() { + if (!self._enableTimeouts) { + return; + } self.callback(new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.')); self.timedOut = true; }, ms); }; /** - * Whitelist these globals for this test run + * Whitelist a list of globals for this test run. * * @api private + * @param {string[]} globals */ -Runnable.prototype.globals = function(arr){ - var self = this; - this._allowedGlobals = arr; +Runnable.prototype.globals = function(globals) { + this._allowedGlobals = globals; }; /** * Run the test and invoke `fn(err)`. * - * @param {Function} fn * @api private + * @param {Function} fn */ - -Runnable.prototype.run = function(fn){ - var self = this - , start = new Date - , ctx = this.ctx - , finished - , emitted; - - // Some times the ctx exists but it is not runnable - if (ctx && ctx.runnable) ctx.runnable(this); +Runnable.prototype.run = function(fn) { + var self = this; + var start = new Date(); + var ctx = this.ctx; + var finished; + var emitted; + + // Sometimes the ctx exists, but it is not runnable + if (ctx && ctx.runnable) { + ctx.runnable(this); + } // called multiple times function multiple(err) { - if (emitted) return; + if (emitted) { + return; + } emitted = true; self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate')); } @@ -209,13 +229,19 @@ Runnable.prototype.run = function(fn){ // finished function done(err) { var ms = self.timeout(); - if (self.timedOut) return; - if (finished) return multiple(err || self._trace); + if (self.timedOut) { + return; + } + if (finished) { + return multiple(err || self._trace); + } self.clearTimeout(); - self.duration = new Date - start; + self.duration = new Date() - start; finished = true; - if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.'); + if (!err && self.duration > ms && self._enableTimeouts) { + err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.'); + } fn(err); } @@ -227,14 +253,15 @@ Runnable.prototype.run = function(fn){ this.resetTimeout(); try { - this.fn.call(ctx, function(err){ - if (err instanceof Error || toString.call(err) === "[object Error]") return done(err); - if (null != err) { + this.fn.call(ctx, function(err) { + if (err instanceof Error || toString.call(err) === '[object Error]') { + return done(err); + } + if (err != null) { if (Object.prototype.toString.call(err) === '[object Object]') { return done(new Error('done() invoked with non-Error: ' + JSON.stringify(err))); - } else { - return done(new Error('done() invoked with non-Error: ' + err)); } + return done(new Error('done() invoked with non-Error: ' + err)); } done(); }); @@ -265,10 +292,10 @@ Runnable.prototype.run = function(fn){ self.resetTimeout(); result .then(function() { - done() + done(); }, function(reason) { - done(reason || new Error('Promise rejected with no or falsy reason')) + done(reason || new Error('Promise rejected with no or falsy reason')); }); } else { done(); diff --git a/lib/runner.js b/lib/runner.js index 23ddaf23b4..353ff0cc46 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -2,16 +2,16 @@ * Module dependencies. */ -var EventEmitter = require('events').EventEmitter - , debug = require('debug')('mocha:runner') - , Pending = require('./pending') - , Test = require('./test') - , utils = require('./utils') - , filter = utils.filter - , keys = utils.keys - , type = utils.type - , stringify = utils.stringify - , stackFilter = utils.stackTraceFilter(); +var EventEmitter = require('events').EventEmitter; +var Pending = require('./pending'); +var debug = require('debug')('mocha:runner'); +var filter = require('./utils').filter; +var indexOf = require('./utils').indexOf; +var keys = require('./utils').keys; +var stackFilter = require('./utils').stackTraceFilter(); +var stringify = require('./utils').stringify; +var type = require('./utils').type; +var undefinedError = require('./utils').undefinedError; /** * Non-enumerable globals. @@ -51,12 +51,11 @@ module.exports = Runner; * - `fail` (test, err) test failed * - `pending` (test) test pending * + * @api public * @param {Suite} suite Root suite * @param {boolean} [delay] Whether or not to delay execution of root suite - * until ready. - * @api public + * until ready. */ - function Runner(suite, delay) { var self = this; this._globals = []; @@ -65,8 +64,12 @@ function Runner(suite, delay) { this.suite = suite; this.total = suite.total(); this.failures = 0; - this.on('test end', function(test){ self.checkGlobals(test); }); - this.on('hook end', function(hook){ self.checkGlobals(hook); }); + this.on('test end', function(test) { + self.checkGlobals(test); + }); + this.on('hook end', function(hook) { + self.checkGlobals(hook); + }); this.grep(/.*/); this.globals(this.globalProps().concat(extraGlobals())); } @@ -74,10 +77,9 @@ function Runner(suite, delay) { /** * Wrapper for setImmediate, process.nextTick, or browser polyfill. * - * @param {Function} fn * @api private + * @param {Function} fn */ - Runner.immediately = global.setImmediate || process.nextTick; /** @@ -90,13 +92,12 @@ Runner.prototype.__proto__ = EventEmitter.prototype; * Run tests with full titles matching `re`. Updates runner.total * with number of tests matched. * - * @param {RegExp} re - * @param {Boolean} invert - * @return {Runner} for chaining * @api public + * @param {RegExp} re + * @param {boolean} invert + * @return {Runner} Runner instance. */ - -Runner.prototype.grep = function(re, invert){ +Runner.prototype.grep = function(re, invert) { debug('grep %s', re); this._grep = re; this._invert = invert; @@ -108,19 +109,22 @@ Runner.prototype.grep = function(re, invert){ * Returns the number of tests matching the grep search for the * given suite. * - * @param {Suite} suite - * @return {Number} * @api public + * @param {Suite} suite + * @return {number} */ - Runner.prototype.grepTotal = function(suite) { var self = this; var total = 0; - suite.eachTest(function(test){ + suite.eachTest(function(test) { var match = self._grep.test(test.fullTitle()); - if (self._invert) match = !match; - if (match) total++; + if (self._invert) { + match = !match; + } + if (match) { + total++; + } }); return total; @@ -129,16 +133,17 @@ Runner.prototype.grepTotal = function(suite) { /** * Return a list of global properties. * - * @return {Array} * @api private + * @return {Array} */ - Runner.prototype.globalProps = function() { - var props = utils.keys(global); + var props = keys(global); // non-enumerables for (var i = 0; i < globals.length; ++i) { - if (~utils.indexOf(props, globals[i])) continue; + if (~indexOf(props, globals[i])) { + continue; + } props.push(globals[i]); } @@ -148,13 +153,14 @@ Runner.prototype.globalProps = function() { /** * Allow the given `arr` of globals. * - * @param {Array} arr - * @return {Runner} for chaining * @api public + * @param {Array} arr + * @return {Runner} Runner instance. */ - -Runner.prototype.globals = function(arr){ - if (0 == arguments.length) return this._globals; +Runner.prototype.globals = function(arr) { + if (!arguments.length) { + return this._globals; + } debug('globals %j', arr); this._globals = this._globals.concat(arr); return this; @@ -165,9 +171,10 @@ Runner.prototype.globals = function(arr){ * * @api private */ - -Runner.prototype.checkGlobals = function(test){ - if (this.ignoreLeaks) return; +Runner.prototype.checkGlobals = function(test) { + if (this.ignoreLeaks) { + return; + } var ok = this._globals; var globals = this.globalProps(); @@ -177,7 +184,9 @@ Runner.prototype.checkGlobals = function(test){ ok = ok.concat(test._allowedGlobals || []); } - if(this.prevGlobalsLength == globals.length) return; + if (this.prevGlobalsLength === globals.length) { + return; + } this.prevGlobalsLength = globals.length; leaks = filterLeaks(ok, globals); @@ -193,11 +202,10 @@ Runner.prototype.checkGlobals = function(test){ /** * Fail the given `test`. * + * @api private * @param {Test} test * @param {Error} err - * @api private */ - Runner.prototype.fail = function(test, err) { ++this.failures; test.state = 'failed'; @@ -229,12 +237,11 @@ Runner.prototype.fail = function(test, err) { * suite and subsuites, but executes other `after each` * hooks * + * @api private * @param {Hook} hook * @param {Error} err - * @api private */ - -Runner.prototype.failHook = function(hook, err){ +Runner.prototype.failHook = function(hook, err) { this.fail(hook, err); if (this.suite.bail()) { this.emit('end'); @@ -244,34 +251,36 @@ Runner.prototype.failHook = function(hook, err){ /** * Run hook `name` callbacks and then invoke `fn()`. * - * @param {String} name - * @param {Function} function * @api private + * @param {string} name + * @param {Function} fn */ - -Runner.prototype.hook = function(name, fn){ - var suite = this.suite - , hooks = suite['_' + name] - , self = this - , timer; +Runner.prototype.hook = function(name, fn) { + var suite = this.suite; + var hooks = suite['_' + name]; + var self = this; function next(i) { var hook = hooks[i]; - if (!hook) return fn(); + if (!hook) { + return fn(); + } self.currentRunnable = hook; hook.ctx.currentTest = self.test; self.emit('hook', hook); - hook.on('error', function(err){ + hook.on('error', function(err) { self.failHook(hook, err); }); - hook.run(function(err){ + hook.run(function(err) { hook.removeAllListeners('error'); var testError = hook.error(); - if (testError) self.fail(self.test, testError); + if (testError) { + self.fail(self.test, testError); + } if (err) { if (err instanceof Pending) { suite.pending = true; @@ -288,7 +297,7 @@ Runner.prototype.hook = function(name, fn){ }); } - Runner.immediately(function(){ + Runner.immediately(function() { next(0); }); }; @@ -297,15 +306,14 @@ Runner.prototype.hook = function(name, fn){ * Run hook `name` for the given array of `suites` * in order, and callback `fn(err, errSuite)`. * - * @param {String} name + * @api private + * @param {string} name * @param {Array} suites * @param {Function} fn - * @api private */ - -Runner.prototype.hooks = function(name, suites, fn){ - var self = this - , orig = this.suite; +Runner.prototype.hooks = function(name, suites, fn) { + var self = this; + var orig = this.suite; function next(suite) { self.suite = suite; @@ -315,7 +323,7 @@ Runner.prototype.hooks = function(name, suites, fn){ return fn(); } - self.hook(name, function(err){ + self.hook(name, function(err) { if (err) { var errSuite = self.suite; self.suite = orig; @@ -332,12 +340,11 @@ Runner.prototype.hooks = function(name, suites, fn){ /** * Run hooks from the top level down. * - * @param {String} name - * @param {Function} fn * @api private + * @param {string} name + * @param {Function} fn */ - -Runner.prototype.hookUp = function(name, fn){ +Runner.prototype.hookUp = function(name, fn) { var suites = [this.suite].concat(this.parents()).reverse(); this.hooks(name, suites, fn); }; @@ -345,12 +352,11 @@ Runner.prototype.hookUp = function(name, fn){ /** * Run hooks from the bottom up. * - * @param {String} name - * @param {Function} fn * @api private + * @param {string} name + * @param {Function} fn */ - -Runner.prototype.hookDown = function(name, fn){ +Runner.prototype.hookDown = function(name, fn) { var suites = [this.suite].concat(this.parents()); this.hooks(name, suites, fn); }; @@ -359,32 +365,34 @@ Runner.prototype.hookDown = function(name, fn){ * Return an array of parent Suites from * closest to furthest. * - * @return {Array} * @api private + * @return {Array} */ - -Runner.prototype.parents = function(){ - var suite = this.suite - , suites = []; - while (suite = suite.parent) suites.push(suite); +Runner.prototype.parents = function() { + var suite = this.suite; + var suites = []; + while (suite = suite.parent) { + suites.push(suite); + } return suites; }; /** * Run the current test and callback `fn(err)`. * - * @param {Function} fn * @api private + * @param {Function} fn */ +Runner.prototype.runTest = function(fn) { + var self = this; + var test = this.test; -Runner.prototype.runTest = function(fn){ - var test = this.test - , self = this; - - if (this.asyncOnly) test.asyncOnly = true; + if (this.asyncOnly) { + test.asyncOnly = true; + } try { - test.on('error', function(err){ + test.on('error', function(err) { self.fail(test, err); }); test.run(fn); @@ -394,21 +402,18 @@ Runner.prototype.runTest = function(fn){ }; /** - * Run tests in the given `suite` and invoke - * the callback `fn()` when complete. + * Run tests in the given `suite` and invoke the callback `fn()` when complete. * + * @api private * @param {Suite} suite * @param {Function} fn - * @api private */ +Runner.prototype.runTests = function(suite, fn) { + var self = this; + var tests = suite.tests.slice(); + var test; -Runner.prototype.runTests = function(suite, fn){ - var self = this - , tests = suite.tests.slice() - , test; - - - function hookErr(err, errSuite, after) { + function hookErr(_, errSuite, after) { // before/after Each hook for errSuite failed: var orig = self.suite; @@ -421,7 +426,9 @@ Runner.prototype.runTests = function(suite, fn){ self.hookUp('afterEach', function(err2, errSuite2) { self.suite = orig; // some hooks may fail even now - if (err2) return hookErr(err2, errSuite2, true); + if (err2) { + return hookErr(err2, errSuite2, true); + } // report error suite fn(errSuite); }); @@ -434,22 +441,34 @@ Runner.prototype.runTests = function(suite, fn){ function next(err, errSuite) { // if we bail after first err - if (self.failures && suite._bail) return fn(); + if (self.failures && suite._bail) { + return fn(); + } - if (self._abort) return fn(); + if (self._abort) { + return fn(); + } - if (err) return hookErr(err, errSuite, true); + if (err) { + return hookErr(err, errSuite, true); + } // next test test = tests.shift(); // all done - if (!test) return fn(); + if (!test) { + return fn(); + } // grep var match = self._grep.test(test.fullTitle()); - if (self._invert) match = !match; - if (!match) return next(); + if (self._invert) { + match = !match; + } + if (!match) { + return next(); + } // pending if (test.pending) { @@ -460,17 +479,17 @@ Runner.prototype.runTests = function(suite, fn){ // execute test and hook(s) self.emit('test', self.test = test); - self.hookDown('beforeEach', function(err, errSuite){ - + self.hookDown('beforeEach', function(err, errSuite) { if (suite.pending) { self.emit('pending', test); self.emit('test end', test); return next(); } - if (err) return hookErr(err, errSuite, false); - + if (err) { + return hookErr(err, errSuite, false); + } self.currentRunnable = self.test; - self.runTest(function(err){ + self.runTest(function(err) { test = self.test; if (err) { @@ -501,56 +520,61 @@ Runner.prototype.runTests = function(suite, fn){ }; /** - * Run the given `suite` and invoke the - * callback `fn()` when complete. + * Run the given `suite` and invoke the callback `fn()` when complete. * + * @api private * @param {Suite} suite * @param {Function} fn - * @api private */ - -Runner.prototype.runSuite = function(suite, fn){ - var total = this.grepTotal(suite) - , self = this - , i = 0; +Runner.prototype.runSuite = function(suite, fn) { + var i = 0; + var self = this; + var total = this.grepTotal(suite); debug('run suite %s', suite.fullTitle()); - if (!total) return fn(); + if (!total) { + return fn(); + } this.emit('suite', this.suite = suite); function next(errSuite) { if (errSuite) { // current suite failed on a hook from errSuite - if (errSuite == suite) { + if (errSuite === suite) { // if errSuite is current suite // continue to the next sibling suite return done(); - } else { - // errSuite is among the parents of current suite - // stop execution of errSuite and all sub-suites - return done(errSuite); } + // errSuite is among the parents of current suite + // stop execution of errSuite and all sub-suites + return done(errSuite); } - if (self._abort) return done(); + if (self._abort) { + return done(); + } var curr = suite.suites[i++]; - if (!curr) return done(); + if (!curr) { + return done(); + } self.runSuite(curr, next); } function done(errSuite) { self.suite = suite; - self.hook('afterAll', function(){ + self.hook('afterAll', function() { self.emit('suite end', suite); fn(errSuite); }); } - this.hook('beforeAll', function(err){ - if (err) return done(); + this.hook('beforeAll', function(err) { + if (err) { + return done(); + } self.runTests(suite, next); }); }; @@ -558,32 +582,35 @@ Runner.prototype.runSuite = function(suite, fn){ /** * Handle uncaught exceptions. * - * @param {Error} err * @api private + * @param {Error} err */ - -Runner.prototype.uncaught = function(err){ +Runner.prototype.uncaught = function(err) { if (err) { - debug('uncaught exception %s', err !== function () { + debug('uncaught exception %s', err !== function() { return this; - }.call(err) ? err : ( err.message || err )); + }.call(err) ? err : (err.message || err)); } else { debug('uncaught undefined exception'); - err = utils.undefinedError(); + err = undefinedError(); } err.uncaught = true; var runnable = this.currentRunnable; - if (!runnable) return; + if (!runnable) { + return; + } runnable.clearTimeout(); // Ignore errors if complete - if (runnable.state) return; + if (runnable.state) { + return; + } this.fail(runnable, err); // recover from test - if ('test' == runnable.type) { + if (runnable.type === 'test') { this.emit('test end', runnable); this.hookUp('afterEach', this.next); return; @@ -597,24 +624,23 @@ Runner.prototype.uncaught = function(err){ * Run the root suite and invoke `fn(failures)` * on completion. * - * @param {Function} fn - * @return {Runner} for chaining * @api public + * @param {Function} fn + * @return {Runner} Runner instance. */ +Runner.prototype.run = function(fn) { + var self = this; + var rootSuite = this.suite; -Runner.prototype.run = function(fn){ - var self = this, - rootSuite = this.suite; - - fn = fn || function(){}; + fn = fn || function() {}; - function uncaught(err){ + function uncaught(err) { self.uncaught(err); } function start() { self.emit('start'); - self.runSuite(rootSuite, function(){ + self.runSuite(rootSuite, function() { debug('finished running'); self.emit('end'); }); @@ -623,7 +649,7 @@ Runner.prototype.run = function(fn){ debug('start'); // callback - this.on('end', function(){ + this.on('end', function() { debug('end'); process.removeListener('uncaughtException', uncaught); fn(self.failures); @@ -637,8 +663,7 @@ Runner.prototype.run = function(fn){ // might be nice to debounce some dots while we wait. this.emit('waiting', rootSuite); rootSuite.once('run', start); - } - else { + } else { start(); } @@ -646,71 +671,79 @@ Runner.prototype.run = function(fn){ }; /** - * Cleanly abort execution + * Cleanly abort execution. * - * @return {Runner} for chaining * @api public + * @return {Runner} Runner instance. */ -Runner.prototype.abort = function(){ +Runner.prototype.abort = function() { debug('aborting'); this._abort = true; + + return this; }; /** * Filter leaks with the given globals flagged as `ok`. * + * @api private * @param {Array} ok * @param {Array} globals * @return {Array} - * @api private */ - function filterLeaks(ok, globals) { - return filter(globals, function(key){ + return filter(globals, function(key) { // Firefox and Chrome exposes iframes as index inside the window object - if (/^d+/.test(key)) return false; + if (/^d+/.test(key)) { + return false; + } // in firefox // if runner runs in an iframe, this iframe's window.getInterface method not init at first // it is assigned in some seconds - if (global.navigator && /^getInterface/.test(key)) return false; + if (global.navigator && (/^getInterface/).test(key)) { + return false; + } // an iframe could be approached by window[iframeIndex] // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak - if (global.navigator && /^\d+/.test(key)) return false; + if (global.navigator && (/^\d+/).test(key)) { + return false; + } // Opera and IE expose global variables for HTML element IDs (issue #243) - if (/^mocha-/.test(key)) return false; + if (/^mocha-/.test(key)) { + return false; + } - var matched = filter(ok, function(ok){ - if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); - return key == ok; + var matched = filter(ok, function(ok) { + if (~ok.indexOf('*')) { + return key.indexOf(ok.split('*')[0]) === 0; + } + return key === ok; }); - return matched.length == 0 && (!global.navigator || 'onerror' !== key); + return !matched.length && (!global.navigator || key !== 'onerror'); }); } /** * Array of globals dependent on the environment. * - * @return {Array} * @api private + * @return {Array} */ - function extraGlobals() { - if (typeof(process) === 'object' && - typeof(process.version) === 'string') { - - var nodeVersion = process.version.split('.').reduce(function(a, v) { - return a << 8 | v; - }); + if (typeof process === 'object' && typeof process.version === 'string') { + var nodeVersion = process.version.split('.').reduce(function(a, v) { + return a << 8 | v; + }); - // 'errno' was renamed to process._errno in v0.9.11. + // 'errno' was renamed to process._errno in v0.9.11. - if (nodeVersion < 0x00090B) { - return ['errno']; - } - } + if (nodeVersion < 0x00090B) { + return ['errno']; + } + } - return []; + return []; } diff --git a/lib/suite.js b/lib/suite.js index edc820e23a..b59b3c8ae9 100644 --- a/lib/suite.js +++ b/lib/suite.js @@ -2,11 +2,11 @@ * Module dependencies. */ -var EventEmitter = require('events').EventEmitter - , debug = require('debug')('mocha:suite') - , milliseconds = require('./ms') - , utils = require('./utils') - , Hook = require('./hook'); +var EventEmitter = require('events').EventEmitter; +var Hook = require('./hook'); +var debug = require('debug')('mocha:suite'); +var milliseconds = require('./ms'); +var utils = require('./utils'); /** * Expose `Suite`. @@ -15,41 +15,38 @@ var EventEmitter = require('events').EventEmitter exports = module.exports = Suite; /** - * Create a new `Suite` with the given `title` - * and parent `Suite`. When a suite with the - * same title is already present, that suite - * is returned to provide nicer reporter - * and more flexible meta-testing. + * Create a new `Suite` with the given `title` and parent `Suite`. When a suite + * with the same title is already present, that suite is returned to provide + * nicer reporter and more flexible meta-testing. * + * @api public * @param {Suite} parent - * @param {String} title + * @param {string} title * @return {Suite} - * @api public */ - -exports.create = function(parent, title){ +exports.create = function(parent, title) { var suite = new Suite(title, parent.ctx); suite.parent = parent; - if (parent.pending) suite.pending = true; + if (parent.pending) { + suite.pending = true; + } title = suite.fullTitle(); parent.addSuite(suite); return suite; }; /** - * Initialize a new `Suite` with the given - * `title` and `ctx`. + * Initialize a new `Suite` with the given `title` and `ctx`. * - * @param {String} title - * @param {Context} ctx * @api private + * @param {string} title + * @param {Context} parentContext */ - function Suite(title, parentContext) { this.title = title; - var context = function() {}; - context.prototype = parentContext; - this.ctx = new context(); + function Context() {} + Context.prototype = parentContext; + this.ctx = new Context(); this.suites = []; this.tests = []; this.pending = false; @@ -74,11 +71,10 @@ Suite.prototype.__proto__ = EventEmitter.prototype; /** * Return a clone of this `Suite`. * - * @return {Suite} * @api private + * @return {Suite} */ - -Suite.prototype.clone = function(){ +Suite.prototype.clone = function() { var suite = new Suite(this.title); debug('clone'); suite.ctx = this.ctx; @@ -92,30 +88,36 @@ Suite.prototype.clone = function(){ /** * Set timeout `ms` or short-hand such as "2s". * - * @param {Number|String} ms - * @return {Suite|Number} for chaining * @api private + * @param {number|string} ms + * @return {Suite|number} for chaining */ - -Suite.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - if (ms.toString() === '0') this._enableTimeouts = false; - if ('string' == typeof ms) ms = milliseconds(ms); +Suite.prototype.timeout = function(ms) { + if (!arguments.length) { + return this._timeout; + } + if (ms.toString() === '0') { + this._enableTimeouts = false; + } + if (typeof ms === 'string') { + ms = milliseconds(ms); + } debug('timeout %d', ms); this._timeout = parseInt(ms, 10); return this; }; /** - * Set timeout `enabled`. + * Set timeout to `enabled`. * - * @param {Boolean} enabled - * @return {Suite|Boolean} self or enabled * @api private + * @param {boolean} enabled + * @return {Suite|boolean} self or enabled */ - -Suite.prototype.enableTimeouts = function(enabled){ - if (arguments.length === 0) return this._enableTimeouts; +Suite.prototype.enableTimeouts = function(enabled) { + if (!arguments.length) { + return this._enableTimeouts; + } debug('enableTimeouts %s', enabled); this._enableTimeouts = enabled; return this; @@ -124,14 +126,17 @@ Suite.prototype.enableTimeouts = function(enabled){ /** * Set slow `ms` or short-hand such as "2s". * - * @param {Number|String} ms - * @return {Suite|Number} for chaining * @api private + * @param {number|string} ms + * @return {Suite|number} for chaining */ - -Suite.prototype.slow = function(ms){ - if (0 === arguments.length) return this._slow; - if ('string' == typeof ms) ms = milliseconds(ms); +Suite.prototype.slow = function(ms) { + if (!arguments.length) { + return this._slow; + } + if (typeof ms === 'string') { + ms = milliseconds(ms); + } debug('slow %d', ms); this._slow = ms; return this; @@ -140,13 +145,14 @@ Suite.prototype.slow = function(ms){ /** * Sets whether to bail after first error. * - * @param {Boolean} bail - * @return {Suite|Number} for chaining * @api private + * @param {boolean} bail + * @return {Suite|number} for chaining */ - -Suite.prototype.bail = function(bail){ - if (0 == arguments.length) return this._bail; +Suite.prototype.bail = function(bail) { + if (!arguments.length) { + return this._bail; + } debug('bail %s', bail); this._bail = bail; return this; @@ -155,14 +161,16 @@ Suite.prototype.bail = function(bail){ /** * Run `fn(test[, done])` before running tests. * + * @api private + * @param {string} title * @param {Function} fn * @return {Suite} for chaining - * @api private */ - -Suite.prototype.beforeAll = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { +Suite.prototype.beforeAll = function(title, fn) { + if (this.pending) { + return this; + } + if (typeof title === 'function') { fn = title; title = fn.name; } @@ -182,14 +190,16 @@ Suite.prototype.beforeAll = function(title, fn){ /** * Run `fn(test[, done])` after running tests. * + * @api private + * @param {string} title * @param {Function} fn * @return {Suite} for chaining - * @api private */ - -Suite.prototype.afterAll = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { +Suite.prototype.afterAll = function(title, fn) { + if (this.pending) { + return this; + } + if (typeof title === 'function') { fn = title; title = fn.name; } @@ -209,14 +219,16 @@ Suite.prototype.afterAll = function(title, fn){ /** * Run `fn(test[, done])` before each test case. * + * @api private + * @param {string} title * @param {Function} fn * @return {Suite} for chaining - * @api private */ - -Suite.prototype.beforeEach = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { +Suite.prototype.beforeEach = function(title, fn) { + if (this.pending) { + return this; + } + if (typeof title === 'function') { fn = title; title = fn.name; } @@ -236,14 +248,16 @@ Suite.prototype.beforeEach = function(title, fn){ /** * Run `fn(test[, done])` after each test case. * + * @api private + * @param {string} title * @param {Function} fn * @return {Suite} for chaining - * @api private */ - -Suite.prototype.afterEach = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { +Suite.prototype.afterEach = function(title, fn) { + if (this.pending) { + return this; + } + if (typeof title === 'function') { fn = title; title = fn.name; } @@ -263,12 +277,11 @@ Suite.prototype.afterEach = function(title, fn){ /** * Add a test `suite`. * + * @api private * @param {Suite} suite * @return {Suite} for chaining - * @api private */ - -Suite.prototype.addSuite = function(suite){ +Suite.prototype.addSuite = function(suite) { suite.parent = this; suite.timeout(this.timeout()); suite.enableTimeouts(this.enableTimeouts()); @@ -282,12 +295,11 @@ Suite.prototype.addSuite = function(suite){ /** * Add a `test` to this suite. * + * @api private * @param {Test} test * @return {Suite} for chaining - * @api private */ - -Suite.prototype.addTest = function(test){ +Suite.prototype.addTest = function(test) { test.parent = this; test.timeout(this.timeout()); test.enableTimeouts(this.enableTimeouts()); @@ -299,17 +311,18 @@ Suite.prototype.addTest = function(test){ }; /** - * Return the full title generated by recursively - * concatenating the parent's full title. + * Return the full title generated by recursively concatenating the parent's + * full title. * - * @return {String} * @api public + * @return {string} */ - -Suite.prototype.fullTitle = function(){ +Suite.prototype.fullTitle = function() { if (this.parent) { var full = this.parent.fullTitle(); - if (full) return full + ' ' + this.title; + if (full) { + return full + ' ' + this.title; + } } return this.title; }; @@ -317,29 +330,26 @@ Suite.prototype.fullTitle = function(){ /** * Return the total number of tests. * - * @return {Number} * @api public + * @return {number} */ - -Suite.prototype.total = function(){ - return utils.reduce(this.suites, function(sum, suite){ +Suite.prototype.total = function() { + return utils.reduce(this.suites, function(sum, suite) { return sum + suite.total(); }, 0) + this.tests.length; }; /** - * Iterates through each suite recursively to find - * all tests. Applies a function in the format - * `fn(test)`. + * Iterates through each suite recursively to find all tests. Applies a + * function in the format `fn(test)`. * + * @api private * @param {Function} fn * @return {Suite} - * @api private */ - -Suite.prototype.eachTest = function(fn){ +Suite.prototype.eachTest = function(fn) { utils.forEach(this.tests, fn); - utils.forEach(this.suites, function(suite){ + utils.forEach(this.suites, function(suite) { suite.eachTest(fn); }); return this; diff --git a/lib/template.html b/lib/template.html index 0590d4aac2..36c5e0b694 100644 --- a/lib/template.html +++ b/lib/template.html @@ -9,7 +9,7 @@
        - +