Вход Регистрация
Файл: error-kitty/node_modules/mocha/lib/runner.js
Строк: 639
<?php
/**
 * Module dependencies.
 */

var EventEmitter = require('events').EventEmitter
  
debug = require('debug')('mocha:runner')
  , 
Test = require('./test')
  , 
utils = require('./utils')
  , 
filter utils.filter
  
keys utils.keys;

/**
 * Non-enumerable globals.
 */

var globals = [
  
'setTimeout',
  
'clearTimeout',
  
'setInterval',
  
'clearInterval',
  
'XMLHttpRequest',
  
'Date'
];

/**
 * Expose `Runner`.
 */

module.exports Runner;

/**
 * Initialize a `Runner` for the given `suite`.
 *
 * Events:
 *
 *   - `start`  execution started
 *   - `end`  execution complete
 *   - `suite`  (suite) test suite execution started
 *   - `suite end`  (suite) all tests (and sub-suites) have finished
 *   - `test`  (test) test execution started
 *   - `test end`  (test) test completed
 *   - `hook`  (hook) hook execution started
 *   - `hook end`  (hook) hook complete
 *   - `pass`  (test) test passed
 *   - `fail`  (test, err) test failed
 *   - `pending`  (test) test pending
 *
 * @api public
 */

function Runner(suite) {
  var 
self this;
  
this._globals = [];
  
this._abort false;
  
this.suite suite;
  
this.total suite.total();
  
this.failures 0;
  
this.on('test end', function(test){ self.checkGlobals(test); });
  
this.on('hook end', function(hook){ self.checkGlobals(hook); });
  
this.grep(/.*/);
  
this.globals(this.globalProps().concat(extraGlobals()));
}

/**
 * Wrapper for setImmediate, process.nextTick, or browser polyfill.
 *
 * @param {Function} fn
 * @api private
 */

Runner.immediately = global.setImmediate || process.nextTick;

/**
 * Inherit from `EventEmitter.prototype`.
 */

Runner.prototype.__proto__ EventEmitter.prototype;

/**
 * Run tests with full titles matching `re`. Updates runner.total
 * with number of tests matched.
 *
 * @param {RegExp} re
 * @param {Boolean} invert
 * @return {Runner} for chaining
 * @api public
 */

Runner.prototype.grep = function(reinvert){
  
debug('grep %s're);
  
this._grep re;
  
this._invert invert;
  
this.total this.grepTotal(this.suite);
  return 
this;
};

/**
 * Returns the number of tests matching the grep search for the
 * given suite.
 *
 * @param {Suite} suite
 * @return {Number}
 * @api public
 */

Runner.prototype.grepTotal = function(suite) {
  var 
self this;
  var 
total 0;

  
suite.eachTest(function(test){
    var 
match self._grep.test(test.fullTitle());
    if (
self._invertmatch = !match;
    if (
matchtotal++;
  });

  return 
total;
};

/**
 * Return a list of global properties.
 *
 * @return {Array}
 * @api private
 */

Runner.prototype.globalProps = function() {
  var 
props utils.keys(global);

  
// non-enumerables
  
for (var 0globals.length; ++i) {
    if (~
utils.indexOf(propsglobals[i])) continue;
    
props.push(globals[i]);
  }

  return 
props;
};

/**
 * Allow the given `arr` of globals.
 *
 * @param {Array} arr
 * @return {Runner} for chaining
 * @api public
 */

Runner.prototype.globals = function(arr){
  if (
== arguments.length) return this._globals;
  
debug('globals %j'arr);
  
this._globals this._globals.concat(arr);
  return 
this;
};

/**
 * Check for global variable leaks.
 *
 * @api private
 */

Runner.prototype.checkGlobals = function(test){
  if (
this.ignoreLeaks) return;
  var 
ok this._globals;

  var 
globals this.globalProps();
  var 
leaks;

  if (
test) {
    
ok ok.concat(test._allowedGlobals || []);
  }

  if(
this.prevGlobalsLength == globals.length) return;
  
this.prevGlobalsLength globals.length;

  
leaks filterLeaks(okglobals);
  
this._globals this._globals.concat(leaks);

  if (
leaks.length 1) {
    
this.fail(test, new Error('global leaks detected: ' leaks.join(', ') + ''));
  } else if (
leaks.length) {
    
this.fail(test, new Error('global leak detected: ' leaks[0]));
  }
};

/**
 * Fail the given `test`.
 *
 * @param {Test} test
 * @param {Error} err
 * @api private
 */

Runner.prototype.fail = function(testerr){
  ++
this.failures;
  
test.state 'failed';

  if (
'string' == typeof err) {
    
err = new Error('the string "' err '" was thrown, throw an Error :)');
  }

  
this.emit('fail'testerr);
};

/**
 * Fail the given `hook` with `err`.
 *
 * Hook failures work in the following pattern:
 * - If bail, then exit
 * - Failed `before` hook skips all tests in a suite and subsuites,
 *   but jumps to corresponding `after` hook
 * - Failed `before each` hook skips remaining tests in a
 *   suite and jumps to corresponding `after each` hook,
 *   which is run only once
 * - Failed `after` hook does not alter
 *   execution order
 * - Failed `after each` hook skips remaining tests in a
 *   suite and subsuites, but executes other `after each`
 *   hooks
 *
 * @param {Hook} hook
 * @param {Error} err
 * @api private
 */

Runner.prototype.failHook = function(hookerr){
  
this.fail(hookerr);
  if (
this.suite.bail()) {
    
this.emit('end');
  }
};

/**
 * Run hook `name` callbacks and then invoke `fn()`.
 *
 * @param {String} name
 * @param {Function} function
 * @api private
 */

Runner.prototype.hook = function(namefn){
  var 
suite this.suite
    
hooks suite['_' name]
    , 
self this
    
timer;

  function 
next(i) {
    var 
hook hooks[i];
    if (!
hook) return fn();
    if (
self.failures && suite.bail()) return fn();
    
self.currentRunnable hook;

    
hook.ctx.currentTest self.test;

    
self.emit('hook'hook);

    
hook.on('error', function(err){
      
self.failHook(hookerr);
    });

    
hook.run(function(err){
      
hook.removeAllListeners('error');
      var 
testError hook.error();
      if (
testErrorself.fail(self.testtestError);
      if (
err) {
        
self.failHook(hookerr);

        
// stop executing hooks, notify callee of hook err
        
return fn(err);
      }
      
self.emit('hook end'hook);
      
delete hook.ctx.currentTest;
      
next(++i);
    });
  }

  
Runner.immediately(function(){
    
next(0);
  });
};

/**
 * Run hook `name` for the given array of `suites`
 * in order, and callback `fn(err, errSuite)`.
 *
 * @param {String} name
 * @param {Array} suites
 * @param {Function} fn
 * @api private
 */

Runner.prototype.hooks = function(namesuitesfn){
  var 
self this
    
orig this.suite;

  function 
next(suite) {
    
self.suite suite;

    if (!
suite) {
      
self.suite orig;
      return 
fn();
    }

    
self.hook(name, function(err){
      if (
err) {
        var 
errSuite self.suite;
        
self.suite orig;
        return 
fn(errerrSuite);
      }

      
next(suites.pop());
    });
  }

  
next(suites.pop());
};

/**
 * Run hooks from the top level down.
 *
 * @param {String} name
 * @param {Function} fn
 * @api private
 */

Runner.prototype.hookUp = function(namefn){
  var 
suites = [this.suite].concat(this.parents()).reverse();
  
this.hooks(namesuitesfn);
};

/**
 * Run hooks from the bottom up.
 *
 * @param {String} name
 * @param {Function} fn
 * @api private
 */

Runner.prototype.hookDown = function(namefn){
  var 
suites = [this.suite].concat(this.parents());
  
this.hooks(namesuitesfn);
};

/**
 * Return an array of parent Suites from
 * closest to furthest.
 *
 * @return {Array}
 * @api private
 */

Runner.prototype.parents = function(){
  var 
suite this.suite
    
suites = [];
  while (
suite suite.parentsuites.push(suite);
  return 
suites;
};

/**
 * Run the current test and callback `fn(err)`.
 *
 * @param {Function} fn
 * @api private
 */

Runner.prototype.runTest = function(fn){
  var 
test this.test
    
self this;

  if (
this.asyncOnlytest.asyncOnly true;

  try {
    
test.on('error', function(err){
      
self.fail(testerr);
    });
    
test.run(fn);
  } catch (
err) {
    
fn(err);
  }
};

/**
 * Run tests in the given `suite` and invoke
 * the callback `fn()` when complete.
 *
 * @param {Suite} suite
 * @param {Function} fn
 * @api private
 */

Runner.prototype.runTests = function(suitefn){
  var 
self this
    
tests suite.tests.slice()
    , 
test;


  function 
hookErr(errerrSuiteafter) {
    
// before/after Each hook for errSuite failed:
    
var orig self.suite;

    
// for failed 'after each' hook start from errSuite parent,
    // otherwise start from errSuite itself
    
self.suite after errSuite.parent errSuite;

    if (
self.suite) {
      
// call hookUp afterEach
      
self.hookUp('afterEach', function(err2errSuite2) {
        
self.suite orig;
        
// some hooks may fail even now
        
if (err2) return hookErr(err2errSuite2true);
        
// report error suite
        
fn(errSuite);
      });
    } else {
      
// there is no need calling other 'after each' hooks
      
self.suite orig;
      
fn(errSuite);
    }
  }

  function 
next(errerrSuite) {
    
// if we bail after first err
    
if (self.failures && suite._bail) return fn();

    if (
self._abort) return fn();

    if (
err) return hookErr(errerrSuitetrue);

    
// next test
    
test tests.shift();

    
// all done
    
if (!test) return fn();

    
// grep
    
var match self._grep.test(test.fullTitle());
    if (
self._invertmatch = !match;
    if (!
match) return next();

    
// pending
    
if (test.pending) {
      
self.emit('pending'test);
      
self.emit('test end'test);
      return 
next();
    }

    
// execute test and hook(s)
    
self.emit('test'self.test test);
    
self.hookDown('beforeEach', function(errerrSuite){

      if (
err) return hookErr(errerrSuitefalse);

      
self.currentRunnable self.test;
      
self.runTest(function(err){
        
test self.test;

        if (
err) {
          
self.fail(testerr);
          
self.emit('test end'test);
          return 
self.hookUp('afterEach'next);
        }

        
test.state 'passed';
        
self.emit('pass'test);
        
self.emit('test end'test);
        
self.hookUp('afterEach'next);
      });
    });
  }

  
this.next next;
  
next();
};

/**
 * Run the given `suite` and invoke the
 * callback `fn()` when complete.
 *
 * @param {Suite} suite
 * @param {Function} fn
 * @api private
 */

Runner.prototype.runSuite = function(suitefn){
  var 
total this.grepTotal(suite)
    , 
self this
    
0;

  
debug('run suite %s'suite.fullTitle());

  if (!
total) return fn();

  
this.emit('suite'this.suite suite);

  function 
next(errSuite) {
    if (
errSuite) {
      
// current suite failed on a hook from errSuite
      
if (errSuite == suite) {
        
// if errSuite is current suite
        // continue to the next sibling suite
        
return done();
      } else {
        
// errSuite is among the parents of current suite
        // stop execution of errSuite and all sub-suites
        
return done(errSuite);
      }
    }

    if (
self._abort) return done();

    var 
curr suite.suites[i++];
    if (!
curr) return done();
    
self.runSuite(currnext);
  }

  function 
done(errSuite) {
    
self.suite suite;
    
self.hook('afterAll', function(){
      
self.emit('suite end'suite);
      
fn(errSuite);
    });
  }

  
this.hook('beforeAll', function(err){
    if (
err) return done();
    
self.runTests(suitenext);
  });
};

/**
 * Handle uncaught exceptions.
 *
 * @param {Error} err
 * @api private
 */

Runner.prototype.uncaught = function(err){
  if (
err) {
    
debug('uncaught exception %s'err.message);
  } else {
    
debug('uncaught undefined exception');
    
err = new Error('Catched undefined error, did you throw without specifying what?');
  }
  
  var 
runnable this.currentRunnable;
  if (!
runnable || 'failed' == runnable.state) return;
  
runnable.clearTimeout();
  
err.uncaught true;
  
this.fail(runnableerr);

  
// recover from test
  
if ('test' == runnable.type) {
    
this.emit('test end'runnable);
    
this.hookUp('afterEach'this.next);
    return;
  }

  
// bail on hooks
  
this.emit('end');
};

/**
 * Run the root suite and invoke `fn(failures)`
 * on completion.
 *
 * @param {Function} fn
 * @return {Runner} for chaining
 * @api public
 */

Runner.prototype.run = function(fn){
  var 
self this
    
fn fn || function(){};

  function 
uncaught(err){
    
self.uncaught(err);
  }

  
debug('start');

  
// callback
  
this.on('end', function(){
    
debug('end');
    
process.removeListener('uncaughtException'uncaught);
    
fn(self.failures);
  });

  
// run suites
  
this.emit('start');
  
this.runSuite(this.suite, function(){
    
debug('finished running');
    
self.emit('end');
  });

  
// uncaught exception
  
process.on('uncaughtException'uncaught);

  return 
this;
};

/**
 * Cleanly abort execution
 *
 * @return {Runner} for chaining
 * @api public
 */
Runner.prototype.abort = function(){
  
debug('aborting');
  
this._abort true;
}

/**
 * Filter leaks with the given globals flagged as `ok`.
 *
 * @param {Array} ok
 * @param {Array} globals
 * @return {Array}
 * @api private
 */

function filterLeaks(okglobals) {
  return 
filter(globals, function(key){
    
// Firefox and Chrome exposes iframes as index inside the window object
    
if (/^d+/.test(key)) return false;

    
// in firefox
    // if runner runs in an iframe, this iframe's window.getInterface method not init at first
    // it is assigned in some seconds
    
if (global.navigator && /^getInterface/.test(key)) return false;

    
// an iframe could be approached by window[iframeIndex]
    // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak
    
if (global.navigator && /^d+/.test(key)) return false;

    
// Opera and IE expose global variables for HTML element IDs (issue #243)
    
if (/^mocha-/.test(key)) return false;

    var 
matched filter(ok, function(ok){
      if (~
ok.indexOf('*')) return == key.indexOf(ok.split('*')[0]);
      return 
key == ok;
    });
    return 
matched.length == && (!global.navigator || 'onerror' !== key);
  });
}

/**
 * Array of globals dependent on the environment.
 *
 * @return {Array}
 * @api private
 */

 
function extraGlobals() {
  if (
typeof(process) === 'object' &&
      
typeof(process.version) === 'string') {

    var 
nodeVersion process.version.split('.').reduce(function(av) {
      return 
<< v;
    });

    
// 'errno' was renamed to process._errno in v0.9.11.

    
if (nodeVersion 0x00090B) {
      return [
'errno'];
    }
  }

  return [];
 }
?>
Онлайн: 0
Реклама