'use strict'; /* eslint no-unused-vars: off */ /* eslint-env commonjs */ /** * Shim process.stdout. */ process.stdout = require('browser-stdout')({label: false}); var parseQuery = require('./lib/browser/parse-query'); var highlightTags = require('./lib/browser/highlight-tags'); var Mocha = require('./lib/mocha'); /** * Create a Mocha instance. * * @return {undefined} */ var mocha = new Mocha({reporter: 'html'}); /** * Save timer references to avoid Sinon interfering (see GH-237). */ var Date = global.Date; var setTimeout = global.setTimeout; var setInterval = global.setInterval; var clearTimeout = global.clearTimeout; var clearInterval = global.clearInterval; var uncaughtExceptionHandlers = []; var originalOnerrorHandler = global.onerror; /** * Remove uncaughtException listener. * Revert to original onerror handler if previously defined. */ process.removeListener = function(e, fn) { if (e === 'uncaughtException') { if (originalOnerrorHandler) { global.onerror = originalOnerrorHandler; } else { global.onerror = function() {}; } var i = uncaughtExceptionHandlers.indexOf(fn); if (i !== -1) { uncaughtExceptionHandlers.splice(i, 1); } } }; /** * Implements listenerCount for 'uncaughtException'. */ process.listenerCount = function(name) { if (name === 'uncaughtException') { return uncaughtExceptionHandlers.length; } return 0; }; /** * Implements uncaughtException listener. */ process.on = function(e, fn) { if (e === 'uncaughtException') { global.onerror = function(err, url, line) { fn(new Error(err + ' (' + url + ':' + line + ')')); return !mocha.options.allowUncaught; }; uncaughtExceptionHandlers.push(fn); } }; process.listeners = function(e) { if (e === 'uncaughtException') { return uncaughtExceptionHandlers; } return []; }; // The BDD UI is registered by default, but no UI will be functional in the // browser without an explicit call to the overridden `mocha.ui` (see below). // Ensure that this default UI does not expose its methods to the global scope. mocha.suite.removeAllListeners('pre-require'); var immediateQueue = []; var immediateTimeout; function timeslice() { var immediateStart = new Date().getTime(); while (immediateQueue.length && new Date().getTime() - immediateStart < 100) { immediateQueue.shift()(); } if (immediateQueue.length) { immediateTimeout = setTimeout(timeslice, 0); } else { immediateTimeout = null; } } /** * High-performance override of Runner.immediately. */ Mocha.Runner.immediately = function(callback) { immediateQueue.push(callback); if (!immediateTimeout) { immediateTimeout = setTimeout(timeslice, 0); } }; /** * Function to allow assertion libraries to throw errors directly into mocha. * This is useful when running tests in a browser because window.onerror will * only receive the 'message' attribute of the Error. */ mocha.throwError = function(err) { uncaughtExceptionHandlers.forEach(function(fn) { fn(err); }); throw err; }; /** * Override ui to ensure that the ui functions are initialized. * Normally this would happen in Mocha.prototype.loadFiles. */ mocha.ui = function(ui) { Mocha.prototype.ui.call(this, ui); this.suite.emit('pre-require', global, null, this); return this; }; /** * Setup mocha with the given setting options. */ mocha.setup = function(opts) { if (typeof opts === 'string') { opts = {ui: opts}; } if (opts.delay === true) { this.delay(); } var self = this; Object.keys(opts) .filter(function(opt) { return opt !== 'delay'; }) .forEach(function(opt) { if (Object.prototype.hasOwnProperty.call(opts, opt)) { self[opt](opts[opt]); } }); return this; }; /** * Run mocha, returning the Runner. */ mocha.run = function(fn) { var options = mocha.options; mocha.globals('location'); var query = parseQuery(global.location.search || ''); 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) { // The DOM Document is not available in Web Workers. var document = global.document; if ( document && document.getElementById('mocha') && options.noHighlighting !== true ) { highlightTags('code'); } if (fn) { fn(err); } }); }; /** * Expose the process shim. * https://github.com/mochajs/mocha/pull/916 */ Mocha.process = process; /** * Expose mocha. */ global.Mocha = Mocha; global.mocha = mocha; // this allows test/acceptance/required-tokens.js to pass; thus, // you can now do `const describe = require('mocha').describe` in a // browser context (assuming browserification). should fix #880 module.exports = Object.assign(mocha, global);