runner.js 35 KB

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