Dieses Repository beinhaltet HTML- und Javascript Code zur einer NotizenWebApp auf Basis von Web Storage. Zudem sind Mocha/Chai Tests im Browser enthalten. https://meinenotizen.netlify.app/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

runner.js 29KB

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