diff --git a/.eslintignore b/.eslintignore index e9067bb70d..2b550ca81d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,3 @@ lib/to-iso-string/ +test/**/* +!test/runner.js diff --git a/.gitignore b/.gitignore index 99fb76a31b..fa1c0b0ccf 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ lib/browser/diff.js npm-debug.log* .envrc .karma/ +*.orig + diff --git a/Makefile b/Makefile index d6501ec33b..4161c4627b 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ clean: lint: @printf "==> [Test :: Lint]\n" - $(ESLINT) "lib/**/*.js" + $(ESLINT) browser-entry.js index.js karma.conf.js bin/mocha bin/_mocha "lib/**/*.js" "scripts/**/*.js" test test-node: test-bdd test-tdd test-qunit test-exports test-unit test-integration test-jsapi test-compilers test-glob test-requires test-reporters test-only test-global-only @@ -82,31 +82,31 @@ test-requires: --require test/acceptance/require/b.coffee \ --require test/acceptance/require/c.js \ --require test/acceptance/require/d.coffee \ - test/acceptance/require/require.js + test/acceptance/require/require.spec.js test-bdd: @printf "==> [Test :: BDD]\n" $(MOCHA) --reporter $(REPORTER) \ --ui bdd \ - test/acceptance/interfaces/bdd + test/acceptance/interfaces/bdd.spec test-tdd: @printf "==> [Test :: TDD]\n" $(MOCHA) --reporter $(REPORTER) \ --ui tdd \ - test/acceptance/interfaces/tdd + test/acceptance/interfaces/tdd.spec test-qunit: @printf "==> [Test :: QUnit]\n" $(MOCHA) --reporter $(REPORTER) \ --ui qunit \ - test/acceptance/interfaces/qunit + test/acceptance/interfaces/qunit.spec test-exports: @printf "==> [Test :: Exports]\n" $(MOCHA) --reporter $(REPORTER) \ --ui exports \ - test/acceptance/interfaces/exports + test/acceptance/interfaces/exports.spec test-glob: @printf "==> [Test :: Glob]\n" @@ -121,29 +121,29 @@ test-only: @printf "==> [Test :: Only]\n" $(MOCHA) --reporter $(REPORTER) \ --ui tdd \ - test/acceptance/misc/only/tdd + test/acceptance/misc/only/tdd.spec $(MOCHA) --reporter $(REPORTER) \ --ui bdd \ - test/acceptance/misc/only/bdd + test/acceptance/misc/only/bdd.spec $(MOCHA) --reporter $(REPORTER) \ --ui qunit \ - test/acceptance/misc/only/bdd-require + test/acceptance/misc/only/bdd-require.spec test-global-only: @printf "==> [Test :: Global Only]\n" $(MOCHA) --reporter $(REPORTER) \ --ui tdd \ - test/acceptance/misc/only/global/tdd + test/acceptance/misc/only/global/tdd.spec $(MOCHA) --reporter $(REPORTER) \ --ui bdd \ - test/acceptance/misc/only/global/bdd + test/acceptance/misc/only/global/bdd.spec $(MOCHA) --reporter $(REPORTER) \ --ui qunit \ - test/acceptance/misc/only/global/qunit + test/acceptance/misc/only/global/qunit.spec test-mocha: @printf "==> [Test :: Mocha]\n" @@ -153,19 +153,19 @@ test-mocha: non-tty: @printf "==> [Test :: Non-TTY]\n" $(MOCHA) --reporter dot \ - test/acceptance/interfaces/bdd 2>&1 > /tmp/dot.out + test/acceptance/interfaces/bdd.spec 2>&1 > /tmp/dot.out @echo dot: @cat /tmp/dot.out $(MOCHA) --reporter list \ - test/acceptance/interfaces/bdd 2>&1 > /tmp/list.out + test/acceptance/interfaces/bdd.spec 2>&1 > /tmp/list.out @echo list: @cat /tmp/list.out $(MOCHA) --reporter spec \ - test/acceptance/interfaces/bdd 2>&1 > /tmp/spec.out + test/acceptance/interfaces/bdd.spec 2>&1 > /tmp/spec.out @echo spec: @cat /tmp/spec.out diff --git a/bin/_mocha b/bin/_mocha index 11d3d0c662..b355e28352 100755 --- a/bin/_mocha +++ b/bin/_mocha @@ -1,31 +1,33 @@ #!/usr/bin/env node +/* eslint no-unused-vars: off */ + /** * Module dependencies. */ -var program = require('commander'), - path = require('path'), - fs = require('fs'), - resolve = path.resolve, - exists = fs.existsSync || path.existsSync, - Mocha = require('../'), - utils = Mocha.utils, - interfaceNames = Object.keys(Mocha.interfaces), - join = path.join, - cwd = process.cwd(), - getOptions = require('./options'), - mocha = new Mocha; +var program = require('commander'); +var path = require('path'); +var fs = require('fs'); +var resolve = path.resolve; +var exists = fs.existsSync || path.existsSync; +var Mocha = require('../'); +var utils = Mocha.utils; +var interfaceNames = Object.keys(Mocha.interfaces); +var join = path.join; +var cwd = process.cwd(); +var getOptions = require('./options'); +var mocha = new Mocha(); /** * 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; +var Date = global.Date; +var setTimeout = global.setTimeout; +var setInterval = global.setInterval; +var clearTimeout = global.clearTimeout; +var clearInterval = global.clearInterval; /** * Files. @@ -50,23 +52,23 @@ var requires = []; */ var images = { - fail: __dirname + '/../images/error.png' - , pass: __dirname + '/../images/ok.png' + fail: path.join(__dirname, '..', 'images', 'error.png'), + pass: path.join(__dirname, '..', 'images', 'ok.png') }; // options program - .version(JSON.parse(fs.readFileSync(__dirname + '/../package.json', 'utf8')).version) + .version(JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')).version) .usage('[debug] [options] [files]') - .option('-A, --async-only', "force all tests to take a callback (async) or return a promise") + .option('-A, --async-only', 'force all tests to take a callback (async) or return a promise') .option('-c, --colors', 'force enabling of colors') .option('-C, --no-colors', 'force disabling of colors') .option('-G, --growl', 'enable growl notification support') .option('-O, --reporter-options ', 'reporter-specific options') .option('-R, --reporter ', 'specify the reporter to use', 'spec') - .option('-S, --sort', "sort test files") - .option('-b, --bail', "bail after first test failure") + .option('-S, --sort', 'sort test files') + .option('-b, --bail', 'bail after first test failure') .option('-d, --debug', "enable node's debugger, synonym for node --debug") .option('-g, --grep ', 'only run tests matching ') .option('-f, --fgrep ', 'only run tests containing ') @@ -103,7 +105,7 @@ program .option('--trace-deprecation', 'show stack traces on deprecations') .option('--use_strict', 'enforce strict mode') .option('--watch-extensions ,...', 'additional extensions to monitor with --watch', list, []) - .option('--delay', 'wait for async suite definition') + .option('--delay', 'wait for async suite definition'); program._name = 'mocha'; @@ -112,7 +114,7 @@ program._name = 'mocha'; program .command('init ') .description('initialize a client-side mocha setup at ') - .action(function(path){ + .action(function(path) { var mkdir = require('mkdirp'); mkdir.sync(path); var css = fs.readFileSync(join(__dirname, '..', 'mocha.css')); @@ -127,13 +129,13 @@ program // --globals -program.on('globals', function(val){ +program.on('globals', function(val) { globals = globals.concat(list(val)); }); // --reporters -program.on('reporters', function(){ +program.on('reporters', function() { console.log(); console.log(' dot - dot matrix'); console.log(' doc - html documentation'); @@ -154,7 +156,7 @@ program.on('reporters', function(){ // --interfaces -program.on('interfaces', function(){ +program.on('interfaces', function() { console.log(''); interfaceNames.forEach(function(interfaceName) { console.log(' ' + interfaceName); @@ -167,9 +169,11 @@ program.on('interfaces', function(){ module.paths.push(cwd, join(cwd, 'node_modules')); -program.on('require', function(mod){ +program.on('require', function(mod) { var abs = exists(mod) || exists(mod + '.js'); - if (abs) mod = resolve(mod); + if (abs) { + mod = resolve(mod); + } requires.push(mod); }); @@ -190,16 +194,16 @@ Error.stackTraceLimit = Infinity; // TODO: config var reporterOptions = {}; if (program.reporterOptions !== undefined) { - program.reporterOptions.split(",").forEach(function(opt) { - var L = opt.split("="); - if (L.length > 2 || L.length === 0) { - throw new Error("invalid reporter option '" + opt + "'"); - } else if (L.length === 2) { - reporterOptions[L[0]] = L[1]; - } else { - reporterOptions[L[0]] = true; - } - }); + program.reporterOptions.split(',').forEach(function(opt) { + var L = opt.split('='); + if (L.length > 2 || L.length === 0) { + throw new Error("invalid reporter option '" + opt + "'"); + } else if (L.length === 2) { + reporterOptions[L[0]] = L[1]; + } else { + reporterOptions[L[0]] = true; + } + }); } // reporter @@ -214,37 +218,46 @@ try { } catch (err) { try { Reporter = require(program.reporter); - } catch (err) { + } catch (err2) { throw new Error('reporter "' + program.reporter + '" does not exist'); } } // --no-colors -if (!program.colors) mocha.useColors(false); +if (!program.colors) { + mocha.useColors(false); +} // --colors -if (~process.argv.indexOf('--colors') || - ~process.argv.indexOf('-c')) { +if (~process.argv.indexOf('--colors') || ~process.argv.indexOf('-c')) { mocha.useColors(true); } // --inline-diffs -if (program.inlineDiffs) mocha.useInlineDiffs(true); +if (program.inlineDiffs) { + mocha.useInlineDiffs(true); +} // --slow -if (program.slow) mocha.suite.slow(program.slow); +if (program.slow) { + mocha.suite.slow(program.slow); +} // --no-timeouts -if (!program.timeouts) mocha.enableTimeouts(false); +if (!program.timeouts) { + mocha.enableTimeouts(false); +} // --timeout -if (program.timeout) mocha.suite.timeout(program.timeout); +if (program.timeout) { + mocha.suite.timeout(program.timeout); +} // --bail @@ -252,35 +265,51 @@ mocha.suite.bail(program.bail); // --grep -if (program.grep) mocha.grep(program.grep); +if (program.grep) { + mocha.grep(program.grep); +} // --fgrep -if (program.fgrep) mocha.fgrep(program.fgrep); +if (program.fgrep) { + mocha.fgrep(program.fgrep); +} // --invert -if (program.invert) mocha.invert(); +if (program.invert) { + mocha.invert(); +} // --check-leaks -if (program.checkLeaks) mocha.checkLeaks(); +if (program.checkLeaks) { + mocha.checkLeaks(); +} // --stack-trace -if(program.fullTrace) mocha.fullTrace(); +if (program.fullTrace) { + mocha.fullTrace(); +} // --growl -if (program.growl) mocha.growl(); +if (program.growl) { + mocha.growl(); +} // --async-only -if (program.asyncOnly) mocha.asyncOnly(); +if (program.asyncOnly) { + mocha.asyncOnly(); +} // --delay -if (program.delay) mocha.delay(); +if (program.delay) { + mocha.delay(); +} // --globals @@ -288,17 +317,21 @@ mocha.globals(globals); // --retries -if (program.retries) mocha.suite.retries(program.retries); +if (program.retries) { + mocha.suite.retries(program.retries); +} // custom compiler support var extensions = ['js']; program.compilers.forEach(function(c) { - var idx = c.indexOf(':') - , ext = c.slice(0, idx) - , mod = c.slice(idx + 1); + var idx = c.indexOf(':'); + var ext = c.slice(0, idx); + var mod = c.slice(idx + 1); - if (mod[0] == '.') mod = join(process.cwd(), mod); + if (mod[0] === '.') { + mod = join(process.cwd(), mod); + } require(mod); extensions.push(ext); program.watchExtensions.push(ext); @@ -314,21 +347,40 @@ requires.forEach(function(mod) { mocha.ui(program.ui); -//args +// args var args = program.args; // default files to test/*.{js,coffee} -if (!args.length) args.push('test'); +if (!args.length) { + args.push('test'); +} + +args.forEach(function(arg) { + var newFiles; + try { + newFiles = utils.lookupFiles(arg, extensions, program.recursive); + } catch (err) { + if (err.message.indexOf('cannot resolve path') === 0) { + console.error('Warning: Could not find any test files matching pattern: ' + arg); + return; + } -args.forEach(function(arg){ - files = files.concat(utils.lookupFiles(arg, extensions, program.recursive)); + throw err; + } + + files = files.concat(newFiles); }); +if (!files.length) { + console.error('No test files found'); + process.exit(1); +} + // resolve -files = files.map(function(path){ +files = files.map(function(path) { return resolve(path); }); @@ -339,54 +391,58 @@ if (program.sort) { // --watch var runner; +var loadAndRun; +var purge; +var rerun; + if (program.watch) { console.log(); hideCursor(); - process.on('SIGINT', function(){ + process.on('SIGINT', function() { showCursor(); console.log('\n'); - process.exit(); + process.exit(130); }); - var watchFiles = utils.files(cwd, [ 'js' ].concat(program.watchExtensions)); var runAgain = false; - function loadAndRun() { + loadAndRun = function loadAndRun() { try { mocha.files = files; runAgain = false; - runner = mocha.run(function(){ + runner = mocha.run(function() { runner = null; if (runAgain) { rerun(); } }); - } catch(e) { + } catch (e) { console.log(e.stack); } - } + }; - function purge() { - watchFiles.forEach(function(file){ + purge = function purge() { + watchFiles.forEach(function(file) { delete require.cache[file]; }); - } + }; loadAndRun(); - function rerun() { + rerun = function rerun() { purge(); - stop() - if (!program.grep) + stop(); + if (!program.grep) { mocha.grep(null); + } mocha.suite = mocha.suite.clone(); - mocha.suite.ctx = new Mocha.Context; + mocha.suite.ctx = new Mocha.Context(); mocha.ui(program.ui); loadAndRun(); - } + }; - utils.watch(watchFiles, function(){ + utils.watch(watchFiles, function() { runAgain = true; if (runner) { runner.abort(); @@ -394,18 +450,17 @@ if (program.watch) { rerun(); } }); - } else { - // load mocha.files = files; runner = mocha.run(program.exit ? exit : exitLater); - } function exitLater(code) { - process.on('exit', function() { process.exit(code) }) + process.on('exit', function() { + process.exit(Math.min(code, 255)); + }); } function exit(code) { @@ -413,13 +468,15 @@ function exit(code) { // https://github.com/joyent/node/issues/6247 is just one bug example // https://github.com/visionmedia/mocha/issues/333 has a good discussion function done() { - if (!(draining--)) process.exit(code); + if (!(draining--)) { + process.exit(Math.min(code, 255)); + } } var draining = 0; var streams = [process.stdout, process.stderr]; - streams.forEach(function(stream){ + streams.forEach(function(stream) { // submit empty write request and wait for completion draining += 1; stream.write('', done); @@ -428,7 +485,14 @@ function exit(code) { done(); } -process.on('SIGINT', function() { runner.abort(); }) +process.on('SIGINT', function() { + runner.abort(); + + // This is a hack: + // Instead of `process.exit(130)`, set runner.failures to 130 (exit code for SIGINT) + // The amount of failures will be emitted as error code later + runner.failures = 130; +}); /** * Parse list. @@ -442,7 +506,7 @@ function list(str) { * Hide the cursor. */ -function hideCursor(){ +function hideCursor() { process.stdout.write('\u001b[?25l'); } @@ -450,7 +514,7 @@ function hideCursor(){ * Show the cursor. */ -function showCursor(){ +function showCursor() { process.stdout.write('\u001b[?25h'); } @@ -468,11 +532,11 @@ function stop() { */ function play(arr, interval) { - var len = arr.length - , interval = interval || 100 - , i = 0; + var len = arr.length; + interval = interval || 100; + var i = 0; - play.timer = setInterval(function(){ + play.timer = setInterval(function() { var str = arr[i++ % len]; process.stdout.write('\u001b[0G' + str); }, interval); diff --git a/bin/mocha b/bin/mocha index 99bc18ae4d..0c16f0ee94 100755 --- a/bin/mocha +++ b/bin/mocha @@ -5,17 +5,16 @@ * when found, before invoking the "real" _mocha(1) executable. */ -var spawn = require('child_process').spawn, - path = require('path'), - fs = require('fs'), - getOptions = require('./options'), - args = [path.join(__dirname, '_mocha')]; +var spawn = require('child_process').spawn; +var path = require('path'); +var getOptions = require('./options'); +var args = [path.join(__dirname, '_mocha')]; // Load mocha.opts into process.argv // Must be loaded here to handle node-specific options getOptions(); -process.argv.slice(2).forEach(function(arg){ +process.argv.slice(2).forEach(function(arg) { var flag = arg.split('=')[0]; switch (flag) { @@ -26,6 +25,7 @@ process.argv.slice(2).forEach(function(arg){ case 'debug': case '--debug': case '--debug-brk': + case '--inspect': args.unshift(arg); args.push('--no-timeouts'); break; @@ -46,19 +46,26 @@ process.argv.slice(2).forEach(function(arg){ args.unshift(arg); break; default: - if (0 == arg.indexOf('--harmony')) args.unshift(arg); - else if (0 == arg.indexOf('--trace')) args.unshift(arg); - else if (0 == arg.indexOf('--icu-data-dir')) args.unshift(arg); - else if (0 == arg.indexOf('--max-old-space-size')) args.unshift(arg); - else if (0 == arg.indexOf('--preserve-symlinks')) args.unshift(arg); - else args.push(arg); + if (arg.indexOf('--harmony') === 0) { + args.unshift(arg); + } else if (arg.indexOf('--trace') === 0) { + args.unshift(arg); + } else if (arg.indexOf('--icu-data-dir') === 0) { + args.unshift(arg); + } else if (arg.indexOf('--max-old-space-size') === 0) { + args.unshift(arg); + } else if (arg.indexOf('--preserve-symlinks') === 0) { + args.unshift(arg); + } else { + args.push(arg); + } break; } }); var proc = spawn(process.execPath, args, { stdio: 'inherit' }); -proc.on('exit', function (code, signal) { - process.on('exit', function(){ +proc.on('exit', function(code, signal) { + process.on('exit', function() { if (signal) { process.kill(process.pid, signal); } else { @@ -68,7 +75,7 @@ proc.on('exit', function (code, signal) { }); // terminate children. -process.on('SIGINT', function () { +process.on('SIGINT', function() { proc.kill('SIGINT'); // calls runner.abort() proc.kill('SIGTERM'); // if that didn't work, we're probably in an infinite loop, so make it die. }); diff --git a/browser-entry.js b/browser-entry.js index 341a199914..789e686ae6 100644 --- a/browser-entry.js +++ b/browser-entry.js @@ -1,3 +1,5 @@ +/* eslint no-unused-vars: off */ + /** * Shim process.stdout. */ @@ -33,15 +35,17 @@ var originalOnerrorHandler = global.onerror; * Revert to original onerror handler if previously defined. */ -process.removeListener = function(e, fn){ - if ('uncaughtException' == e) { +process.removeListener = function(e, fn) { + if (e === 'uncaughtException') { if (originalOnerrorHandler) { global.onerror = originalOnerrorHandler; } else { global.onerror = function() {}; } var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn); - if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); } + if (i !== -1) { + uncaughtExceptionHandlers.splice(i, 1); + } } }; @@ -49,9 +53,9 @@ process.removeListener = function(e, fn){ * Implements uncaughtException listener. */ -process.on = function(e, fn){ - if ('uncaughtException' == e) { - global.onerror = function(err, url, line){ +process.on = function(e, fn) { + if (e === 'uncaughtException') { + global.onerror = function(err, url, line) { fn(new Error(err + ' (' + url + ':' + line + ')')); return !mocha.allowUncaught; }; @@ -64,8 +68,8 @@ process.on = function(e, fn){ // Ensure that this default UI does not expose its methods to the global scope. mocha.suite.removeAllListeners('pre-require'); -var immediateQueue = [] - , immediateTimeout; +var immediateQueue = []; +var immediateTimeout; function timeslice() { var immediateStart = new Date().getTime(); @@ -96,7 +100,7 @@ Mocha.Runner.immediately = function(callback) { * only receive the 'message' attribute of the Error. */ mocha.throwError = function(err) { - Mocha.utils.forEach(uncaughtExceptionHandlers, function (fn) { + Mocha.utils.forEach(uncaughtExceptionHandlers, function(fn) { fn(err); }); throw err; @@ -107,7 +111,7 @@ mocha.throwError = function(err) { * Normally this would happen in Mocha.prototype.loadFiles. */ -mocha.ui = function(ui){ +mocha.ui = function(ui) { Mocha.prototype.ui.call(this, ui); this.suite.emit('pre-require', global, null, this); return this; @@ -117,9 +121,15 @@ mocha.ui = function(ui){ * Setup mocha with the given setting options. */ -mocha.setup = function(opts){ - if ('string' == typeof opts) opts = { ui: opts }; - for (var opt in opts) this[opt](opts[opt]); +mocha.setup = function(opts) { + if (typeof opts === 'string') { + opts = { ui: opts }; + } + for (var opt in opts) { + if (opts.hasOwnProperty(opt)) { + this[opt](opts[opt]); + } + } return this; }; @@ -127,22 +137,30 @@ mocha.setup = function(opts){ * Run mocha, returning the Runner. */ -mocha.run = function(fn){ +mocha.run = function(fn) { var options = mocha.options; mocha.globals('location'); var query = Mocha.utils.parseQuery(global.location.search || ''); - if (query.grep) mocha.grep(query.grep); - if (query.fgrep) mocha.fgrep(query.fgrep); - if (query.invert) mocha.invert(); + if (query.grep) { + mocha.grep(query.grep); + } + if (query.fgrep) { + mocha.fgrep(query.fgrep); + } + if (query.invert) { + mocha.invert(); + } - return Mocha.prototype.run.call(mocha, function(err){ + return Mocha.prototype.run.call(mocha, function(err) { // The DOM Document is not available in Web Workers. var document = global.document; if (document && document.getElementById('mocha') && options.noHighlighting !== true) { Mocha.utils.highlightTags('code'); } - if (fn) fn(err); + if (fn) { + fn(err); + } }); }; diff --git a/karma.conf.js b/karma.conf.js index 76e8ae631c..266fe72b7a 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -14,13 +14,15 @@ module.exports = function(config) { 'mocha' ], files: [ - 'test/browser-fixtures/bdd.js', - 'test/acceptance/*.js' + // we use the BDD interface for all of the tests that + // aren't interface-specific. + 'test/browser-fixtures/bdd.fixture.js', + 'test/acceptance/*.spec.js' ], exclude: [ - 'test/acceptance/http.js', - 'test/acceptance/fs.js', - 'test/acceptance/lookup-files.js', + 'test/acceptance/http.spec.js', + 'test/acceptance/fs.spec.js', + 'test/acceptance/lookup-files.spec.js', 'test/acceptance/require/**/*.js', 'test/acceptance/misc/**/*.js' ], @@ -108,8 +110,8 @@ module.exports = function(config) { cfg.sauceLabs.testName = 'Interface "' + ui + '" integration tests'; } cfg.files = [ - 'test/browser-fixtures/' + ui + '.js', - 'test/acceptance/interfaces/' + ui + '.js' + 'test/browser-fixtures/' + ui + '.fixture.js', + 'test/acceptance/interfaces/' + ui + '.spec.js' ]; } else if (cfg.sauceLabs) { cfg.sauceLabs.testName = 'Unit Tests'; diff --git a/lib/interfaces/common.js b/lib/interfaces/common.js index b367544a3f..447458487b 100644 --- a/lib/interfaces/common.js +++ b/lib/interfaces/common.js @@ -113,6 +113,8 @@ module.exports = function(suites, context, mocha) { if (typeof opts.fn === 'function') { opts.fn.call(suite); suites.shift(); + } else if (typeof opts.fn === 'undefined' && !suite.pending) { + throw new Error('Suite "' + suite.fullTitle() + '" was defined but no callback was supplied. Supply a callback or explicitly skip the suite.'); } return suite; diff --git a/lib/interfaces/qunit.js b/lib/interfaces/qunit.js index a2d67ef90f..22e8080e2e 100644 --- a/lib/interfaces/qunit.js +++ b/lib/interfaces/qunit.js @@ -50,7 +50,8 @@ module.exports = function(suite) { } return common.suite.create({ title: title, - file: file + file: file, + fn: false }); }; @@ -64,7 +65,8 @@ module.exports = function(suite) { } return common.suite.only({ title: title, - file: file + file: file, + fn: false }); }; diff --git a/lib/runnable.js b/lib/runnable.js index d89a7dd5d7..52ee900b22 100644 --- a/lib/runnable.js +++ b/lib/runnable.js @@ -133,7 +133,7 @@ Runnable.prototype.enableTimeouts = function(enabled) { * @api public */ Runnable.prototype.skip = function() { - throw new Pending(); + throw new Pending('sync skip'); }; /** @@ -298,14 +298,19 @@ Runnable.prototype.run = function(fn) { if (this.async) { this.resetTimeout(); + // allows skip() to be used in an explicit async context + this.skip = function asyncSkip() { + done(new Pending('async skip call')); + // halt execution. the Runnable will be marked pending + // by the previous call, and the uncaught handler will ignore + // the failure. + throw new Pending('async skip; aborting execution'); + }; + if (this.allowUncaught) { return callFnAsync(this.fn); } try { - // allows skip() to be used in an explicit async context - this.skip = function() { - done(new Pending()); - }; callFnAsync(this.fn); } catch (err) { done(utils.getError(err)); diff --git a/lib/runner.js b/lib/runner.js index f19a4060eb..145d990351 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -220,6 +220,10 @@ Runner.prototype.checkGlobals = function(test) { * @param {Error} err */ Runner.prototype.fail = function(test, err) { + if (test.isPending()) { + return; + } + ++this.failures; test.state = 'failed'; @@ -309,6 +313,8 @@ Runner.prototype.hook = function(name, fn) { suite.tests.forEach(function(test) { test.pending = true; }); + // a pending hook won't be executed twice. + hook.pending = true; } } else { self.failHook(hook, err); @@ -414,6 +420,9 @@ Runner.prototype.runTest = function(fn) { var self = this; var test = this.test; + if (!test) { + return; + } if (this.asyncOnly) { test.asyncOnly = true; } @@ -695,8 +704,8 @@ Runner.prototype.uncaught = function(err) { runnable.clearTimeout(); - // Ignore errors if complete - if (runnable.state) { + // Ignore errors if complete or pending + if (runnable.state || runnable.isPending()) { return; } this.fail(runnable, err); @@ -892,7 +901,7 @@ function hasOnly(suite) { function filterLeaks(ok, globals) { return filter(globals, function(key) { // Firefox and Chrome exposes iframes as index inside the window object - if (/^d+/.test(key)) { + if (/^\d+/.test(key)) { return false; } diff --git a/mocha.js b/mocha.js index c9224e3b92..3ca0ae9e67 100644 --- a/mocha.js +++ b/mocha.js @@ -1,5 +1,7 @@ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o& /tmp/mocha-glob.txt || { + echo Globbing ./*.js ./*-none.js in `pwd` failed. + exit 1 +} + +cat /tmp/mocha-glob.txt | grep -q -F '["end",{"suites":1,"tests":1,"passes":1,"pending":0,"failures":0,' && +cat /tmp/mocha-glob.txt | grep -q -F 'Could not find any test files matching pattern' || { + echo Globbing ./*.js ./*-none.js in `pwd` should match glob.js with one test inside and display one warning for the non-existing file. + exit 1 +} + # Globbing in windows command-shell differs completely from unix-style globbing. # In bash, the shell expands globs and passes the result to executables. # In windows, the shell passes globs unexpanded, executables do expansion if they support it. @@ -47,7 +58,7 @@ cat /tmp/mocha-glob.txt | grep -q -F '["end",{"suites":1,"tests":1,"passes":1,"p exit 1 } -cat /tmp/mocha-glob.txt | grep -q -F 'cannot resolve path' || { +cat /tmp/mocha-glob.txt | grep -q -F 'Could not find any test files matching pattern' || { echo Globbing './*-none.js' in `pwd` should match no files and run no tests. exit 1 } diff --git a/test/acceptance/glob/glob.js b/test/acceptance/glob/glob.spec.js similarity index 100% rename from test/acceptance/glob/glob.js rename to test/acceptance/glob/glob.spec.js diff --git a/test/acceptance/globals.js b/test/acceptance/globals.spec.js similarity index 100% rename from test/acceptance/globals.js rename to test/acceptance/globals.spec.js diff --git a/test/acceptance/http.js b/test/acceptance/http.spec.js similarity index 100% rename from test/acceptance/http.js rename to test/acceptance/http.spec.js diff --git a/test/acceptance/interfaces/bdd.js b/test/acceptance/interfaces/bdd.spec.js similarity index 100% rename from test/acceptance/interfaces/bdd.js rename to test/acceptance/interfaces/bdd.spec.js diff --git a/test/acceptance/interfaces/exports.js b/test/acceptance/interfaces/exports.spec.js similarity index 100% rename from test/acceptance/interfaces/exports.js rename to test/acceptance/interfaces/exports.spec.js diff --git a/test/acceptance/interfaces/qunit.js b/test/acceptance/interfaces/qunit.spec.js similarity index 100% rename from test/acceptance/interfaces/qunit.js rename to test/acceptance/interfaces/qunit.spec.js diff --git a/test/acceptance/interfaces/tdd.js b/test/acceptance/interfaces/tdd.spec.js similarity index 100% rename from test/acceptance/interfaces/tdd.js rename to test/acceptance/interfaces/tdd.spec.js diff --git a/test/acceptance/lookup-files.js b/test/acceptance/lookup-files.spec.js similarity index 100% rename from test/acceptance/lookup-files.js rename to test/acceptance/lookup-files.spec.js diff --git a/test/acceptance/misc/exit.js b/test/acceptance/misc/exit.spec.js similarity index 100% rename from test/acceptance/misc/exit.js rename to test/acceptance/misc/exit.spec.js diff --git a/test/acceptance/misc/many.js b/test/acceptance/misc/many.spec.js similarity index 100% rename from test/acceptance/misc/many.js rename to test/acceptance/misc/many.spec.js diff --git a/test/acceptance/misc/nontty.js b/test/acceptance/misc/nontty.spec.js similarity index 100% rename from test/acceptance/misc/nontty.js rename to test/acceptance/misc/nontty.spec.js diff --git a/test/acceptance/misc/only/bdd-require.js b/test/acceptance/misc/only/bdd-require.spec.js similarity index 100% rename from test/acceptance/misc/only/bdd-require.js rename to test/acceptance/misc/only/bdd-require.spec.js diff --git a/test/acceptance/misc/only/bdd.js b/test/acceptance/misc/only/bdd.spec.js similarity index 100% rename from test/acceptance/misc/only/bdd.js rename to test/acceptance/misc/only/bdd.spec.js diff --git a/test/acceptance/misc/only/global/bdd.js b/test/acceptance/misc/only/global/bdd.spec.js similarity index 100% rename from test/acceptance/misc/only/global/bdd.js rename to test/acceptance/misc/only/global/bdd.spec.js diff --git a/test/acceptance/misc/only/global/qunit.js b/test/acceptance/misc/only/global/qunit.spec.js similarity index 100% rename from test/acceptance/misc/only/global/qunit.js rename to test/acceptance/misc/only/global/qunit.spec.js diff --git a/test/acceptance/misc/only/global/tdd.js b/test/acceptance/misc/only/global/tdd.spec.js similarity index 100% rename from test/acceptance/misc/only/global/tdd.js rename to test/acceptance/misc/only/global/tdd.spec.js diff --git a/test/acceptance/misc/only/qunit.js b/test/acceptance/misc/only/qunit.spec.js similarity index 100% rename from test/acceptance/misc/only/qunit.js rename to test/acceptance/misc/only/qunit.spec.js diff --git a/test/acceptance/misc/only/tdd.js b/test/acceptance/misc/only/tdd.spec.js similarity index 100% rename from test/acceptance/misc/only/tdd.js rename to test/acceptance/misc/only/tdd.spec.js diff --git a/test/acceptance/overspecified-async.js b/test/acceptance/overspecified-async.spec.js similarity index 100% rename from test/acceptance/overspecified-async.js rename to test/acceptance/overspecified-async.spec.js diff --git a/test/acceptance/require/require.js b/test/acceptance/require/require.spec.js similarity index 100% rename from test/acceptance/require/require.js rename to test/acceptance/require/require.spec.js diff --git a/test/acceptance/required-tokens.js b/test/acceptance/required-tokens.spec.js similarity index 100% rename from test/acceptance/required-tokens.js rename to test/acceptance/required-tokens.spec.js diff --git a/test/acceptance/root.js b/test/acceptance/root.spec.js similarity index 100% rename from test/acceptance/root.js rename to test/acceptance/root.spec.js diff --git a/test/acceptance/throw.js b/test/acceptance/throw.spec.js similarity index 100% rename from test/acceptance/throw.js rename to test/acceptance/throw.spec.js diff --git a/test/acceptance/timeout.js b/test/acceptance/timeout.spec.js similarity index 100% rename from test/acceptance/timeout.js rename to test/acceptance/timeout.spec.js diff --git a/test/acceptance/utils.js b/test/acceptance/utils.spec.js similarity index 100% rename from test/acceptance/utils.js rename to test/acceptance/utils.spec.js diff --git a/test/browser-fixtures/bdd.js b/test/browser-fixtures/bdd.fixture.js similarity index 100% rename from test/browser-fixtures/bdd.js rename to test/browser-fixtures/bdd.fixture.js diff --git a/test/browser-fixtures/exports.js b/test/browser-fixtures/exports.fixture.js similarity index 100% rename from test/browser-fixtures/exports.js rename to test/browser-fixtures/exports.fixture.js diff --git a/test/browser-fixtures/qunit.js b/test/browser-fixtures/qunit.fixture.js similarity index 100% rename from test/browser-fixtures/qunit.js rename to test/browser-fixtures/qunit.fixture.js diff --git a/test/browser-fixtures/tdd.js b/test/browser-fixtures/tdd.fixture.js similarity index 100% rename from test/browser-fixtures/tdd.js rename to test/browser-fixtures/tdd.fixture.js diff --git a/test/browser/array.js b/test/browser/array.spec.js similarity index 100% rename from test/browser/array.js rename to test/browser/array.spec.js diff --git a/test/browser/grep.js b/test/browser/grep.spec.js similarity index 100% rename from test/browser/grep.js rename to test/browser/grep.spec.js diff --git a/test/browser/large.js b/test/browser/large.spec.js similarity index 100% rename from test/browser/large.js rename to test/browser/large.spec.js diff --git a/test/browser/multiple-done.js b/test/browser/multiple-done.spec.js similarity index 100% rename from test/browser/multiple-done.js rename to test/browser/multiple-done.spec.js diff --git a/test/browser/opts.js b/test/browser/opts.spec.js similarity index 100% rename from test/browser/opts.js rename to test/browser/opts.spec.js diff --git a/test/browser/stack-trace.js b/test/browser/stack-trace.spec.js similarity index 100% rename from test/browser/stack-trace.js rename to test/browser/stack-trace.spec.js diff --git a/test/browser/ui.js b/test/browser/ui.spec.js similarity index 100% rename from test/browser/ui.js rename to test/browser/ui.spec.js diff --git a/test/color.js b/test/color.spec.js similarity index 100% rename from test/color.js rename to test/color.spec.js diff --git a/test/grep.js b/test/grep.spec.js similarity index 100% rename from test/grep.js rename to test/grep.spec.js diff --git a/test/hook.async.js b/test/hook-async.spec.js similarity index 100% rename from test/hook.async.js rename to test/hook-async.spec.js diff --git a/test/hook.sync.nested.js b/test/hook-sync-nested.spec.js similarity index 100% rename from test/hook.sync.nested.js rename to test/hook-sync-nested.spec.js diff --git a/test/hook.sync.js b/test/hook-sync.spec.js similarity index 100% rename from test/hook.sync.js rename to test/hook-sync.spec.js diff --git a/test/hook.timeout.js b/test/hook-timeout.spec.js similarity index 100% rename from test/hook.timeout.js rename to test/hook-timeout.spec.js diff --git a/test/http.meta.2.js b/test/http-meta-2.spec.js similarity index 100% rename from test/http.meta.2.js rename to test/http-meta-2.spec.js diff --git a/test/http.meta.js b/test/http-meta.spec.js similarity index 100% rename from test/http.meta.js rename to test/http-meta.spec.js diff --git a/test/integration/diffs.js b/test/integration/diffs.spec.js similarity index 95% rename from test/integration/diffs.js rename to test/integration/diffs.spec.js index 111b6f2042..b779b84ada 100644 --- a/test/integration/diffs.js +++ b/test/integration/diffs.spec.js @@ -17,7 +17,7 @@ describe('diffs', function() { var diffs, expected; before(function(done) { - run('diffs/diffs.js', ['-C'], function(err, res) { + run('diffs/diffs.fixture.js', ['-C'], function(err, res) { expected = getExpectedOutput(); diffs = getDiffs(res.output); done(err); diff --git a/test/integration/fixtures/cascade.js b/test/integration/fixtures/cascade.fixture.js similarity index 100% rename from test/integration/fixtures/cascade.js rename to test/integration/fixtures/cascade.fixture.js diff --git a/test/integration/fixtures/diffs/diffs.js b/test/integration/fixtures/diffs/diffs.fixture.js similarity index 100% rename from test/integration/fixtures/diffs/diffs.js rename to test/integration/fixtures/diffs/diffs.fixture.js diff --git a/test/integration/fixtures/hooks/after.hook.async.error.js b/test/integration/fixtures/hooks/after-hook-async-error.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/after.hook.async.error.js rename to test/integration/fixtures/hooks/after-hook-async-error.fixture.js diff --git a/test/integration/fixtures/hooks/after.hook.error.js b/test/integration/fixtures/hooks/after-hook-error.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/after.hook.error.js rename to test/integration/fixtures/hooks/after-hook-error.fixture.js diff --git a/test/integration/fixtures/hooks/afterEach.hook.async.error.js b/test/integration/fixtures/hooks/afterEach-hook-async-error.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/afterEach.hook.async.error.js rename to test/integration/fixtures/hooks/afterEach-hook-async-error.fixture.js diff --git a/test/integration/fixtures/hooks/afterEach.hook.error.js b/test/integration/fixtures/hooks/afterEach-hook-error.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/afterEach.hook.error.js rename to test/integration/fixtures/hooks/afterEach-hook-error.fixture.js diff --git a/test/integration/fixtures/hooks/before.hook.async.error.tip.js b/test/integration/fixtures/hooks/before-hook-async-error-tip.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/before.hook.async.error.tip.js rename to test/integration/fixtures/hooks/before-hook-async-error-tip.fixture.js diff --git a/test/integration/fixtures/hooks/before.hook.async.error.js b/test/integration/fixtures/hooks/before-hook-async-error.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/before.hook.async.error.js rename to test/integration/fixtures/hooks/before-hook-async-error.fixture.js diff --git a/test/integration/fixtures/hooks/before.hook.error.tip.js b/test/integration/fixtures/hooks/before-hook-error-tip.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/before.hook.error.tip.js rename to test/integration/fixtures/hooks/before-hook-error-tip.fixture.js diff --git a/test/integration/fixtures/hooks/before.hook.error.js b/test/integration/fixtures/hooks/before-hook-error.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/before.hook.error.js rename to test/integration/fixtures/hooks/before-hook-error.fixture.js diff --git a/test/integration/fixtures/hooks/beforeEach.hook.async.error.js b/test/integration/fixtures/hooks/beforeEach-hook-async-error.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/beforeEach.hook.async.error.js rename to test/integration/fixtures/hooks/beforeEach-hook-async-error.fixture.js diff --git a/test/integration/fixtures/hooks/beforeEach.hook.error.js b/test/integration/fixtures/hooks/beforeEach-hook-error.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/beforeEach.hook.error.js rename to test/integration/fixtures/hooks/beforeEach-hook-error.fixture.js diff --git a/test/integration/fixtures/hooks/multiple.hook.async.error.js b/test/integration/fixtures/hooks/multiple-hook-async-error.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/multiple.hook.async.error.js rename to test/integration/fixtures/hooks/multiple-hook-async-error.fixture.js diff --git a/test/integration/fixtures/hooks/multiple.hook.error.js b/test/integration/fixtures/hooks/multiple-hook-error.fixture.js similarity index 100% rename from test/integration/fixtures/hooks/multiple.hook.error.js rename to test/integration/fixtures/hooks/multiple-hook-error.fixture.js diff --git a/test/integration/fixtures/multiple.done.before.js b/test/integration/fixtures/multiple-done-before.fixture.js similarity index 100% rename from test/integration/fixtures/multiple.done.before.js rename to test/integration/fixtures/multiple-done-before.fixture.js diff --git a/test/integration/fixtures/multiple.done.beforeEach.js b/test/integration/fixtures/multiple-done-beforeEach.fixture.js similarity index 100% rename from test/integration/fixtures/multiple.done.beforeEach.js rename to test/integration/fixtures/multiple-done-beforeEach.fixture.js diff --git a/test/integration/fixtures/multiple.done.specs.js b/test/integration/fixtures/multiple-done-specs.fixture.js similarity index 100% rename from test/integration/fixtures/multiple.done.specs.js rename to test/integration/fixtures/multiple-done-specs.fixture.js diff --git a/test/integration/fixtures/multiple.done.js b/test/integration/fixtures/multiple-done.fixture.js similarity index 100% rename from test/integration/fixtures/multiple.done.js rename to test/integration/fixtures/multiple-done.fixture.js diff --git a/test/integration/fixtures/options/async-only.async.js b/test/integration/fixtures/options/async-only-async.fixture.js similarity index 100% rename from test/integration/fixtures/options/async-only.async.js rename to test/integration/fixtures/options/async-only-async.fixture.js diff --git a/test/integration/fixtures/options/async-only.sync.js b/test/integration/fixtures/options/async-only-sync.fixture.js similarity index 100% rename from test/integration/fixtures/options/async-only.sync.js rename to test/integration/fixtures/options/async-only-sync.fixture.js diff --git a/test/integration/fixtures/options/bail.js b/test/integration/fixtures/options/bail.fixture.js similarity index 100% rename from test/integration/fixtures/options/bail.js rename to test/integration/fixtures/options/bail.fixture.js diff --git a/test/integration/fixtures/options/delay-fail.js b/test/integration/fixtures/options/delay-fail.fixture.js similarity index 100% rename from test/integration/fixtures/options/delay-fail.js rename to test/integration/fixtures/options/delay-fail.fixture.js diff --git a/test/integration/fixtures/options/delay.js b/test/integration/fixtures/options/delay.fixture.js similarity index 62% rename from test/integration/fixtures/options/delay.js rename to test/integration/fixtures/options/delay.fixture.js index 32b8f99383..a8bf2d4112 100644 --- a/test/integration/fixtures/options/delay.js +++ b/test/integration/fixtures/options/delay.fixture.js @@ -1,13 +1,8 @@ var assert = require('assert'); var delay = 500; -var start = new Date().getTime(); setTimeout(function() { describe('delayed execution', function() { - it('should have waited ' + delay + 'ms to run this suite', function() { - assert(new Date().getTime() - delay >= start); - }); - it('should have no effect if attempted twice in the same suite', function() { assert(true); run(); diff --git a/test/integration/fixtures/options/grep.js b/test/integration/fixtures/options/grep.fixture.js similarity index 100% rename from test/integration/fixtures/options/grep.js rename to test/integration/fixtures/options/grep.fixture.js diff --git a/test/integration/fixtures/options/only/bdd.js b/test/integration/fixtures/options/only/bdd.fixture.js similarity index 100% rename from test/integration/fixtures/options/only/bdd.js rename to test/integration/fixtures/options/only/bdd.fixture.js diff --git a/test/integration/fixtures/options/only/qunit.js b/test/integration/fixtures/options/only/qunit.fixture.js similarity index 100% rename from test/integration/fixtures/options/only/qunit.js rename to test/integration/fixtures/options/only/qunit.fixture.js diff --git a/test/integration/fixtures/options/only/tdd.js b/test/integration/fixtures/options/only/tdd.fixture.js similarity index 100% rename from test/integration/fixtures/options/only/tdd.js rename to test/integration/fixtures/options/only/tdd.fixture.js diff --git a/test/integration/fixtures/options/retries.js b/test/integration/fixtures/options/retries.fixture.js similarity index 100% rename from test/integration/fixtures/options/retries.js rename to test/integration/fixtures/options/retries.fixture.js diff --git a/test/integration/fixtures/options/sort.alpha.js b/test/integration/fixtures/options/sort-alpha.fixture.js similarity index 100% rename from test/integration/fixtures/options/sort.alpha.js rename to test/integration/fixtures/options/sort-alpha.fixture.js diff --git a/test/integration/fixtures/options/sort.beta.js b/test/integration/fixtures/options/sort-beta.fixture.js similarity index 100% rename from test/integration/fixtures/options/sort.beta.js rename to test/integration/fixtures/options/sort-beta.fixture.js diff --git a/test/integration/fixtures/passing.js b/test/integration/fixtures/passing.fixture.js similarity index 100% rename from test/integration/fixtures/passing.js rename to test/integration/fixtures/passing.fixture.js diff --git a/test/integration/fixtures/pending/skip.async.before.js b/test/integration/fixtures/pending/skip-async-before.fixture.js similarity index 100% rename from test/integration/fixtures/pending/skip.async.before.js rename to test/integration/fixtures/pending/skip-async-before.fixture.js diff --git a/test/integration/fixtures/pending/skip.async.beforeEach.js b/test/integration/fixtures/pending/skip-async-beforeEach.fixture.js similarity index 100% rename from test/integration/fixtures/pending/skip.async.beforeEach.js rename to test/integration/fixtures/pending/skip-async-beforeEach.fixture.js diff --git a/test/integration/fixtures/pending/skip.async.spec.js b/test/integration/fixtures/pending/skip-async-spec.fixture.js similarity index 100% rename from test/integration/fixtures/pending/skip.async.spec.js rename to test/integration/fixtures/pending/skip-async-spec.fixture.js diff --git a/test/integration/fixtures/pending/skip.sync.before.js b/test/integration/fixtures/pending/skip-sync-before.fixture.js similarity index 100% rename from test/integration/fixtures/pending/skip.sync.before.js rename to test/integration/fixtures/pending/skip-sync-before.fixture.js diff --git a/test/integration/fixtures/pending/skip.sync.beforeEach.js b/test/integration/fixtures/pending/skip-sync-beforeEach.fixture.js similarity index 100% rename from test/integration/fixtures/pending/skip.sync.beforeEach.js rename to test/integration/fixtures/pending/skip-sync-beforeEach.fixture.js diff --git a/test/integration/fixtures/pending/skip.sync.spec.js b/test/integration/fixtures/pending/skip-sync-spec.fixture.js similarity index 100% rename from test/integration/fixtures/pending/skip.sync.spec.js rename to test/integration/fixtures/pending/skip-sync-spec.fixture.js diff --git a/test/integration/fixtures/pending/spec.js b/test/integration/fixtures/pending/spec.fixture.js similarity index 100% rename from test/integration/fixtures/pending/spec.js rename to test/integration/fixtures/pending/spec.fixture.js diff --git a/test/integration/fixtures/regression/1794/issue-1794.js b/test/integration/fixtures/regression/1794/issue-1794.fixture.js similarity index 100% rename from test/integration/fixtures/regression/1794/issue-1794.js rename to test/integration/fixtures/regression/1794/issue-1794.fixture.js diff --git a/test/integration/fixtures/regression/issue-1327.js b/test/integration/fixtures/regression/issue-1327.fixture.js similarity index 100% rename from test/integration/fixtures/regression/issue-1327.js rename to test/integration/fixtures/regression/issue-1327.fixture.js diff --git a/test/integration/fixtures/regression/issue-1991.js b/test/integration/fixtures/regression/issue-1991.fixture.js similarity index 100% rename from test/integration/fixtures/regression/issue-1991.js rename to test/integration/fixtures/regression/issue-1991.fixture.js diff --git a/test/integration/fixtures/regression/issue-2315.js b/test/integration/fixtures/regression/issue-2315.js new file mode 100644 index 0000000000..cdfb201059 --- /dev/null +++ b/test/integration/fixtures/regression/issue-2315.js @@ -0,0 +1,9 @@ +describe('issue-2315: cannot read property currentRetry of undefined', function () { + before(function () { + process.nextTick(function () { + throw new Error(); + }); + }); + + it('something', function () {}); +}); diff --git a/test/integration/fixtures/regression/issue-2406.js b/test/integration/fixtures/regression/issue-2406.fixture.js similarity index 100% rename from test/integration/fixtures/regression/issue-2406.js rename to test/integration/fixtures/regression/issue-2406.fixture.js diff --git a/test/integration/fixtures/regression/issue-2417.js b/test/integration/fixtures/regression/issue-2417.fixture.js similarity index 100% rename from test/integration/fixtures/regression/issue-2417.js rename to test/integration/fixtures/regression/issue-2417.fixture.js diff --git a/test/integration/fixtures/retries/async.js b/test/integration/fixtures/retries/async.fixture.js similarity index 100% rename from test/integration/fixtures/retries/async.js rename to test/integration/fixtures/retries/async.fixture.js diff --git a/test/integration/fixtures/retries/early-pass.js b/test/integration/fixtures/retries/early-pass.fixture.js similarity index 100% rename from test/integration/fixtures/retries/early-pass.js rename to test/integration/fixtures/retries/early-pass.fixture.js diff --git a/test/integration/fixtures/retries/hooks.js b/test/integration/fixtures/retries/hooks.fixture.js similarity index 100% rename from test/integration/fixtures/retries/hooks.js rename to test/integration/fixtures/retries/hooks.fixture.js diff --git a/test/integration/fixtures/retries/nested.js b/test/integration/fixtures/retries/nested.fixture.js similarity index 100% rename from test/integration/fixtures/retries/nested.js rename to test/integration/fixtures/retries/nested.fixture.js diff --git a/test/integration/fixtures/suite/suite-no-callback.fixture.js b/test/integration/fixtures/suite/suite-no-callback.fixture.js new file mode 100644 index 0000000000..de55b358a3 --- /dev/null +++ b/test/integration/fixtures/suite/suite-no-callback.fixture.js @@ -0,0 +1 @@ +describe('a suite without a callback'); diff --git a/test/integration/fixtures/suite/suite-skipped-callback.fixture.js b/test/integration/fixtures/suite/suite-skipped-callback.fixture.js new file mode 100644 index 0000000000..b30b67ee2e --- /dev/null +++ b/test/integration/fixtures/suite/suite-skipped-callback.fixture.js @@ -0,0 +1 @@ +xdescribe('a pending suite with a callback', function () {}); diff --git a/test/integration/fixtures/suite/suite-skipped-no-callback.fixture.js b/test/integration/fixtures/suite/suite-skipped-no-callback.fixture.js new file mode 100644 index 0000000000..c5bca84a47 --- /dev/null +++ b/test/integration/fixtures/suite/suite-skipped-no-callback.fixture.js @@ -0,0 +1 @@ +xdescribe('a pending suite without a callback'); diff --git a/test/integration/fixtures/timeout.js b/test/integration/fixtures/timeout.fixture.js similarity index 100% rename from test/integration/fixtures/timeout.js rename to test/integration/fixtures/timeout.fixture.js diff --git a/test/integration/fixtures/uncaught.hook.js b/test/integration/fixtures/uncaught-hook.fixture.js similarity index 100% rename from test/integration/fixtures/uncaught.hook.js rename to test/integration/fixtures/uncaught-hook.fixture.js diff --git a/test/integration/fixtures/uncaught.js b/test/integration/fixtures/uncaught.fixture.js similarity index 100% rename from test/integration/fixtures/uncaught.js rename to test/integration/fixtures/uncaught.fixture.js diff --git a/test/integration/hook.err.js b/test/integration/hook-err.spec.js similarity index 86% rename from test/integration/hook.err.js rename to test/integration/hook-err.spec.js index f3a16c15d1..be18721f31 100644 --- a/test/integration/hook.err.js +++ b/test/integration/hook-err.spec.js @@ -7,7 +7,7 @@ describe('hook error handling', function() { var lines; describe('before hook error', function() { - before(run('hooks/before.hook.error.js')); + before(run('hooks/before-hook-error.fixture.js')); it('should verify results', function() { assert.deepEqual( lines, @@ -17,7 +17,7 @@ describe('hook error handling', function() { }); describe('before hook error tip', function() { - before(run('hooks/before.hook.error.tip.js', onlyErrorTitle)); + before(run('hooks/before-hook-error-tip.fixture.js', onlyErrorTitle)); it('should verify results', function() { assert.deepEqual( lines, @@ -27,7 +27,7 @@ describe('hook error handling', function() { }); describe('before each hook error', function() { - before(run('hooks/beforeEach.hook.error.js')); + before(run('hooks/beforeEach-hook-error.fixture.js')); it('should verify results', function() { assert.deepEqual( lines, @@ -37,7 +37,7 @@ describe('hook error handling', function() { }); describe('after hook error', function() { - before(run('hooks/after.hook.error.js')); + before(run('hooks/after-hook-error.fixture.js')); it('should verify results', function() { assert.deepEqual( lines, @@ -47,7 +47,7 @@ describe('hook error handling', function() { }); describe('after each hook error', function() { - before(run('hooks/afterEach.hook.error.js')); + before(run('hooks/afterEach-hook-error.fixture.js')); it('should verify results', function() { assert.deepEqual( lines, @@ -57,7 +57,7 @@ describe('hook error handling', function() { }); describe('multiple hook errors', function() { - before(run('hooks/multiple.hook.error.js')); + before(run('hooks/multiple-hook-error.fixture.js')); it('should verify results', function() { assert.deepEqual( lines, @@ -95,7 +95,7 @@ describe('hook error handling', function() { }); describe('async - before hook error', function() { - before(run('hooks/before.hook.async.error.js')); + before(run('hooks/before-hook-async-error.fixture.js')); it('should verify results', function() { assert.deepEqual( lines, @@ -105,7 +105,7 @@ describe('hook error handling', function() { }); describe('async - before hook error tip', function() { - before(run('hooks/before.hook.async.error.tip.js', onlyErrorTitle)); + before(run('hooks/before-hook-async-error-tip.fixture.js', onlyErrorTitle)); it('should verify results', function() { assert.deepEqual( lines, @@ -115,7 +115,7 @@ describe('hook error handling', function() { }); describe('async - before each hook error', function() { - before(run('hooks/beforeEach.hook.async.error.js')); + before(run('hooks/beforeEach-hook-async-error.fixture.js')); it('should verify results', function() { assert.deepEqual( lines, @@ -125,7 +125,7 @@ describe('hook error handling', function() { }); describe('async - after hook error', function() { - before(run('hooks/after.hook.async.error.js')); + before(run('hooks/after-hook-async-error.fixture.js')); it('should verify results', function() { assert.deepEqual( lines, @@ -135,7 +135,7 @@ describe('hook error handling', function() { }); describe('async - after each hook error', function() { - before(run('hooks/afterEach.hook.async.error.js')); + before(run('hooks/afterEach-hook-async-error.fixture.js')); it('should verify results', function() { assert.deepEqual( lines, @@ -145,7 +145,7 @@ describe('hook error handling', function() { }); describe('async - multiple hook errors', function() { - before(run('hooks/multiple.hook.async.error.js')); + before(run('hooks/multiple-hook-async-error.fixture.js')); it('should verify results', function() { assert.deepEqual( lines, diff --git a/test/integration/hooks.js b/test/integration/hooks.spec.js similarity index 94% rename from test/integration/hooks.js rename to test/integration/hooks.spec.js index acd829f7c9..7633cb5630 100644 --- a/test/integration/hooks.js +++ b/test/integration/hooks.spec.js @@ -5,7 +5,7 @@ var args = []; describe('hooks', function() { it('are ran in correct order', function(done) { - run('cascade.js', args, function(err, res) { + run('cascade.fixture.js', args, function(err, res) { var lines, expected; assert(!err); diff --git a/test/integration/multiple.done.js b/test/integration/multiple-done.spec.js similarity index 89% rename from test/integration/multiple.done.js rename to test/integration/multiple-done.spec.js index 0159e90e43..47e82dbebb 100644 --- a/test/integration/multiple.done.js +++ b/test/integration/multiple-done.spec.js @@ -6,7 +6,7 @@ describe('multiple calls to done()', function() { var res; describe('from a spec', function() { before(function(done) { - run('multiple.done.js', args, function(err, result) { + run('multiple-done.fixture.js', args, function(err, result) { res = result; done(err); }); @@ -27,7 +27,7 @@ describe('multiple calls to done()', function() { describe('with multiple specs', function() { before(function(done) { - run('multiple.done.specs.js', args, function(err, result) { + run('multiple-done-specs.fixture.js', args, function(err, result) { res = result; done(err); }); @@ -49,7 +49,7 @@ describe('multiple calls to done()', function() { describe('from a before hook', function() { before(function(done) { - run('multiple.done.before.js', args, function(err, result) { + run('multiple-done-before.fixture.js', args, function(err, result) { res = result; done(err); }); @@ -71,7 +71,7 @@ describe('multiple calls to done()', function() { describe('from a beforeEach hook', function() { before(function(done) { - run('multiple.done.beforeEach.js', args, function(err, result) { + run('multiple-done-beforeEach.fixture.js', args, function(err, result) { res = result; done(err); }); diff --git a/test/integration/only.js b/test/integration/only.js deleted file mode 100644 index dc7644e5a4..0000000000 --- a/test/integration/only.js +++ /dev/null @@ -1,37 +0,0 @@ -var run = require('./helpers').runMochaJSON; -var assert = require('assert'); - -describe('.only()', function() { - it('should run only tests that marked as `only`', function(done) { - run('options/only/bdd.js', ['--ui', 'bdd'], function(err, res) { - assert(!err); - assert.equal(res.stats.pending, 0); - assert.equal(res.stats.passes, 11); - assert.equal(res.stats.failures, 0); - assert.equal(res.code, 0); - done(); - }); - }); - - it('should run only tests that marked as `only`', function(done) { - run('options/only/tdd.js', ['--ui', 'tdd'], function(err, res) { - assert(!err); - assert.equal(res.stats.pending, 0); - assert.equal(res.stats.passes, 8); - assert.equal(res.stats.failures, 0); - assert.equal(res.code, 0); - done(); - }); - }); - - it('should run only tests that marked as `only`', function(done) { - run('options/only/qunit.js', ['--ui', 'qunit'], function(err, res) { - assert(!err); - assert.equal(res.stats.pending, 0); - assert.equal(res.stats.passes, 5); - assert.equal(res.stats.failures, 0); - assert.equal(res.code, 0); - done(); - }); - }); -}); diff --git a/test/integration/only.spec.js b/test/integration/only.spec.js new file mode 100644 index 0000000000..61254ce1d3 --- /dev/null +++ b/test/integration/only.spec.js @@ -0,0 +1,45 @@ +var run = require('./helpers').runMochaJSON; +var assert = require('assert'); + +describe('.only()', function() { + describe('bdd', function() { + it('should run only tests that marked as `only`', function(done) { + run('options/only/bdd.fixture.js', ['--ui', 'bdd'], function(err, res) { + assert(!err); + assert.equal(res.stats.pending, 0); + assert.equal(res.stats.passes, 11); + assert.equal(res.stats.failures, 0); + assert.equal(res.code, 0); + done(); + }); + }); + }); + + describe('tdd', function() { + it('should run only tests that marked as `only`', function(done) { + run('options/only/tdd.fixture.js', ['--ui', 'tdd'], function(err, res) { + assert(!err); + assert.equal(res.stats.pending, 0); + assert.equal(res.stats.passes, 8); + assert.equal(res.stats.failures, 0); + assert.equal(res.code, 0); + done(); + }); + }); + }); + + describe('qunit', function() { + it('should run only tests that marked as `only`', function(done) { + run('options/only/qunit.fixture.js', ['--ui', 'qunit'], function(err, res) { + console.log(err); + + assert(!err); + assert.equal(res.stats.pending, 0); + assert.equal(res.stats.passes, 5); + assert.equal(res.stats.failures, 0); + assert.equal(res.code, 0); + done(); + }); + }); + }); +}); diff --git a/test/integration/options.js b/test/integration/options.spec.js similarity index 85% rename from test/integration/options.js rename to test/integration/options.spec.js index 5e18ac5e71..4755647f76 100644 --- a/test/integration/options.js +++ b/test/integration/options.spec.js @@ -10,7 +10,7 @@ describe('options', function() { }); it('should fail synchronous specs', function(done) { - run('options/async-only.sync.js', args, function(err, res) { + run('options/async-only-sync.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); @@ -23,7 +23,7 @@ describe('options', function() { }); it('should allow asynchronous specs', function(done) { - run('options/async-only.async.js', args, function(err, res) { + run('options/async-only-async.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 1); @@ -42,7 +42,7 @@ describe('options', function() { }); it('should stop after the first error', function(done) { - run('options/bail.js', args, function(err, res) { + run('options/bail.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 1); @@ -82,21 +82,21 @@ describe('options', function() { }); it('should run the generated test suite', function(done) { - run('options/delay.js', args, function(err, res) { + run('options/delay.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); - assert.equal(res.stats.passes, 2); + assert.equal(res.stats.passes, 1); assert.equal(res.stats.failures, 0); assert.equal(res.passes[0].title, - 'should have waited 500ms to run this suite'); + 'should have no effect if attempted twice in the same suite'); assert.equal(res.code, 0); done(); }); }); it('should throw an error if the test suite failed to run', function(done) { - run('options/delay-fail.js', args, function(err, res) { + run('options/delay-fail.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); @@ -113,7 +113,7 @@ describe('options', function() { describe('--grep', function() { it('runs specs matching a string', function(done) { args = ['--grep', 'match']; - run('options/grep.js', args, function(err, res) { + run('options/grep.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 2); @@ -126,7 +126,7 @@ describe('options', function() { describe('runs specs matching a RegExp', function() { it('with RegExp like strings(pattern follow by flag)', function(done) { args = ['--grep', '/match/i']; - run('options/grep.js', args, function(err, res) { + run('options/grep.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 4); @@ -138,7 +138,7 @@ describe('options', function() { it('string as pattern', function(done) { args = ['--grep', '.*']; - run('options/grep.js', args, function(err, res) { + run('options/grep.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 4); @@ -152,7 +152,7 @@ describe('options', function() { describe('with --invert', function() { it('runs specs that do not match the pattern', function(done) { args = ['--grep', 'fail', '--invert']; - run('options/grep.js', args, function(err, res) { + run('options/grep.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 4); @@ -167,7 +167,7 @@ describe('options', function() { describe('--retries', function() { it('retries after a certain threshold', function (done) { args = ['--retries', '3']; - run('options/retries.js', args, function(err, res) { + run('options/retries.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); diff --git a/test/integration/pending.js b/test/integration/pending.spec.js similarity index 83% rename from test/integration/pending.js rename to test/integration/pending.spec.js index 0c18ab4bc7..4d4beffc2a 100644 --- a/test/integration/pending.js +++ b/test/integration/pending.spec.js @@ -5,7 +5,7 @@ var args = []; describe('pending', function() { describe('pending specs', function() { it('should be created by omitting a function', function(done) { - run('pending/spec.js', args, function(err, res) { + run('pending/spec.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 1); assert.equal(res.stats.passes, 0); @@ -19,7 +19,7 @@ describe('pending', function() { describe('synchronous skip()', function() { describe('in spec', function() { it('should immediately skip the spec and run all others', function(done) { - run('pending/skip.sync.spec.js', args, function(err, res) { + run('pending/skip-sync-spec.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 1); assert.equal(res.stats.passes, 1); @@ -32,7 +32,7 @@ describe('pending', function() { describe('in before', function() { it('should skip all suite specs', function(done) { - run('pending/skip.sync.before.js', args, function(err, res) { + run('pending/skip-sync-before.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 2); assert.equal(res.stats.passes, 0); @@ -45,7 +45,7 @@ describe('pending', function() { describe('in beforeEach', function() { it('should skip all suite specs', function(done) { - run('pending/skip.sync.beforeEach.js', args, function(err, res) { + run('pending/skip-sync-beforeEach.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 2); assert.equal(res.stats.passes, 0); @@ -60,7 +60,7 @@ describe('pending', function() { describe('asynchronous skip()', function() { describe('in spec', function() { it('should immediately skip the spec and run all others', function(done) { - run('pending/skip.async.spec.js', args, function(err, res) { + run('pending/skip-async-spec.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 1); assert.equal(res.stats.passes, 1); @@ -73,7 +73,7 @@ describe('pending', function() { describe('in before', function() { it('should skip all suite specs', function(done) { - run('pending/skip.async.before.js', args, function(err, res) { + run('pending/skip-async-before.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 2); assert.equal(res.stats.passes, 0); @@ -86,7 +86,7 @@ describe('pending', function() { describe('in beforeEach', function() { it('should skip all suite specs', function(done) { - run('pending/skip.sync.beforeEach.js', args, function(err, res) { + run('pending/skip-sync-beforeEach.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 2); assert.equal(res.stats.passes, 0); diff --git a/test/integration/regression.js b/test/integration/regression.spec.js similarity index 80% rename from test/integration/regression.js rename to test/integration/regression.spec.js index f0762ec0e9..f2a435a34c 100644 --- a/test/integration/regression.js +++ b/test/integration/regression.spec.js @@ -1,4 +1,4 @@ -var assert = require('assert'); +var assert = require('assert'); var fs = require('fs'); var path = require('path'); var run = require('./helpers').runMocha; @@ -7,7 +7,7 @@ var runJSON = require('./helpers').runMochaJSON; describe('regressions', function() { it('issue-1327: should run all 3 specs exactly once', function(done) { var args = []; - run('regression/issue-1327.js', args, function(err, res) { + run('regression/issue-1327.fixture.js', args, function(err, res) { var occurences = function(str) { var pattern = new RegExp(str, 'g'); return (res.output.match(pattern) || []).length; @@ -33,7 +33,7 @@ describe('regressions', function() { it('issue-1794: Can\'t --require custom UI and use it', function(done) { var simpleUiPath = path.join(__dirname, 'fixtures', 'regression', '1794', 'simple-ui.js'); var args = ['--require', simpleUiPath, '--ui', 'simple-ui']; - run('regression/1794/issue-1794.js', args, function(err, res) { + run('regression/1794/issue-1794.fixture.js', args, function(err, res) { assert.equal(res.code, 0, 'Custom UI should be loaded'); done(); }); @@ -43,7 +43,7 @@ describe('regressions', function() { // on a modern MBP takes ±5 seconds on node 4.0, but on older laptops with node 0.12 ±40 seconds. // Could easily take longer on even weaker machines (Travis-CI containers for example). this.timeout(120000); - run('regression/issue-1991.js', [], function(err, res) { + run('regression/issue-1991.fixture.js', [], function(err, res) { assert.equal(/process out of memory/.test(res.output), false, 'fixture\'s process out of memory!'); assert.equal(res.code, 0, 'Runnable fn (it/before[Each]/after[Each]) references should be deleted to avoid memory leaks'); done(); @@ -62,9 +62,20 @@ describe('regressions', function() { }); }); + it('issue-2315: cannot read property currentRetry of undefined', function (done) { + runJSON('regression/issue-2315.js', [], function(err, res) { + assert(!err); + assert.equal(res.stats.pending, 0); + assert.equal(res.stats.passes, 0); + assert.equal(res.stats.failures, 1); + assert.equal(res.code, 1); + done(); + }); + }); + it('issue-2406: should run nested describe.only suites', function(done) { this.timeout(2000); - runJSON('regression/issue-2406.js', [], function(err, res) { + runJSON('regression/issue-2406.fixture.js', [], function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 2); @@ -75,7 +86,7 @@ describe('regressions', function() { }); it('issue-2417: should not recurse infinitely with .only suites nested within each other', function() { - runJSON('regression/issue-2417.js', [], function(err, res) { + runJSON('regression/issue-2417.fixture.js', [], function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 1); diff --git a/test/integration/reporters.js b/test/integration/reporters.spec.js similarity index 91% rename from test/integration/reporters.js rename to test/integration/reporters.spec.js index c2f022fe29..9595611829 100644 --- a/test/integration/reporters.js +++ b/test/integration/reporters.spec.js @@ -10,7 +10,7 @@ describe('reporters', function() { var res; before(function(done) { - run('passing.js', ['--reporter', 'markdown'], function(err, result) { + run('passing.fixture.js', ['--reporter', 'markdown'], function(err, result) { res = result; done(err); }); @@ -44,7 +44,7 @@ describe('reporters', function() { '' ]; - run('passing.js', args, function(err, result) { + run('passing.fixture.js', args, function(err, result) { if (err) return done(err); var xml = fs.readFileSync(tmpFile, 'utf8'); diff --git a/test/integration/retries.js b/test/integration/retries.spec.js similarity index 88% rename from test/integration/retries.js rename to test/integration/retries.spec.js index 56516b3a92..ce76545b00 100644 --- a/test/integration/retries.js +++ b/test/integration/retries.spec.js @@ -5,7 +5,7 @@ var bang = require('../../lib/reporters/base').symbols.bang; describe('retries', function() { it('are ran in correct order', function(done) { - helpers.runMocha('retries/hooks.js', args, function(err, res) { + helpers.runMocha('retries/hooks.fixture.js', args, function(err, res) { var lines, expected; assert(!err); @@ -46,7 +46,7 @@ describe('retries', function() { }); it('should exit early if test passes', function (done) { - helpers.runMochaJSON('retries/early-pass.js', args, function(err, res) { + helpers.runMochaJSON('retries/early-pass.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.passes, 1); assert.equal(res.stats.failures, 0); @@ -58,7 +58,7 @@ describe('retries', function() { }); it('should let test override', function (done) { - helpers.runMochaJSON('retries/nested.js', args, function(err, res) { + helpers.runMochaJSON('retries/nested.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 1); @@ -70,7 +70,7 @@ describe('retries', function() { }); it('should not hang w/ async test', function (done) { - helpers.runMocha('retries/async.js', args, function(err, res) { + helpers.runMocha('retries/async.fixture.js', args, function(err, res) { var lines, expected; assert(!err); diff --git a/test/integration/suite.spec.js b/test/integration/suite.spec.js new file mode 100644 index 0000000000..00066a34f4 --- /dev/null +++ b/test/integration/suite.spec.js @@ -0,0 +1,42 @@ +var assert = require('assert'); +var run = require('./helpers').runMocha; +var args = []; + +describe('suite w/no callback', function() { + this.timeout(1000); + it('should throw a helpful error message when a callback for suite is not supplied', function(done) { + run('suite/suite-no-callback.fixture.js', args, function(err, res) { + assert(!err); + var result = res.output.match(/no callback was supplied/) || []; + assert.equal(result.length, 1); + done(); + }); + }); +}); + +describe('skipped suite w/no callback', function() { + this.timeout(1000); + it('should not throw an error when a callback for skipped suite is not supplied', function(done) { + run('suite/suite-skipped-no-callback.fixture.js', args, function(err, res) { + assert(!err); + pattern = new RegExp("Error", 'g'); + var result = res.output.match(pattern) || []; + assert.equal(result.length, 0); + done(); + }); + }); +}); + + +describe('skipped suite w/ callback', function() { + this.timeout(1000); + it('should not throw an error when a callback for skipped suite is supplied', function(done) { + run('suite/suite-skipped-callback.fixture.js', args, function(err, res) { + assert(!err); + pattern = new RegExp("Error", 'g'); + var result = res.output.match(pattern) || []; + assert.equal(result.length, 0); + done(); + }); + }); +}); diff --git a/test/integration/timeout.js b/test/integration/timeout.spec.js similarity index 87% rename from test/integration/timeout.js rename to test/integration/timeout.spec.js index b2dfb201f3..33b8e33093 100644 --- a/test/integration/timeout.js +++ b/test/integration/timeout.spec.js @@ -4,7 +4,7 @@ var args = []; describe('this.timeout()', function() { it('is respected by sync and async suites', function(done) { - run('timeout.js', args, function(err, res) { + run('timeout.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); diff --git a/test/integration/uncaught.js b/test/integration/uncaught.spec.js similarity index 89% rename from test/integration/uncaught.js rename to test/integration/uncaught.spec.js index 92a0ce5d35..87dde90902 100644 --- a/test/integration/uncaught.js +++ b/test/integration/uncaught.spec.js @@ -4,7 +4,7 @@ var args = []; describe('uncaught exceptions', function() { it('handles uncaught exceptions from hooks', function(done) { - run('uncaught.hook.js', args, function(err, res) { + run('uncaught-hook.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); @@ -18,7 +18,7 @@ describe('uncaught exceptions', function() { }); it('handles uncaught exceptions from async specs', function(done) { - run('uncaught.js', args, function(err, res) { + run('uncaught.fixture.js', args, function(err, res) { assert(!err); assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); diff --git a/test/jsapi/index.js b/test/jsapi/index.js index 2dbbcb0469..a096186b96 100644 --- a/test/jsapi/index.js +++ b/test/jsapi/index.js @@ -11,16 +11,16 @@ var mocha = new Mocha({ // mocha.reporter('spec'); require('should'); -mocha.addFile('test/suite.js'); -mocha.addFile('test/runner.js'); -mocha.addFile('test/runnable.js'); -mocha.addFile('test/hook.sync.js'); -mocha.addFile('test/hook.sync.nested.js'); -mocha.addFile('test/hook.async.js'); -mocha.addFile('test/acceptance/duration.js'); -mocha.addFile('test/acceptance/fs.js'); -mocha.addFile('test/acceptance/globals.js'); -mocha.addFile('test/acceptance/timeout.js'); +mocha.addFile('test/suite.spec.js'); +mocha.addFile('test/runner.spec.js'); +mocha.addFile('test/runnable.spec.js'); +mocha.addFile('test/hook-sync.spec.js'); +mocha.addFile('test/hook-sync-nested.spec.js'); +mocha.addFile('test/hook-async.spec.js'); +mocha.addFile('test/acceptance/duration.spec.js'); +mocha.addFile('test/acceptance/fs.spec.js'); +mocha.addFile('test/acceptance/globals.spec.js'); +mocha.addFile('test/acceptance/timeout.spec.js'); mocha.run(function(){ console.log('done'); diff --git a/test/mocha.js b/test/mocha.spec.js similarity index 100% rename from test/mocha.js rename to test/mocha.spec.js diff --git a/test/ms.js b/test/ms.spec.js similarity index 100% rename from test/ms.js rename to test/ms.spec.js diff --git a/test/reporters/base.js b/test/reporters/base.spec.js similarity index 100% rename from test/reporters/base.js rename to test/reporters/base.spec.js diff --git a/test/reporters/json.js b/test/reporters/json.spec.js similarity index 100% rename from test/reporters/json.js rename to test/reporters/json.spec.js diff --git a/test/reporters/nyan.js b/test/reporters/nyan.spec.js similarity index 100% rename from test/reporters/nyan.js rename to test/reporters/nyan.spec.js diff --git a/test/runnable.js b/test/runnable.spec.js similarity index 100% rename from test/runnable.js rename to test/runnable.spec.js diff --git a/test/runner.js b/test/runner.spec.js similarity index 54% rename from test/runner.js rename to test/runner.spec.js index 37aeb22d6f..ffe4d70e8c 100644 --- a/test/runner.js +++ b/test/runner.spec.js @@ -1,55 +1,59 @@ -var mocha = require('../') - , Suite = mocha.Suite - , Runner = mocha.Runner - , Test = mocha.Test; +var mocha = require('../'); +var Suite = mocha.Suite; +var Runner = mocha.Runner; +var Test = mocha.Test; +var Hook = mocha.Hook; -describe('Runner', function(){ - var suite, runner; +function noop() {} - beforeEach(function(){ +describe('Runner', function() { + var suite; + var runner; + + beforeEach(function() { suite = new Suite('Suite', 'root'); runner = new Runner(suite); - }) + }); - describe('.grep()', function(){ - it('should update the runner.total with number of matched tests', function(){ - suite.addTest(new Test('im a test about lions')); - suite.addTest(new Test('im another test about lions')); - suite.addTest(new Test('im a test about bears')); + describe('.grep()', function() { + it('should update the runner.total with number of matched tests', function() { + suite.addTest(new Test('im a test about lions', noop)); + suite.addTest(new Test('im another test about lions', noop)); + suite.addTest(new Test('im a test about bears', noop)); var newRunner = new Runner(suite); newRunner.grep(/lions/); newRunner.total.should.equal(2); - }) + }); - it('should update the runner.total with number of matched tests when inverted', function(){ - suite.addTest(new Test('im a test about lions')); - suite.addTest(new Test('im another test about lions')); - suite.addTest(new Test('im a test about bears')); + it('should update the runner.total with number of matched tests when inverted', function() { + suite.addTest(new Test('im a test about lions', noop)); + suite.addTest(new Test('im another test about lions', noop)); + suite.addTest(new Test('im a test about bears', noop)); var newRunner = new Runner(suite); newRunner.grep(/lions/, true); newRunner.total.should.equal(1); - }) - }) - - describe('.grepTotal()', function(){ - it('should return the total number of matched tests', function(){ - suite.addTest(new Test('im a test about lions')); - suite.addTest(new Test('im another test about lions')); - suite.addTest(new Test('im a test about bears')); + }); + }); + + describe('.grepTotal()', function() { + it('should return the total number of matched tests', function() { + suite.addTest(new Test('im a test about lions', noop)); + suite.addTest(new Test('im another test about lions', noop)); + suite.addTest(new Test('im a test about bears', noop)); runner.grep(/lions/); runner.grepTotal(suite).should.equal(2); - }) + }); - it('should return the total number of matched tests when inverted', function(){ - suite.addTest(new Test('im a test about lions')); - suite.addTest(new Test('im another test about lions')); - suite.addTest(new Test('im a test about bears')); + it('should return the total number of matched tests when inverted', function() { + suite.addTest(new Test('im a test about lions', noop)); + suite.addTest(new Test('im another test about lions', noop)); + suite.addTest(new Test('im a test about bears', noop)); runner.grep(/lions/, true); runner.grepTotal(suite).should.equal(1); - }) - }) + }); + }); - describe('.globalProps()', function(){ + describe('.globalProps()', function() { it('should include common non enumerable globals', function() { var props = runner.globalProps(); props.should.containEql('setTimeout'); @@ -61,19 +65,19 @@ describe('Runner', function(){ }); }); - describe('.globals()', function(){ - it('should default to the known globals', function(){ + describe('.globals()', function() { + it('should default to the known globals', function() { runner.globals().length.should.be.above(16); - }) + }); - it('should white-list globals', function(){ + it('should white-list globals', function() { runner.globals(['foo', 'bar']); runner.globals().should.containEql('foo'); runner.globals().should.containEql('bar'); - }) - }) + }); + }); - describe('.checkGlobals(test)', function(){ + describe('.checkGlobals(test)', function() { it('should allow variables that match a wildcard', function(done) { runner.globals(['foo*', 'giz*']); global.foo = 'baz'; @@ -81,43 +85,44 @@ describe('Runner', function(){ runner.checkGlobals(); delete global.foo; delete global.gizmo; - done() - }) + done(); + }); - it('should emit "fail" when a new global is introduced', function(done){ + it('should emit "fail" when a new global is introduced', function(done) { + var test = new Test('im a test', noop); runner.checkGlobals(); global.foo = 'bar'; - runner.on('fail', function(test, err){ - test.should.equal('im a test'); + runner.on('fail', function(_test, err) { + _test.should.equal(test); err.message.should.equal('global leak detected: foo'); delete global.foo; done(); }); - runner.checkGlobals('im a test'); - }) + runner.checkGlobals(test); + }); it('should emit "fail" when a single new disallowed global is introduced after a single extra global is allowed', function(done) { var doneCalled = false; runner.globals('good'); global.bad = 1; - runner.on('fail', function(test, err) { + runner.on('fail', function() { delete global.bad; done(); doneCalled = true; }); - runner.checkGlobals('test'); + runner.checkGlobals(new Test('yet another test', noop)); if (!doneCalled) { - done(Error("Expected test failure did not occur.")); + done(Error('Expected test failure did not occur.')); } }); - it ('should not fail when a new common global is introduced', function(){ + it('should not fail when a new common global is introduced', function() { // verify that the prop isn't enumerable delete global.XMLHttpRequest; global.propertyIsEnumerable('XMLHttpRequest').should.not.be.ok(); // create a new runner and keep a reference to the test. - var test = new Test('im a test about bears'); + var test = new Test('im a test about bears', noop); suite.addTest(test); var newRunner = new Runner(suite); @@ -133,22 +138,23 @@ describe('Runner', function(){ delete global.XMLHttpRequest; }); - it('should pluralize the error message when several are introduced', function(done){ + it('should pluralize the error message when several are introduced', function(done) { + var test = new Test('im a test', noop); runner.checkGlobals(); global.foo = 'bar'; global.bar = 'baz'; - runner.on('fail', function(test, err){ - test.should.equal('im a test'); + runner.on('fail', function(_test, err) { + _test.should.equal(test); err.message.should.equal('global leaks detected: foo, bar'); delete global.foo; delete global.bar; done(); }); - runner.checkGlobals('im a test'); - }) + runner.checkGlobals(test); + }); it('should respect per test whitelisted globals', function() { - var test = new Test('im a test about lions'); + var test = new Test('im a test about lions', noop); test.globals(['foo']); suite.addTest(test); @@ -161,157 +167,179 @@ describe('Runner', function(){ test.should.not.have.key('state'); delete global.foo; - }) + }); it('should respect per test whitelisted globals but still detect other leaks', function(done) { - var test = new Test('im a test about lions'); + var test = new Test('im a test about lions', noop); test.globals(['foo']); suite.addTest(test); global.foo = 'bar'; global.bar = 'baz'; - runner.on('fail', function(test, err){ + runner.on('fail', function(test, err) { test.title.should.equal('im a test about lions'); err.message.should.equal('global leak detected: bar'); delete global.foo; done(); }); runner.checkGlobals(test); - }) - }) + }); + + it('should emit "fail" when a global beginning with d is introduced', function(done) { + global.derp = 'bar'; + runner.on('fail', function() { + delete global.derp; + done(); + }); + runner.checkGlobals(new Test('herp', function() {})); + }); + }); - describe('.hook(name, fn)', function(){ - it('should execute hooks after failed test if suite bail is true', function(done){ - runner.fail({}); + describe('.hook(name, fn)', function() { + it('should execute hooks after failed test if suite bail is true', function(done) { + runner.fail(new Test('failed test', noop)); suite.bail(true); - suite.afterEach(function(){ + suite.afterEach(function() { suite.afterAll(function() { done(); - }) + }); }); - runner.hook('afterEach', function(){}); - runner.hook('afterAll', function(){}); - }) - }) + runner.hook('afterEach', function() {}); + runner.hook('afterAll', function() {}); + }); + }); - describe('.fail(test, err)', function(){ - it('should increment .failures', function(){ + describe('.fail(test, err)', function() { + it('should increment .failures', function() { runner.failures.should.equal(0); - runner.fail({}, {}); + runner.fail(new Test('one', noop), {}); runner.failures.should.equal(1); - runner.fail({}, {}); + runner.fail(new Test('two', noop), {}); runner.failures.should.equal(2); - }) + }); - it('should set test.state to "failed"', function(){ - var test = {}; + it('should set test.state to "failed"', function() { + var test = new Test('some test', noop); runner.fail(test, 'some error'); test.state.should.equal('failed'); - }) + }); - it('should emit "fail"', function(done){ - var test = {}, err = {}; - runner.on('fail', function(test, err){ + it('should emit "fail"', function(done) { + var test = new Test('some other test', noop); + var err = {}; + runner.on('fail', function(test, err) { test.should.equal(test); err.should.equal(err); done(); }); runner.fail(test, err); - }) + }); - it('should emit a helpful message when failed with a string', function(done){ - var test = {}, err = 'string'; - runner.on('fail', function(test, err){ + it('should emit a helpful message when failed with a string', function(done) { + var test = new Test('helpful test', noop); + var err = 'string'; + runner.on('fail', function(test, err) { err.message.should.equal('the string "string" was thrown, throw an Error :)'); done(); }); runner.fail(test, err); - }) + }); - it('should emit a the error when failed with an Error instance', function(done){ - var test = {}, err = new Error('an error message'); - runner.on('fail', function(test, err){ + it('should emit a the error when failed with an Error instance', function(done) { + var test = new Test('a test', noop); + var err = new Error('an error message'); + runner.on('fail', function(test, err) { err.message.should.equal('an error message'); done(); }); runner.fail(test, err); - }) + }); - it('should emit the error when failed with an Error-like object', function(done){ - var test = {}, err = {message: 'an error message'}; - runner.on('fail', function(test, err){ + it('should emit the error when failed with an Error-like object', function(done) { + var test = new Test('a test', noop); + var err = { message: 'an error message' }; + runner.on('fail', function(test, err) { err.message.should.equal('an error message'); done(); }); runner.fail(test, err); - }) + }); - it('should emit a helpful message when failed with an Object', function(done){ - var test = {}, err = { x: 1 }; - runner.on('fail', function(test, err){ + it('should emit a helpful message when failed with an Object', function(done) { + var test = new Test('a test', noop); + var err = { x: 1 }; + runner.on('fail', function(test, err) { err.message.should.equal('the object {\n "x": 1\n} was thrown, throw an Error :)'); done(); }); runner.fail(test, err); - }) + }); - it('should emit a helpful message when failed with an Array', function(done){ - var test = {}, err = [1,2]; - runner.on('fail', function(test, err){ + it('should emit a helpful message when failed with an Array', function(done) { + var test = new Test('a test', noop); + var err = [ + 1, + 2 + ]; + runner.on('fail', function(test, err) { err.message.should.equal('the array [\n 1\n 2\n] was thrown, throw an Error :)'); done(); }); runner.fail(test, err); - }) - }) + }); + }); - describe('.failHook(hook, err)', function(){ - it('should increment .failures', function(){ + describe('.failHook(hook, err)', function() { + it('should increment .failures', function() { runner.failures.should.equal(0); - runner.failHook({}, {}); + runner.failHook(new Test('fail hook 1', noop), {}); runner.failures.should.equal(1); - runner.failHook({}, {}); + runner.failHook(new Test('fail hook 2', noop), {}); runner.failures.should.equal(2); - }) + }); + + it('should augment hook title with current test title', function() { + var hook = new Hook('"before each" hook'); + hook.ctx = { currentTest: new Test('should behave', noop) }; - it('should augment hook title with current test title', function(){ - var hook = { - title: '"before each" hook', - ctx: { currentTest: new Test('should behave') } - }; runner.failHook(hook, {}); hook.title.should.equal('"before each" hook for "should behave"'); - hook.ctx.currentTest = new Test('should obey'); + hook.ctx.currentTest = new Test('should obey', noop); runner.failHook(hook, {}); hook.title.should.equal('"before each" hook for "should obey"'); - }) + }); - it('should emit "fail"', function(done){ - var hook = {}, err = {}; - runner.on('fail', function(hook, err){ + it('should emit "fail"', function(done) { + var hook = new Hook(); + var err = {}; + runner.on('fail', function(hook, err) { hook.should.equal(hook); err.should.equal(err); done(); }); runner.failHook(hook, err); - }) + }); - it('should emit "end" if suite bail is true', function(done){ - var hook = {}, err = {}; + it('should emit "end" if suite bail is true', function(done) { + var hook = new Hook(); + var err = {}; suite.bail(true); runner.on('end', done); runner.failHook(hook, err); - }) + }); - it('should not emit "end" if suite bail is not true', function(done){ - var hook = {}, err = {}; + it('should not emit "end" if suite bail is not true', function(done) { + var hook = new Hook(); + var err = {}; suite.bail(false); - runner.on('end', function() { throw new Error('"end" was emit, but the bail is false'); }); + runner.on('end', function() { + throw new Error('"end" was emit, but the bail is false'); + }); runner.failHook(hook, err); done(); - }) + }); }); describe('allowUncaught', function() { @@ -330,27 +358,29 @@ describe('Runner', function(){ }); describe('stackTrace', function() { - var stack = [ 'AssertionError: foo bar' - , 'at EventEmitter. (/usr/local/dev/test.js:16:12)' - , 'at Context. (/usr/local/dev/test.js:19:5)' - , 'Test.Runnable.run (/usr/local/lib/node_modules/mocha/lib/runnable.js:244:7)' - , 'Runner.runTest (/usr/local/lib/node_modules/mocha/lib/runner.js:374:10)' - , '/usr/local/lib/node_modules/mocha/lib/runner.js:452:12' - , 'next (/usr/local/lib/node_modules/mocha/lib/runner.js:299:14)' - , '/usr/local/lib/node_modules/mocha/lib/runner.js:309:7' - , 'next (/usr/local/lib/node_modules/mocha/lib/runner.js:248:23)' - , 'Immediate._onImmediate (/usr/local/lib/node_modules/mocha/lib/runner.js:276:5)' - , 'at processImmediate [as _immediateCallback] (timers.js:321:17)']; + var stack = [ + 'AssertionError: foo bar', + 'at EventEmitter. (/usr/local/dev/test.js:16:12)', + 'at Context. (/usr/local/dev/test.js:19:5)', + 'Test.Runnable.run (/usr/local/lib/node_modules/mocha/lib/runnable.js:244:7)', + 'Runner.runTest (/usr/local/lib/node_modules/mocha/lib/runner.js:374:10)', + '/usr/local/lib/node_modules/mocha/lib/runner.js:452:12', + 'next (/usr/local/lib/node_modules/mocha/lib/runner.js:299:14)', + '/usr/local/lib/node_modules/mocha/lib/runner.js:309:7', + 'next (/usr/local/lib/node_modules/mocha/lib/runner.js:248:23)', + 'Immediate._onImmediate (/usr/local/lib/node_modules/mocha/lib/runner.js:276:5)', + 'at processImmediate [as _immediateCallback] (timers.js:321:17)' + ]; describe('shortStackTrace', function() { it('should prettify the stack-trace', function(done) { - var hook = {}, - err = new Error(); + var hook = new Hook(); + var err = new Error(); // Fake stack-trace err.stack = stack.join('\n'); - runner.on('fail', function(hook, err){ - err.stack.should.equal(stack.slice(0,3).join('\n')); + runner.on('fail', function(hook, err) { + err.stack.should.equal(stack.slice(0, 3).join('\n')); done(); }); runner.failHook(hook, err); @@ -359,14 +389,14 @@ describe('Runner', function(){ describe('longStackTrace', function() { it('should display the full stack-trace', function(done) { - var hook = {}, - err = new Error(); + var hook = new Hook(); + var err = new Error(); // Fake stack-trace err.stack = stack.join('\n'); // Add --stack-trace option runner.fullStackTrace = true; - runner.on('fail', function(hook, err){ + runner.on('fail', function(hook, err) { err.stack.should.equal(stack.join('\n')); done(); }); diff --git a/test/sanity/sanity.js b/test/sanity/sanity.spec.js similarity index 100% rename from test/sanity/sanity.js rename to test/sanity/sanity.spec.js diff --git a/test/suite.js b/test/suite.spec.js similarity index 98% rename from test/suite.js rename to test/suite.spec.js index 7fead0745a..54a1acd667 100644 --- a/test/suite.js +++ b/test/suite.spec.js @@ -136,7 +136,7 @@ describe('Suite', function(){ this.suite._beforeAll.should.have.length(1); var beforeAllItem = this.suite._beforeAll[0]; - beforeAllItem.title.should.equal('"before all" hook'); + beforeAllItem.title.should.match(/^"before all" hook/); beforeAllItem.fn.should.equal(fn); }); @@ -171,7 +171,7 @@ describe('Suite', function(){ this.suite._afterAll.should.have.length(1); var afterAllItem = this.suite._afterAll[0]; - afterAllItem.title.should.equal('"after all" hook'); + afterAllItem.title.should.match(/^"after all" hook/); afterAllItem.fn.should.equal(fn); }); it('appends title to hook', function(){ @@ -205,7 +205,7 @@ describe('Suite', function(){ this.suite._beforeEach.should.have.length(1); var beforeEachItem = this.suite._beforeEach[0]; - beforeEachItem.title.should.equal('"before each" hook'); + beforeEachItem.title.should.match(/^"before each" hook/); beforeEachItem.fn.should.equal(fn); }); @@ -240,7 +240,7 @@ describe('Suite', function(){ this.suite._afterEach.should.have.length(1); var afterEachItem = this.suite._afterEach[0]; - afterEachItem.title.should.equal('"after each" hook'); + afterEachItem.title.should.match(/^"after each" hook/); afterEachItem.fn.should.equal(fn); }); diff --git a/test/test.js b/test/test.spec.js similarity index 100% rename from test/test.js rename to test/test.spec.js diff --git a/test/utils.js b/test/utils.spec.js similarity index 100% rename from test/utils.js rename to test/utils.spec.js