index.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. 'use strict';
  2. var _exit;
  3. function _load_exit() {
  4. return (_exit = _interopRequireDefault(require('exit')));
  5. }
  6. var _run_test;
  7. function _load_run_test() {
  8. return (_run_test = _interopRequireDefault(require('./run_test')));
  9. }
  10. var _throat;
  11. function _load_throat() {
  12. return (_throat = _interopRequireDefault(require('throat')));
  13. }
  14. var _jestWorker;
  15. function _load_jestWorker() {
  16. return (_jestWorker = _interopRequireDefault(require('jest-worker')));
  17. }
  18. function _interopRequireDefault(obj) {
  19. return obj && obj.__esModule ? obj : {default: obj};
  20. }
  21. function _asyncToGenerator(fn) {
  22. return function() {
  23. var gen = fn.apply(this, arguments);
  24. return new Promise(function(resolve, reject) {
  25. function step(key, arg) {
  26. try {
  27. var info = gen[key](arg);
  28. var value = info.value;
  29. } catch (error) {
  30. reject(error);
  31. return;
  32. }
  33. if (info.done) {
  34. resolve(value);
  35. } else {
  36. return Promise.resolve(value).then(
  37. function(value) {
  38. step('next', value);
  39. },
  40. function(err) {
  41. step('throw', err);
  42. }
  43. );
  44. }
  45. }
  46. return step('next');
  47. });
  48. };
  49. }
  50. /**
  51. * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  52. *
  53. * This source code is licensed under the MIT license found in the
  54. * LICENSE file in the root directory of this source tree.
  55. *
  56. *
  57. */
  58. const TEST_WORKER_PATH = require.resolve('./test_worker');
  59. class TestRunner {
  60. constructor(globalConfig) {
  61. this._globalConfig = globalConfig;
  62. }
  63. runTests(tests, watcher, onStart, onResult, onFailure, options) {
  64. var _this = this;
  65. return _asyncToGenerator(function*() {
  66. return yield options.serial
  67. ? _this._createInBandTestRun(
  68. tests,
  69. watcher,
  70. onStart,
  71. onResult,
  72. onFailure
  73. )
  74. : _this._createParallelTestRun(
  75. tests,
  76. watcher,
  77. onStart,
  78. onResult,
  79. onFailure
  80. );
  81. })();
  82. }
  83. _createInBandTestRun(tests, watcher, onStart, onResult, onFailure) {
  84. var _this2 = this;
  85. return _asyncToGenerator(function*() {
  86. process.env.JEST_WORKER_ID = '1';
  87. const mutex = (0, (_throat || _load_throat()).default)(1);
  88. return tests.reduce(function(promise, test) {
  89. return mutex(function() {
  90. return promise
  91. .then(
  92. _asyncToGenerator(function*() {
  93. if (watcher.isInterrupted()) {
  94. throw new CancelRun();
  95. }
  96. yield onStart(test);
  97. return (0,
  98. (_run_test || _load_run_test())
  99. .default)(test.path, _this2._globalConfig, test.context.config, test.context.resolver);
  100. })
  101. )
  102. .then(function(result) {
  103. return onResult(test, result);
  104. })
  105. .catch(function(err) {
  106. return onFailure(test, err);
  107. });
  108. });
  109. }, Promise.resolve());
  110. })();
  111. }
  112. _createParallelTestRun(tests, watcher, onStart, onResult, onFailure) {
  113. var _this3 = this;
  114. return _asyncToGenerator(function*() {
  115. // $FlowFixMe: class object is augmented with worker when instantiating.
  116. const worker = new (_jestWorker || _load_jestWorker()).default(
  117. TEST_WORKER_PATH,
  118. {
  119. exposedMethods: ['worker'],
  120. forkOptions: {stdio: 'inherit'},
  121. maxRetries: 3,
  122. numWorkers: _this3._globalConfig.maxWorkers
  123. }
  124. );
  125. const mutex = (0, (_throat || _load_throat()).default)(
  126. _this3._globalConfig.maxWorkers
  127. );
  128. // Send test suites to workers continuously instead of all at once to track
  129. // the start time of individual tests.
  130. const runTestInWorker = function(test) {
  131. return mutex(
  132. _asyncToGenerator(function*() {
  133. if (watcher.isInterrupted()) {
  134. return Promise.reject();
  135. }
  136. yield onStart(test);
  137. return worker.worker({
  138. config: test.context.config,
  139. globalConfig: _this3._globalConfig,
  140. path: test.path,
  141. rawModuleMap: watcher.isWatchMode()
  142. ? test.context.moduleMap.getRawModuleMap()
  143. : null
  144. });
  145. })
  146. );
  147. };
  148. const onError = (() => {
  149. var _ref3 = _asyncToGenerator(function*(err, test) {
  150. yield onFailure(test, err);
  151. if (err.type === 'ProcessTerminatedError') {
  152. console.error(
  153. 'A worker process has quit unexpectedly! ' +
  154. 'Most likely this is an initialization error.'
  155. );
  156. (0, (_exit || _load_exit()).default)(1);
  157. }
  158. });
  159. return function onError(_x, _x2) {
  160. return _ref3.apply(this, arguments);
  161. };
  162. })();
  163. const onInterrupt = new Promise(function(_, reject) {
  164. watcher.on('change', function(state) {
  165. if (state.interrupted) {
  166. reject(new CancelRun());
  167. }
  168. });
  169. });
  170. const runAllTests = Promise.all(
  171. tests.map(function(test) {
  172. return runTestInWorker(test)
  173. .then(function(testResult) {
  174. return onResult(test, testResult);
  175. })
  176. .catch(function(error) {
  177. return onError(error, test);
  178. });
  179. })
  180. );
  181. const cleanup = function() {
  182. return worker.end();
  183. };
  184. return Promise.race([runAllTests, onInterrupt]).then(cleanup, cleanup);
  185. })();
  186. }
  187. }
  188. class CancelRun extends Error {
  189. constructor(message) {
  190. super(message);
  191. this.name = 'CancelRun';
  192. }
  193. }
  194. module.exports = TestRunner;