runner.js 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. 'use strict';
  2. /**
  3. * Module dependencies.
  4. */
  5. var util = require('util');
  6. var EventEmitter = require('events').EventEmitter;
  7. var Pending = require('./pending');
  8. var utils = require('./utils');
  9. var inherits = utils.inherits;
  10. var debug = require('debug')('mocha:runner');
  11. var Runnable = require('./runnable');
  12. var Suite = require('./suite');
  13. var HOOK_TYPE_BEFORE_EACH = Suite.constants.HOOK_TYPE_BEFORE_EACH;
  14. var HOOK_TYPE_AFTER_EACH = Suite.constants.HOOK_TYPE_AFTER_EACH;
  15. var HOOK_TYPE_AFTER_ALL = Suite.constants.HOOK_TYPE_AFTER_ALL;
  16. var HOOK_TYPE_BEFORE_ALL = Suite.constants.HOOK_TYPE_BEFORE_ALL;
  17. var EVENT_ROOT_SUITE_RUN = Suite.constants.EVENT_ROOT_SUITE_RUN;
  18. var STATE_FAILED = Runnable.constants.STATE_FAILED;
  19. var STATE_PASSED = Runnable.constants.STATE_PASSED;
  20. var dQuote = utils.dQuote;
  21. var ngettext = utils.ngettext;
  22. var sQuote = utils.sQuote;
  23. var stackFilter = utils.stackTraceFilter();
  24. var stringify = utils.stringify;
  25. var type = utils.type;
  26. var createInvalidExceptionError = require('./errors')
  27. .createInvalidExceptionError;
  28. /**
  29. * Non-enumerable globals.
  30. * @readonly
  31. */
  32. var globals = [
  33. 'setTimeout',
  34. 'clearTimeout',
  35. 'setInterval',
  36. 'clearInterval',
  37. 'XMLHttpRequest',
  38. 'Date',
  39. 'setImmediate',
  40. 'clearImmediate'
  41. ];
  42. var constants = utils.defineConstants(
  43. /**
  44. * {@link Runner}-related constants.
  45. * @public
  46. * @memberof Runner
  47. * @readonly
  48. * @alias constants
  49. * @static
  50. * @enum {string}
  51. */
  52. {
  53. /**
  54. * Emitted when {@link Hook} execution begins
  55. */
  56. EVENT_HOOK_BEGIN: 'hook',
  57. /**
  58. * Emitted when {@link Hook} execution ends
  59. */
  60. EVENT_HOOK_END: 'hook end',
  61. /**
  62. * Emitted when Root {@link Suite} execution begins (all files have been parsed and hooks/tests are ready for execution)
  63. */
  64. EVENT_RUN_BEGIN: 'start',
  65. /**
  66. * Emitted when Root {@link Suite} execution has been delayed via `delay` option
  67. */
  68. EVENT_DELAY_BEGIN: 'waiting',
  69. /**
  70. * Emitted when delayed Root {@link Suite} execution is triggered by user via `global.run()`
  71. */
  72. EVENT_DELAY_END: 'ready',
  73. /**
  74. * Emitted when Root {@link Suite} execution ends
  75. */
  76. EVENT_RUN_END: 'end',
  77. /**
  78. * Emitted when {@link Suite} execution begins
  79. */
  80. EVENT_SUITE_BEGIN: 'suite',
  81. /**
  82. * Emitted when {@link Suite} execution ends
  83. */
  84. EVENT_SUITE_END: 'suite end',
  85. /**
  86. * Emitted when {@link Test} execution begins
  87. */
  88. EVENT_TEST_BEGIN: 'test',
  89. /**
  90. * Emitted when {@link Test} execution ends
  91. */
  92. EVENT_TEST_END: 'test end',
  93. /**
  94. * Emitted when {@link Test} execution fails
  95. */
  96. EVENT_TEST_FAIL: 'fail',
  97. /**
  98. * Emitted when {@link Test} execution succeeds
  99. */
  100. EVENT_TEST_PASS: 'pass',
  101. /**
  102. * Emitted when {@link Test} becomes pending
  103. */
  104. EVENT_TEST_PENDING: 'pending',
  105. /**
  106. * Emitted when {@link Test} execution has failed, but will retry
  107. */
  108. EVENT_TEST_RETRY: 'retry'
  109. }
  110. );
  111. module.exports = Runner;
  112. /**
  113. * Initialize a `Runner` at the Root {@link Suite}, which represents a hierarchy of {@link Suite|Suites} and {@link Test|Tests}.
  114. *
  115. * @extends external:EventEmitter
  116. * @public
  117. * @class
  118. * @param {Suite} suite Root suite
  119. * @param {boolean} [delay] Whether or not to delay execution of root suite
  120. * until ready.
  121. */
  122. function Runner(suite, delay) {
  123. var self = this;
  124. this._globals = [];
  125. this._abort = false;
  126. this._delay = delay;
  127. this.suite = suite;
  128. this.started = false;
  129. this.total = suite.total();
  130. this.failures = 0;
  131. this.on(constants.EVENT_TEST_END, function(test) {
  132. self.checkGlobals(test);
  133. });
  134. this.on(constants.EVENT_HOOK_END, function(hook) {
  135. self.checkGlobals(hook);
  136. });
  137. this._defaultGrep = /.*/;
  138. this.grep(this._defaultGrep);
  139. this.globals(this.globalProps().concat(extraGlobals()));
  140. }
  141. /**
  142. * Wrapper for setImmediate, process.nextTick, or browser polyfill.
  143. *
  144. * @param {Function} fn
  145. * @private
  146. */
  147. Runner.immediately = global.setImmediate || process.nextTick;
  148. /**
  149. * Inherit from `EventEmitter.prototype`.
  150. */
  151. inherits(Runner, EventEmitter);
  152. /**
  153. * Run tests with full titles matching `re`. Updates runner.total
  154. * with number of tests matched.
  155. *
  156. * @public
  157. * @memberof Runner
  158. * @param {RegExp} re
  159. * @param {boolean} invert
  160. * @return {Runner} Runner instance.
  161. */
  162. Runner.prototype.grep = function(re, invert) {
  163. debug('grep %s', re);
  164. this._grep = re;
  165. this._invert = invert;
  166. this.total = this.grepTotal(this.suite);
  167. return this;
  168. };
  169. /**
  170. * Returns the number of tests matching the grep search for the
  171. * given suite.
  172. *
  173. * @memberof Runner
  174. * @public
  175. * @param {Suite} suite
  176. * @return {number}
  177. */
  178. Runner.prototype.grepTotal = function(suite) {
  179. var self = this;
  180. var total = 0;
  181. suite.eachTest(function(test) {
  182. var match = self._grep.test(test.fullTitle());
  183. if (self._invert) {
  184. match = !match;
  185. }
  186. if (match) {
  187. total++;
  188. }
  189. });
  190. return total;
  191. };
  192. /**
  193. * Return a list of global properties.
  194. *
  195. * @return {Array}
  196. * @private
  197. */
  198. Runner.prototype.globalProps = function() {
  199. var props = Object.keys(global);
  200. // non-enumerables
  201. for (var i = 0; i < globals.length; ++i) {
  202. if (~props.indexOf(globals[i])) {
  203. continue;
  204. }
  205. props.push(globals[i]);
  206. }
  207. return props;
  208. };
  209. /**
  210. * Allow the given `arr` of globals.
  211. *
  212. * @public
  213. * @memberof Runner
  214. * @param {Array} arr
  215. * @return {Runner} Runner instance.
  216. */
  217. Runner.prototype.globals = function(arr) {
  218. if (!arguments.length) {
  219. return this._globals;
  220. }
  221. debug('globals %j', arr);
  222. this._globals = this._globals.concat(arr);
  223. return this;
  224. };
  225. /**
  226. * Check for global variable leaks.
  227. *
  228. * @private
  229. */
  230. Runner.prototype.checkGlobals = function(test) {
  231. if (this.ignoreLeaks) {
  232. return;
  233. }
  234. var ok = this._globals;
  235. var globals = this.globalProps();
  236. var leaks;
  237. if (test) {
  238. ok = ok.concat(test._allowedGlobals || []);
  239. }
  240. if (this.prevGlobalsLength === globals.length) {
  241. return;
  242. }
  243. this.prevGlobalsLength = globals.length;
  244. leaks = filterLeaks(ok, globals);
  245. this._globals = this._globals.concat(leaks);
  246. if (leaks.length) {
  247. var format = ngettext(
  248. leaks.length,
  249. 'global leak detected: %s',
  250. 'global leaks detected: %s'
  251. );
  252. var error = new Error(util.format(format, leaks.map(sQuote).join(', ')));
  253. this.fail(test, error);
  254. }
  255. };
  256. /**
  257. * Fail the given `test`.
  258. *
  259. * @private
  260. * @param {Test} test
  261. * @param {Error} err
  262. */
  263. Runner.prototype.fail = function(test, err) {
  264. if (test.isPending()) {
  265. return;
  266. }
  267. ++this.failures;
  268. test.state = STATE_FAILED;
  269. if (!isError(err)) {
  270. err = thrown2Error(err);
  271. }
  272. try {
  273. err.stack =
  274. this.fullStackTrace || !err.stack ? err.stack : stackFilter(err.stack);
  275. } catch (ignore) {
  276. // some environments do not take kindly to monkeying with the stack
  277. }
  278. this.emit(constants.EVENT_TEST_FAIL, test, err);
  279. };
  280. /**
  281. * Fail the given `hook` with `err`.
  282. *
  283. * Hook failures work in the following pattern:
  284. * - If bail, run corresponding `after each` and `after` hooks,
  285. * then exit
  286. * - Failed `before` hook skips all tests in a suite and subsuites,
  287. * but jumps to corresponding `after` hook
  288. * - Failed `before each` hook skips remaining tests in a
  289. * suite and jumps to corresponding `after each` hook,
  290. * which is run only once
  291. * - Failed `after` hook does not alter
  292. * execution order
  293. * - Failed `after each` hook skips remaining tests in a
  294. * suite and subsuites, but executes other `after each`
  295. * hooks
  296. *
  297. * @private
  298. * @param {Hook} hook
  299. * @param {Error} err
  300. */
  301. Runner.prototype.failHook = function(hook, err) {
  302. hook.originalTitle = hook.originalTitle || hook.title;
  303. if (hook.ctx && hook.ctx.currentTest) {
  304. hook.title =
  305. hook.originalTitle + ' for ' + dQuote(hook.ctx.currentTest.title);
  306. } else {
  307. var parentTitle;
  308. if (hook.parent.title) {
  309. parentTitle = hook.parent.title;
  310. } else {
  311. parentTitle = hook.parent.root ? '{root}' : '';
  312. }
  313. hook.title = hook.originalTitle + ' in ' + dQuote(parentTitle);
  314. }
  315. this.fail(hook, err);
  316. };
  317. /**
  318. * Run hook `name` callbacks and then invoke `fn()`.
  319. *
  320. * @private
  321. * @param {string} name
  322. * @param {Function} fn
  323. */
  324. Runner.prototype.hook = function(name, fn) {
  325. var suite = this.suite;
  326. var hooks = suite.getHooks(name);
  327. var self = this;
  328. function next(i) {
  329. var hook = hooks[i];
  330. if (!hook) {
  331. return fn();
  332. }
  333. self.currentRunnable = hook;
  334. if (name === 'beforeAll') {
  335. hook.ctx.currentTest = hook.parent.tests[0];
  336. } else if (name === 'afterAll') {
  337. hook.ctx.currentTest = hook.parent.tests[hook.parent.tests.length - 1];
  338. } else {
  339. hook.ctx.currentTest = self.test;
  340. }
  341. self.emit(constants.EVENT_HOOK_BEGIN, hook);
  342. if (!hook.listeners('error').length) {
  343. hook.on('error', function(err) {
  344. self.failHook(hook, err);
  345. });
  346. }
  347. hook.run(function(err) {
  348. var testError = hook.error();
  349. if (testError) {
  350. self.fail(self.test, testError);
  351. }
  352. if (err) {
  353. if (err instanceof Pending) {
  354. if (name === HOOK_TYPE_BEFORE_EACH || name === HOOK_TYPE_AFTER_EACH) {
  355. self.test.pending = true;
  356. } else {
  357. suite.tests.forEach(function(test) {
  358. test.pending = true;
  359. });
  360. suite.suites.forEach(function(suite) {
  361. suite.pending = true;
  362. });
  363. // a pending hook won't be executed twice.
  364. hook.pending = true;
  365. }
  366. } else {
  367. self.failHook(hook, err);
  368. // stop executing hooks, notify callee of hook err
  369. return fn(err);
  370. }
  371. }
  372. self.emit(constants.EVENT_HOOK_END, hook);
  373. delete hook.ctx.currentTest;
  374. next(++i);
  375. });
  376. }
  377. Runner.immediately(function() {
  378. next(0);
  379. });
  380. };
  381. /**
  382. * Run hook `name` for the given array of `suites`
  383. * in order, and callback `fn(err, errSuite)`.
  384. *
  385. * @private
  386. * @param {string} name
  387. * @param {Array} suites
  388. * @param {Function} fn
  389. */
  390. Runner.prototype.hooks = function(name, suites, fn) {
  391. var self = this;
  392. var orig = this.suite;
  393. function next(suite) {
  394. self.suite = suite;
  395. if (!suite) {
  396. self.suite = orig;
  397. return fn();
  398. }
  399. self.hook(name, function(err) {
  400. if (err) {
  401. var errSuite = self.suite;
  402. self.suite = orig;
  403. return fn(err, errSuite);
  404. }
  405. next(suites.pop());
  406. });
  407. }
  408. next(suites.pop());
  409. };
  410. /**
  411. * Run hooks from the top level down.
  412. *
  413. * @param {String} name
  414. * @param {Function} fn
  415. * @private
  416. */
  417. Runner.prototype.hookUp = function(name, fn) {
  418. var suites = [this.suite].concat(this.parents()).reverse();
  419. this.hooks(name, suites, fn);
  420. };
  421. /**
  422. * Run hooks from the bottom up.
  423. *
  424. * @param {String} name
  425. * @param {Function} fn
  426. * @private
  427. */
  428. Runner.prototype.hookDown = function(name, fn) {
  429. var suites = [this.suite].concat(this.parents());
  430. this.hooks(name, suites, fn);
  431. };
  432. /**
  433. * Return an array of parent Suites from
  434. * closest to furthest.
  435. *
  436. * @return {Array}
  437. * @private
  438. */
  439. Runner.prototype.parents = function() {
  440. var suite = this.suite;
  441. var suites = [];
  442. while (suite.parent) {
  443. suite = suite.parent;
  444. suites.push(suite);
  445. }
  446. return suites;
  447. };
  448. /**
  449. * Run the current test and callback `fn(err)`.
  450. *
  451. * @param {Function} fn
  452. * @private
  453. */
  454. Runner.prototype.runTest = function(fn) {
  455. var self = this;
  456. var test = this.test;
  457. if (!test) {
  458. return;
  459. }
  460. var suite = this.parents().reverse()[0] || this.suite;
  461. if (this.forbidOnly && suite.hasOnly()) {
  462. fn(new Error('`.only` forbidden'));
  463. return;
  464. }
  465. if (this.asyncOnly) {
  466. test.asyncOnly = true;
  467. }
  468. test.on('error', function(err) {
  469. self.fail(test, err);
  470. });
  471. if (this.allowUncaught) {
  472. test.allowUncaught = true;
  473. return test.run(fn);
  474. }
  475. try {
  476. test.run(fn);
  477. } catch (err) {
  478. fn(err);
  479. }
  480. };
  481. /**
  482. * Run tests in the given `suite` and invoke the callback `fn()` when complete.
  483. *
  484. * @private
  485. * @param {Suite} suite
  486. * @param {Function} fn
  487. */
  488. Runner.prototype.runTests = function(suite, fn) {
  489. var self = this;
  490. var tests = suite.tests.slice();
  491. var test;
  492. function hookErr(_, errSuite, after) {
  493. // before/after Each hook for errSuite failed:
  494. var orig = self.suite;
  495. // for failed 'after each' hook start from errSuite parent,
  496. // otherwise start from errSuite itself
  497. self.suite = after ? errSuite.parent : errSuite;
  498. if (self.suite) {
  499. // call hookUp afterEach
  500. self.hookUp(HOOK_TYPE_AFTER_EACH, function(err2, errSuite2) {
  501. self.suite = orig;
  502. // some hooks may fail even now
  503. if (err2) {
  504. return hookErr(err2, errSuite2, true);
  505. }
  506. // report error suite
  507. fn(errSuite);
  508. });
  509. } else {
  510. // there is no need calling other 'after each' hooks
  511. self.suite = orig;
  512. fn(errSuite);
  513. }
  514. }
  515. function next(err, errSuite) {
  516. // if we bail after first err
  517. if (self.failures && suite._bail) {
  518. tests = [];
  519. }
  520. if (self._abort) {
  521. return fn();
  522. }
  523. if (err) {
  524. return hookErr(err, errSuite, true);
  525. }
  526. // next test
  527. test = tests.shift();
  528. // all done
  529. if (!test) {
  530. return fn();
  531. }
  532. // grep
  533. var match = self._grep.test(test.fullTitle());
  534. if (self._invert) {
  535. match = !match;
  536. }
  537. if (!match) {
  538. // Run immediately only if we have defined a grep. When we
  539. // define a grep — It can cause maximum callstack error if
  540. // the grep is doing a large recursive loop by neglecting
  541. // all tests. The run immediately function also comes with
  542. // a performance cost. So we don't want to run immediately
  543. // if we run the whole test suite, because running the whole
  544. // test suite don't do any immediate recursive loops. Thus,
  545. // allowing a JS runtime to breathe.
  546. if (self._grep !== self._defaultGrep) {
  547. Runner.immediately(next);
  548. } else {
  549. next();
  550. }
  551. return;
  552. }
  553. if (test.isPending()) {
  554. if (self.forbidPending) {
  555. test.isPending = alwaysFalse;
  556. self.fail(test, new Error('Pending test forbidden'));
  557. delete test.isPending;
  558. } else {
  559. self.emit(constants.EVENT_TEST_PENDING, test);
  560. }
  561. self.emit(constants.EVENT_TEST_END, test);
  562. return next();
  563. }
  564. // execute test and hook(s)
  565. self.emit(constants.EVENT_TEST_BEGIN, (self.test = test));
  566. self.hookDown(HOOK_TYPE_BEFORE_EACH, function(err, errSuite) {
  567. if (test.isPending()) {
  568. if (self.forbidPending) {
  569. test.isPending = alwaysFalse;
  570. self.fail(test, new Error('Pending test forbidden'));
  571. delete test.isPending;
  572. } else {
  573. self.emit(constants.EVENT_TEST_PENDING, test);
  574. }
  575. self.emit(constants.EVENT_TEST_END, test);
  576. return next();
  577. }
  578. if (err) {
  579. return hookErr(err, errSuite, false);
  580. }
  581. self.currentRunnable = self.test;
  582. self.runTest(function(err) {
  583. test = self.test;
  584. if (err) {
  585. var retry = test.currentRetry();
  586. if (err instanceof Pending && self.forbidPending) {
  587. self.fail(test, new Error('Pending test forbidden'));
  588. } else if (err instanceof Pending) {
  589. test.pending = true;
  590. self.emit(constants.EVENT_TEST_PENDING, test);
  591. } else if (retry < test.retries()) {
  592. var clonedTest = test.clone();
  593. clonedTest.currentRetry(retry + 1);
  594. tests.unshift(clonedTest);
  595. self.emit(constants.EVENT_TEST_RETRY, test, err);
  596. // Early return + hook trigger so that it doesn't
  597. // increment the count wrong
  598. return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
  599. } else {
  600. self.fail(test, err);
  601. }
  602. self.emit(constants.EVENT_TEST_END, test);
  603. if (err instanceof Pending) {
  604. return next();
  605. }
  606. return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
  607. }
  608. test.state = STATE_PASSED;
  609. self.emit(constants.EVENT_TEST_PASS, test);
  610. self.emit(constants.EVENT_TEST_END, test);
  611. self.hookUp(HOOK_TYPE_AFTER_EACH, next);
  612. });
  613. });
  614. }
  615. this.next = next;
  616. this.hookErr = hookErr;
  617. next();
  618. };
  619. function alwaysFalse() {
  620. return false;
  621. }
  622. /**
  623. * Run the given `suite` and invoke the callback `fn()` when complete.
  624. *
  625. * @private
  626. * @param {Suite} suite
  627. * @param {Function} fn
  628. */
  629. Runner.prototype.runSuite = function(suite, fn) {
  630. var i = 0;
  631. var self = this;
  632. var total = this.grepTotal(suite);
  633. var afterAllHookCalled = false;
  634. debug('run suite %s', suite.fullTitle());
  635. if (!total || (self.failures && suite._bail)) {
  636. return fn();
  637. }
  638. this.emit(constants.EVENT_SUITE_BEGIN, (this.suite = suite));
  639. function next(errSuite) {
  640. if (errSuite) {
  641. // current suite failed on a hook from errSuite
  642. if (errSuite === suite) {
  643. // if errSuite is current suite
  644. // continue to the next sibling suite
  645. return done();
  646. }
  647. // errSuite is among the parents of current suite
  648. // stop execution of errSuite and all sub-suites
  649. return done(errSuite);
  650. }
  651. if (self._abort) {
  652. return done();
  653. }
  654. var curr = suite.suites[i++];
  655. if (!curr) {
  656. return done();
  657. }
  658. // Avoid grep neglecting large number of tests causing a
  659. // huge recursive loop and thus a maximum call stack error.
  660. // See comment in `this.runTests()` for more information.
  661. if (self._grep !== self._defaultGrep) {
  662. Runner.immediately(function() {
  663. self.runSuite(curr, next);
  664. });
  665. } else {
  666. self.runSuite(curr, next);
  667. }
  668. }
  669. function done(errSuite) {
  670. self.suite = suite;
  671. self.nextSuite = next;
  672. if (afterAllHookCalled) {
  673. fn(errSuite);
  674. } else {
  675. // mark that the afterAll block has been called once
  676. // and so can be skipped if there is an error in it.
  677. afterAllHookCalled = true;
  678. // remove reference to test
  679. delete self.test;
  680. self.hook(HOOK_TYPE_AFTER_ALL, function() {
  681. self.emit(constants.EVENT_SUITE_END, suite);
  682. fn(errSuite);
  683. });
  684. }
  685. }
  686. this.nextSuite = next;
  687. this.hook(HOOK_TYPE_BEFORE_ALL, function(err) {
  688. if (err) {
  689. return done();
  690. }
  691. self.runTests(suite, next);
  692. });
  693. };
  694. /**
  695. * Handle uncaught exceptions.
  696. *
  697. * @param {Error} err
  698. * @private
  699. */
  700. Runner.prototype.uncaught = function(err) {
  701. if (err) {
  702. debug('uncaught exception %O', err);
  703. } else {
  704. debug('uncaught undefined/falsy exception');
  705. err = createInvalidExceptionError(
  706. 'Caught falsy/undefined exception which would otherwise be uncaught. No stack trace found; try a debugger',
  707. err
  708. );
  709. }
  710. if (!isError(err)) {
  711. err = thrown2Error(err);
  712. }
  713. err.uncaught = true;
  714. var runnable = this.currentRunnable;
  715. if (!runnable) {
  716. runnable = new Runnable('Uncaught error outside test suite');
  717. runnable.parent = this.suite;
  718. if (this.started) {
  719. this.fail(runnable, err);
  720. } else {
  721. // Can't recover from this failure
  722. this.emit(constants.EVENT_RUN_BEGIN);
  723. this.fail(runnable, err);
  724. this.emit(constants.EVENT_RUN_END);
  725. }
  726. return;
  727. }
  728. runnable.clearTimeout();
  729. // Ignore errors if already failed or pending
  730. // See #3226
  731. if (runnable.isFailed() || runnable.isPending()) {
  732. return;
  733. }
  734. // we cannot recover gracefully if a Runnable has already passed
  735. // then fails asynchronously
  736. var alreadyPassed = runnable.isPassed();
  737. // this will change the state to "failed" regardless of the current value
  738. this.fail(runnable, err);
  739. if (!alreadyPassed) {
  740. // recover from test
  741. if (runnable.type === constants.EVENT_TEST_BEGIN) {
  742. this.emit(constants.EVENT_TEST_END, runnable);
  743. this.hookUp(HOOK_TYPE_AFTER_EACH, this.next);
  744. return;
  745. }
  746. debug(runnable);
  747. // recover from hooks
  748. var errSuite = this.suite;
  749. // XXX how about a less awful way to determine this?
  750. // if hook failure is in afterEach block
  751. if (runnable.fullTitle().indexOf('after each') > -1) {
  752. return this.hookErr(err, errSuite, true);
  753. }
  754. // if hook failure is in beforeEach block
  755. if (runnable.fullTitle().indexOf('before each') > -1) {
  756. return this.hookErr(err, errSuite, false);
  757. }
  758. // if hook failure is in after or before blocks
  759. return this.nextSuite(errSuite);
  760. }
  761. // bail
  762. this.emit(constants.EVENT_RUN_END);
  763. };
  764. /**
  765. * Run the root suite and invoke `fn(failures)`
  766. * on completion.
  767. *
  768. * @public
  769. * @memberof Runner
  770. * @param {Function} fn
  771. * @return {Runner} Runner instance.
  772. */
  773. Runner.prototype.run = function(fn) {
  774. var self = this;
  775. var rootSuite = this.suite;
  776. fn = fn || function() {};
  777. function uncaught(err) {
  778. self.uncaught(err);
  779. }
  780. function start() {
  781. // If there is an `only` filter
  782. if (rootSuite.hasOnly()) {
  783. rootSuite.filterOnly();
  784. }
  785. self.started = true;
  786. if (self._delay) {
  787. self.emit(constants.EVENT_DELAY_END);
  788. }
  789. self.emit(constants.EVENT_RUN_BEGIN);
  790. self.runSuite(rootSuite, function() {
  791. debug('finished running');
  792. self.emit(constants.EVENT_RUN_END);
  793. });
  794. }
  795. debug(constants.EVENT_RUN_BEGIN);
  796. // references cleanup to avoid memory leaks
  797. this.on(constants.EVENT_SUITE_END, function(suite) {
  798. suite.cleanReferences();
  799. });
  800. // callback
  801. this.on(constants.EVENT_RUN_END, function() {
  802. debug(constants.EVENT_RUN_END);
  803. process.removeListener('uncaughtException', uncaught);
  804. fn(self.failures);
  805. });
  806. // uncaught exception
  807. process.on('uncaughtException', uncaught);
  808. if (this._delay) {
  809. // for reporters, I guess.
  810. // might be nice to debounce some dots while we wait.
  811. this.emit(constants.EVENT_DELAY_BEGIN, rootSuite);
  812. rootSuite.once(EVENT_ROOT_SUITE_RUN, start);
  813. } else {
  814. start();
  815. }
  816. return this;
  817. };
  818. /**
  819. * Cleanly abort execution.
  820. *
  821. * @memberof Runner
  822. * @public
  823. * @return {Runner} Runner instance.
  824. */
  825. Runner.prototype.abort = function() {
  826. debug('aborting');
  827. this._abort = true;
  828. return this;
  829. };
  830. /**
  831. * Filter leaks with the given globals flagged as `ok`.
  832. *
  833. * @private
  834. * @param {Array} ok
  835. * @param {Array} globals
  836. * @return {Array}
  837. */
  838. function filterLeaks(ok, globals) {
  839. return globals.filter(function(key) {
  840. // Firefox and Chrome exposes iframes as index inside the window object
  841. if (/^\d+/.test(key)) {
  842. return false;
  843. }
  844. // in firefox
  845. // if runner runs in an iframe, this iframe's window.getInterface method
  846. // not init at first it is assigned in some seconds
  847. if (global.navigator && /^getInterface/.test(key)) {
  848. return false;
  849. }
  850. // an iframe could be approached by window[iframeIndex]
  851. // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak
  852. if (global.navigator && /^\d+/.test(key)) {
  853. return false;
  854. }
  855. // Opera and IE expose global variables for HTML element IDs (issue #243)
  856. if (/^mocha-/.test(key)) {
  857. return false;
  858. }
  859. var matched = ok.filter(function(ok) {
  860. if (~ok.indexOf('*')) {
  861. return key.indexOf(ok.split('*')[0]) === 0;
  862. }
  863. return key === ok;
  864. });
  865. return !matched.length && (!global.navigator || key !== 'onerror');
  866. });
  867. }
  868. /**
  869. * Check if argument is an instance of Error object or a duck-typed equivalent.
  870. *
  871. * @private
  872. * @param {Object} err - object to check
  873. * @param {string} err.message - error message
  874. * @returns {boolean}
  875. */
  876. function isError(err) {
  877. return err instanceof Error || (err && typeof err.message === 'string');
  878. }
  879. /**
  880. *
  881. * Converts thrown non-extensible type into proper Error.
  882. *
  883. * @private
  884. * @param {*} thrown - Non-extensible type thrown by code
  885. * @return {Error}
  886. */
  887. function thrown2Error(err) {
  888. return new Error(
  889. 'the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)'
  890. );
  891. }
  892. /**
  893. * Array of globals dependent on the environment.
  894. *
  895. * @return {Array}
  896. * @deprecated
  897. * @todo remove; long since unsupported
  898. * @private
  899. */
  900. function extraGlobals() {
  901. if (typeof process === 'object' && typeof process.version === 'string') {
  902. var parts = process.version.split('.');
  903. var nodeVersion = parts.reduce(function(a, v) {
  904. return (a << 8) | v;
  905. });
  906. // 'errno' was renamed to process._errno in v0.9.11.
  907. if (nodeVersion < 0x00090b) {
  908. return ['errno'];
  909. }
  910. }
  911. return [];
  912. }
  913. Runner.constants = constants;
  914. /**
  915. * Node.js' `EventEmitter`
  916. * @external EventEmitter
  917. * @see {@link https://nodejs.org/api/events.html#events_class_eventemitter}
  918. */