vendor/assets/javascripts/mocha.js in mocha_rails-0.0.3 vs vendor/assets/javascripts/mocha.js in mocha_rails-0.0.4

- old
+ new

@@ -55,10 +55,14 @@ } }; }); // module: browser/debug.js +require.register("browser/diff.js", function(module, exports, require){ + +}); // module: browser/diff.js + require.register("browser/events.js", function(module, exports, require){ /** * Module exports. */ @@ -511,10 +515,15 @@ module.exports = function(suite){ var suites = [suite]; suite.on('pre-require', function(context){ + // noop variants + + context.xdescribe = function(){}; + context.xit = function(){}; + /** * Execute before running tests. */ context.before = function(fn){ @@ -844,34 +853,189 @@ * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca> * MIT Licensed */ /** + * Module dependencies. + */ + +var path = require('browser/path'); + +/** + * Expose `Mocha`. + */ + +exports = module.exports = Mocha; + +/** * Library version. */ -exports.version = '0.12.0'; +exports.version = '1.0.0'; +/** + * Expose internals. + */ + exports.utils = require('./utils'); exports.interfaces = require('./interfaces'); exports.reporters = require('./reporters'); exports.Runnable = require('./runnable'); exports.Context = require('./context'); exports.Runner = require('./runner'); exports.Suite = require('./suite'); exports.Hook = require('./hook'); exports.Test = require('./test'); +/** + * Return image `name` path. + * + * @param {String} name + * @return {String} + * @api private + */ + +function image(name) { + return __dirname + '/../images/' + name + '.png'; +} + +/** + * Setup mocha with `options`. + * + * Options: + * + * - `ui` name "bdd", "tdd", "exports" etc + * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` + * - `globals` array of accepted globals + * - `timeout` timeout in milliseconds + * - `ignoreLeaks` ignore global leaks + * + * @param {Object} options + * @api public + */ + +function Mocha(options) { + options = options || {}; + this.files = []; + this.options = options; + this.suite = new exports.Suite('', new exports.Context); + this.ui(options.ui); + this.reporter(options.reporter); + if (options.timeout) this.suite.timeout(options.timeout); +} + +/** + * Add test `file`. + * + * @param {String} file + * @api public + */ + +Mocha.prototype.addFile = function(file){ + this.files.push(file); + return this; +}; + +/** + * Set reporter to `name`, defaults to "dot". + * + * @param {String} name + * @api public + */ + +Mocha.prototype.reporter = function(name){ + name = name || 'dot'; + this._reporter = require('./reporters/' + name); + if (!this._reporter) throw new Error('invalid reporter "' + name + '"'); + return this; +}; + +/** + * Set test UI `name`, defaults to "bdd". + * + * @param {String} bdd + * @api public + */ + +Mocha.prototype.ui = function(name){ + name = name || 'bdd'; + this._ui = exports.interfaces[name]; + if (!this._ui) throw new Error('invalid interface "' + name + '"'); + this._ui = this._ui(this.suite); + return this; +}; + +/** + * Load registered files. + * + * @api private + */ + +Mocha.prototype.loadFiles = function(){ + var suite = this.suite; + this.files.forEach(function(file){ + file = path.resolve(file); + suite.emit('pre-require', global, file); + suite.emit('require', require(file), file); + suite.emit('post-require', global, file); + }); +}; + +/** + * Enable growl support. + * + * @api private + */ + +Mocha.prototype.growl = function(runner, reporter) { + var notify = require('growl'); + + runner.on('end', function(){ + var stats = reporter.stats; + if (stats.failures) { + var msg = stats.failures + ' of ' + runner.total + ' tests failed'; + notify(msg, { title: 'Failed', image: image('fail') }); + } else { + notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { + title: 'Passed' + , image: image('pass') + }); + } + }); +}; + +/** + * Run tests and invoke `fn()` when complete. + * + * @param {Function} fn + * @return {Runner} + * @api public + */ + +Mocha.prototype.run = function(fn){ + this.loadFiles(); + var suite = this.suite; + var options = this.options; + var runner = new exports.Runner(suite); + var reporter = new this._reporter(runner); + runner.ignoreLeaks = options.ignoreLeaks; + if (options.grep) runner.grep(options.grep); + if (options.globals) runner.globals(options.globals); + if (options.growl) this.growl(runner, reporter); + return runner.run(fn); +}; + }); // module: mocha.js require.register("reporters/base.js", function(module, exports, require){ /** * Module dependencies. */ -var tty = require('browser/tty'); +var tty = require('browser/tty') + , diff = require('browser/diff'); /** * Check if both stdio streams are associated with a tty. */ @@ -908,10 +1072,13 @@ , 'fast': 90 , 'medium': 33 , 'slow': 31 , 'green': 32 , 'light': 90 + , 'diff gutter': 90 + , 'diff added': 42 + , 'diff removed': 41 }; /** * Color `str` with the given `type`, * allowing colors to be disabled, @@ -995,14 +1162,48 @@ // msg var err = test.err , message = err.message || '' , stack = err.stack || message , index = stack.indexOf(message) + message.length - , msg = stack.slice(0, index); + , msg = stack.slice(0, index) + , actual = err.actual + , expected = err.expected; + // actual / expected diff + if ('string' == typeof actual && 'string' == typeof expected) { + var len = Math.max(actual.length, expected.length); + + if (len < 20) msg = errorDiff(err, 'Chars'); + else msg = errorDiff(err, 'Words'); + + // linenos + var lines = msg.split('\n'); + if (lines.length > 4) { + var width = String(lines.length).length; + msg = lines.map(function(str, i){ + return pad(++i, width) + ' |' + ' ' + str; + }).join('\n'); + } + + // legend + msg = '\n' + + color('diff removed', 'actual') + + ' ' + + color('diff added', 'expected') + + '\n\n' + + msg + + '\n'; + + // indent + msg = msg.replace(/^/gm, ' '); + + fmt = color('error title', ' %s) %s:\n%s') + + color('error stack', '\n%s\n'); + } + // indent stack trace without msg - stack = stack.slice(index + 1) + stack = stack.slice(index ? index + 1 : index) .replace(/^/gm, ' '); console.error(fmt, (i + 1), test.fullTitle(), msg, stack); }); }; @@ -1099,10 +1300,55 @@ console.log(fmt, stats.tests || 0, stats.duration); console.log(); }; +/** + * Pad the given `str` to `len`. + * + * @param {String} str + * @param {String} len + * @return {String} + * @api private + */ + +function pad(str, len) { + str = String(str); + return Array(len - str.length + 1).join(' ') + str; +} + +/** + * Return a character diff for `err`. + * + * @param {Error} err + * @return {String} + * @api private + */ + +function errorDiff(err, type) { + return diff['diff' + type](err.actual, err.expected).map(function(str){ + if (str.added) return colorLines('diff added', str.value); + if (str.removed) return colorLines('diff removed', str.value); + return str.value; + }).join(''); +} + +/** + * Color lines for `str`, using the color `name`. + * + * @param {String} name + * @param {String} str + * @return {String} + * @api private + */ + +function colorLines(name, str) { + return str.split('\n').map(function(str){ + return color(name, str); + }).join('\n'); +} + }); // module: reporters/base.js require.register("reporters/doc.js", function(module, exports, require){ /** @@ -1245,10 +1491,57 @@ Dot.prototype = new Base; Dot.prototype.constructor = Dot; }); // module: reporters/dot.js +require.register("reporters/html-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var JSONCov = require('./json-cov') + , fs = require('browser/fs'); + +/** + * Expose `HTMLCov`. + */ + +exports = module.exports = HTMLCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTMLCov(runner) { + var jade = require('jade') + , file = __dirname + '/templates/coverage.jade' + , str = fs.readFileSync(file, 'utf8') + , fn = jade.compile(str, { filename: file }) + , self = this; + + JSONCov.call(this, runner, false); + + runner.on('end', function(){ + process.stdout.write(fn({ + cov: self.cov + , coverageClass: coverageClass + })); + }); +} + +function coverageClass(n) { + if (n >= 75) return 'high'; + if (n >= 50) return 'medium'; + if (n >= 25) return 'low'; + return 'terrible'; +} +}); // module: reporters/html-cov.js + require.register("reporters/html.js", function(module, exports, require){ /** * Module dependencies. */ @@ -1283,41 +1576,45 @@ */ function HTML(runner) { Base.call(this, runner); - // TODO: clean up - var self = this , stats = this.stats , total = runner.total - , root = $('#mocha') + , root = document.getElementById('mocha') + , stat = fragment(statsTemplate) + , items = stat.getElementsByTagName('li') + , passes = items[1].getElementsByTagName('em')[0] + , failures = items[2].getElementsByTagName('em')[0] + , duration = items[3].getElementsByTagName('em')[0] + , canvas = stat.getElementsByTagName('canvas')[0] , stack = [root] - , stat = $(statsTemplate).appendTo(root) - , canvas = stat.find('canvas').get(0) , progress , ctx if (canvas.getContext) { ctx = canvas.getContext('2d'); progress = new Progress; } - if (!root.length) return error('#mocha div missing, add it to your document'); + if (!root) return error('#mocha div missing, add it to your document'); + root.appendChild(stat); + if (progress) progress.size(40); runner.on('suite', function(suite){ if (suite.root) return; // suite - var el = $('<div class="suite"><h1>' + suite.title + '</h1></div>'); + var el = fragment('<div class="suite"><h1>%s</h1></div>', suite.title); // container - stack[0].append(el); - stack.unshift($('<div>')); - el.append(stack[0]); + stack[0].appendChild(el); + stack.unshift(document.createElement('div')); + el.appendChild(stack[0]); }); runner.on('suite end', function(suite){ if (suite.root) return; stack.shift(); @@ -1328,64 +1625,117 @@ }); runner.on('test end', function(test){ // TODO: add to stats var percent = stats.tests / total * 100 | 0; + if (progress) progress.update(percent).draw(ctx); - if (progress) { - progress.update(percent).draw(ctx); - } - // update stats var ms = new Date - stats.start; - stat.find('.passes em').text(stats.passes); - stat.find('.failures em').text(stats.failures); - stat.find('.duration em').text((ms / 1000).toFixed(2)); + text(passes, stats.passes); + text(failures, stats.failures); + text(duration, (ms / 1000).toFixed(2)); // test - if (test.passed) { - var el = $('<div class="test pass"><h2>' + escape(test.title) + '</h2></div>') + if ('passed' == test.state) { + var el = fragment('<div class="test pass"><h2>%e</h2></div>', test.title); } else if (test.pending) { - var el = $('<div class="test pass pending"><h2>' + escape(test.title) + '</h2></div>') + var el = fragment('<div class="test pass pending"><h2>%e</h2></div>', test.title); } else { - var el = $('<div class="test fail"><h2>' + escape(test.title) + '</h2></div>'); - var str = test.err.stack || test.err; + var el = fragment('<div class="test fail"><h2>%e</h2></div>', test.title); + var str = test.err.stack || test.err.toString(); + // FF / Opera do not add the message + if (!~str.indexOf(test.err.message)) { + str = test.err.message + '\n' + str; + } + // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we // check for the result of the stringifying. if ('[object Error]' == str) str = test.err.message; - $('<pre class="error">' + escape(str) + '</pre>').appendTo(el); + // Safari doesn't give you a stack. Let's at least provide a source line. + if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { + str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; + } + + el.appendChild(fragment('<pre class="error">%e</pre>', str)); } // toggle code - el.find('h2').toggle(function(){ - pre && pre.slideDown('fast'); - }, function(){ - pre && pre.slideUp('fast'); + var h2 = el.getElementsByTagName('h2')[0]; + + on(h2, 'click', function(){ + pre.style.display = 'none' == pre.style.display + ? 'block' + : 'none'; }); // code // TODO: defer if (!test.pending) { - var code = escape(clean(test.fn.toString())); - var pre = $('<pre><code>' + code + '</code></pre>'); - pre.appendTo(el).hide(); + var pre = fragment('<pre><code>%e</code></pre>', clean(test.fn.toString())); + el.appendChild(pre); + pre.style.display = 'none'; } - stack[0].append(el); + + stack[0].appendChild(el); }); } /** * Display error `msg`. */ function error(msg) { - $('<div id="error">' + msg + '</div>').appendTo('body'); + document.body.appendChild(fragment('<div id="error">%s</div>', msg)); } /** + * Return a DOM fragment from `html`. + */ + +function fragment(html) { + var args = arguments + , div = document.createElement('div') + , i = 1; + + div.innerHTML = html.replace(/%([se])/g, function(_, type){ + switch (type) { + case 's': return String(args[i++]); + case 'e': return escape(args[i++]); + } + }); + + return div.firstChild; +} + +/** + * Set `el` text to `str`. + */ + +function text(el, str) { + if (el.textContent) { + el.textContent = str; + } else { + el.innerText = str; + } +} + +/** + * Listen on `event` with callback `fn`. + */ + +function on(el, event, fn) { + if (el.addEventListener) { + el.addEventListener(event, fn, false); + } else { + el.attachEvent('on' + event, fn); + } +} + +/** * Strip the function definition from `str`, * and re-indent for pre whitespace. */ function clean(str) { @@ -1412,18 +1762,175 @@ exports.Doc = require('./doc'); exports.TAP = require('./tap'); exports.JSON = require('./json'); exports.HTML = require('./html'); exports.List = require('./list'); +exports.Min = require('./min'); exports.Spec = require('./spec'); exports.Progress = require('./progress'); exports.Landing = require('./landing'); +exports.JSONCov = require('./json-cov'); +exports.HTMLCov = require('./html-cov'); exports.JSONStream = require('./json-stream'); exports.XUnit = require('./xunit') +exports.Teamcity = require('./teamcity') }); // module: reporters/index.js +require.register("reporters/json-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `JSONCov`. + */ + +exports = module.exports = JSONCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @param {Boolean} output + * @api public + */ + +function JSONCov(runner, output) { + var self = this + , output = 1 == arguments.length ? true : output; + + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var cov = global._$jscoverage || {}; + var result = self.cov = map(cov); + result.stats = self.stats; + result.tests = tests.map(clean); + result.failures = failures.map(clean); + result.passes = passes.map(clean); + if (!output) return; + process.stdout.write(JSON.stringify(result, null, 2 )); + }); +} + +/** + * Map jscoverage data to a JSON structure + * suitable for reporting. + * + * @param {Object} cov + * @return {Object} + * @api private + */ + +function map(cov) { + var ret = { + instrumentation: 'node-jscoverage' + , sloc: 0 + , hits: 0 + , misses: 0 + , coverage: 0 + , files: [] + }; + + for (var filename in cov) { + var data = coverage(filename, cov[filename]); + ret.files.push(data); + ret.hits += data.hits; + ret.misses += data.misses; + ret.sloc += data.sloc; + } + + if (ret.sloc > 0) { + ret.coverage = (ret.hits / ret.sloc) * 100; + } + + return ret; +}; + +/** + * Map jscoverage data for a single source file + * to a JSON structure suitable for reporting. + * + * @param {String} filename name of the source file + * @param {Object} data jscoverage coverage data + * @return {Object} + * @api private + */ + +function coverage(filename, data) { + var ret = { + filename: filename, + coverage: 0, + hits: 0, + misses: 0, + sloc: 0, + source: {} + }; + + data.source.forEach(function(line, num){ + num++; + + if (data[num] === 0) { + ret.misses++; + ret.sloc++; + } else if (data[num] !== undefined) { + ret.hits++; + ret.sloc++; + } + + ret.source[num] = { + source: line + , coverage: data[num] === undefined + ? '' + : data[num] + }; + }); + + ret.coverage = ret.hits / ret.sloc * 100; + + return ret; +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} + +}); // module: reporters/json-cov.js + require.register("reporters/json-stream.js", function(module, exports, require){ /** * Module dependencies. */ @@ -1535,11 +2042,11 @@ , tests: tests.map(clean) , failures: failures.map(clean) , passes: passes.map(clean) }; - process.stdout.write(JSON.stringify(obj)); + process.stdout.write(JSON.stringify(obj, null, 2)); }); } /** * Return a plain-object representation of `test` @@ -1627,11 +2134,11 @@ var col = -1 == crashed ? width * ++n / total | 0 : crashed; // show the crash - if (test.failed) { + if ('failed' == test.state) { plane = color('plane crash', '✈'); crashed = col; } // render landing strip @@ -1729,10 +2236,166 @@ List.prototype.constructor = List; }); // module: reporters/list.js +require.register("reporters/markdown.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Markdown`. + */ + +exports = module.exports = Markdown; + +/** + * Initialize a new `Markdown` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Markdown(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , level = 0 + , buf = ''; + + function title(str) { + return Array(level).join('#') + ' ' + str; + } + + function indent() { + return Array(level).join(' '); + } + + function mapTOC(suite, obj) { + var ret = obj; + obj = obj[suite.title] = obj[suite.title] || { suite: suite }; + suite.suites.forEach(function(suite){ + mapTOC(suite, obj); + }); + return ret; + } + + function stringifyTOC(obj, level) { + ++level; + var buf = ''; + var link; + for (var key in obj) { + if ('suite' == key) continue; + if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; + if (key) buf += Array(level).join(' ') + link; + buf += stringifyTOC(obj[key], level); + } + --level; + return buf; + } + + function generateTOC(suite) { + var obj = mapTOC(suite, {}); + return stringifyTOC(obj, 0); + } + + generateTOC(runner.suite); + + runner.on('suite', function(suite){ + ++level; + var slug = utils.slug(suite.fullTitle()); + buf += '<a name="' + slug + '" />' + '\n'; + buf += title(suite.title) + '\n'; + }); + + runner.on('suite end', function(suite){ + --level; + }); + + runner.on('pass', function(test){ + var code = clean(test.fn.toString()); + buf += test.title + '.\n'; + buf += '\n```js'; + buf += code + '\n'; + buf += '```\n\n'; + }); + + runner.on('end', function(){ + process.stdout.write('# TOC\n'); + process.stdout.write(generateTOC(runner.suite)); + process.stdout.write(buf); + }); +} + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +function clean(str) { + str = str + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , re = new RegExp('^ {' + spaces + '}', 'gm'); + + str = str.replace(re, ''); + + return str; +} +}); // module: reporters/markdown.js + +require.register("reporters/min.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `Min`. + */ + +exports = module.exports = Min; + +/** + * Initialize a new `Min` minimal test reporter (best used with --watch). + * + * @param {Runner} runner + * @api public + */ + +function Min(runner) { + Base.call(this, runner); + + runner.on('start', function(){ + // clear screen + process.stdout.write('\033[2J'); + // set cursor position + process.stdout.write('\033[1;3H'); + }); + + runner.on('end', this.epilogue.bind(this)); +} + +/** + * Inherit from `Base.prototype`. + */ + +Min.prototype = new Base; +Min.prototype.constructor = Min; + +}); // module: reporters/min.js + require.register("reporters/progress.js", function(module, exports, require){ /** * Module dependencies. */ @@ -2107,11 +2770,11 @@ classname: test.parent.fullTitle() , name: test.title , time: test.duration / 1000 }; - if (test.failed) { + if ('failed' == test.state) { var err = test.err; attrs.message = escape(err.message); console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); } else if (test.pending) { console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); @@ -2434,11 +3097,11 @@ * @api private */ Runner.prototype.fail = function(test, err){ ++this.failures; - test.failed = true; + test.state = 'failed'; this.emit('fail', test, err); }; /** * Fail the given `hook` with `err`. @@ -2641,11 +3304,11 @@ self.fail(test, err); self.emit('test end', test); return self.hookUp('afterEach', next); } - test.passed = true; + test.state = 'passed'; self.emit('pass', test); self.emit('test end', test); self.hookUp('afterEach', next); }); }); @@ -2698,11 +3361,11 @@ */ Runner.prototype.uncaught = function(err){ debug('uncaught exception'); var runnable = this.currentRunnable; - if (runnable.failed) return; + if ('failed' == runnable.state) return; runnable.clearTimeout(); err.uncaught = true; this.fail(runnable, err); // recover from test @@ -2832,10 +3495,11 @@ */ Suite.prototype.clone = function(){ var suite = new Suite(this.title); debug('clone'); + suite.ctx = this.ctx; suite.timeout(this.timeout()); suite.bail(this.bail()); return suite; }; @@ -3176,13 +3840,13 @@ exports.keys = Object.keys || function(obj) { var keys = [] , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 - for (var i in obj) { - if (has.call(obj, i)) { - keys.push(i); + for (var key in obj) { + if (has.call(obj, key)) { + keys.push(key); } } return keys; }; @@ -3216,11 +3880,11 @@ /** * Lookup files in the given `dir`. * * @return {Array} - * @api public + * @api private */ exports.files = function(dir, ret){ ret = ret || []; @@ -3235,10 +3899,24 @@ } }); return ret; }; + +/** + * Compute a slug from the given `str`. + * + * @param {String} str + * @return {String} + */ + +exports.slug = function(str){ + return str + .toLowerCase() + .replace(/ +/g, '-') + .replace(/[^-\w]/g, ''); +}; }); // module: utils.js /** * Node shims. * @@ -3308,35 +3986,40 @@ // boot ;(function(){ var suite = new mocha.Suite('', new mocha.Context) , utils = mocha.utils - , Reporter = mocha.reporters.HTML + , options = {} - $(function(){ - $('code').each(function(){ - $(this).html(highlight($(this).text())); - }); - }); - /** * Highlight the given string of `js`. */ function highlight(js) { return js .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>') - .replace(/('.*')/gm, '<span class="string">$1</span>') + .replace(/('.*?')/gm, '<span class="string">$1</span>') .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>') .replace(/(\d+)/gm, '<span class="number">$1</span>') .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>') .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>') } /** + * Highlight code contents. + */ + + function highlightCode() { + var code = document.getElementsByTagName('code'); + for (var i = 0, len = code.length; i < len; ++i) { + code[i].innerHTML = highlight(code[i].innerHTML); + } + } + + /** * Parse the given `qs`. */ function parse(qs) { return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){ @@ -3348,16 +4031,20 @@ return obj; }, {}); } /** - * Setup mocha with the give `ui` name. + * Setup mocha with the given setting options. */ - mocha.setup = function(ui){ - ui = mocha.interfaces[ui]; + mocha.setup = function(opts){ + if ('string' === typeof opts) options.ui = opts; + else options = opts; + + ui = mocha.interfaces[options.ui]; if (!ui) throw new Error('invalid mocha interface "' + ui + '"'); + if (options.timeout) suite.timeout(options.timeout); ui(suite); suite.emit('pre-require', window); }; /** @@ -3365,17 +4052,17 @@ */ mocha.run = function(){ suite.emit('run'); var runner = new mocha.Runner(suite); + var Reporter = options.reporter || mocha.reporters.HTML; var reporter = new Reporter(runner); var query = parse(window.location.search || ""); if (query.grep) runner.grep(new RegExp(query.grep)); - runner.on('end', function(){ - $('code').each(function(){ - $(this).html(highlight($(this).text())); - }); - }); + if (options.ignoreLeaks) runner.ignoreLeaks = true; + if (options.globals) runner.globals(options.globals); + runner.globals(['location']); + runner.on('end', highlightCode); return runner.run(); }; })(); })(); \ No newline at end of file