index.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. 'use strict';
  2. function _exit() {
  3. const data = _interopRequireDefault(require('exit'));
  4. _exit = function _exit() {
  5. return data;
  6. };
  7. return data;
  8. }
  9. function _throat() {
  10. const data = _interopRequireDefault(require('throat'));
  11. _throat = function _throat() {
  12. return data;
  13. };
  14. return data;
  15. }
  16. function _jestWorker() {
  17. const data = _interopRequireDefault(require('jest-worker'));
  18. _jestWorker = function _jestWorker() {
  19. return data;
  20. };
  21. return data;
  22. }
  23. var _runTest = _interopRequireDefault(require('./runTest'));
  24. var _testWorker = require('./testWorker');
  25. function _interopRequireDefault(obj) {
  26. return obj && obj.__esModule ? obj : {default: obj};
  27. }
  28. function _objectSpread(target) {
  29. for (var i = 1; i < arguments.length; i++) {
  30. var source = arguments[i] != null ? arguments[i] : {};
  31. var ownKeys = Object.keys(source);
  32. if (typeof Object.getOwnPropertySymbols === 'function') {
  33. ownKeys = ownKeys.concat(
  34. Object.getOwnPropertySymbols(source).filter(function(sym) {
  35. return Object.getOwnPropertyDescriptor(source, sym).enumerable;
  36. })
  37. );
  38. }
  39. ownKeys.forEach(function(key) {
  40. _defineProperty(target, key, source[key]);
  41. });
  42. }
  43. return target;
  44. }
  45. function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  46. try {
  47. var info = gen[key](arg);
  48. var value = info.value;
  49. } catch (error) {
  50. reject(error);
  51. return;
  52. }
  53. if (info.done) {
  54. resolve(value);
  55. } else {
  56. Promise.resolve(value).then(_next, _throw);
  57. }
  58. }
  59. function _asyncToGenerator(fn) {
  60. return function() {
  61. var self = this,
  62. args = arguments;
  63. return new Promise(function(resolve, reject) {
  64. var gen = fn.apply(self, args);
  65. function _next(value) {
  66. asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
  67. }
  68. function _throw(err) {
  69. asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
  70. }
  71. _next(undefined);
  72. });
  73. };
  74. }
  75. function _defineProperty(obj, key, value) {
  76. if (key in obj) {
  77. Object.defineProperty(obj, key, {
  78. value: value,
  79. enumerable: true,
  80. configurable: true,
  81. writable: true
  82. });
  83. } else {
  84. obj[key] = value;
  85. }
  86. return obj;
  87. }
  88. const TEST_WORKER_PATH = require.resolve('./testWorker');
  89. /* eslint-disable-next-line no-redeclare */
  90. class TestRunner {
  91. constructor(globalConfig, context) {
  92. _defineProperty(this, '_globalConfig', void 0);
  93. _defineProperty(this, '_context', void 0);
  94. this._globalConfig = globalConfig;
  95. this._context = context || {};
  96. }
  97. runTests(tests, watcher, onStart, onResult, onFailure, options) {
  98. var _this = this;
  99. return _asyncToGenerator(function*() {
  100. return yield options.serial
  101. ? _this._createInBandTestRun(
  102. tests,
  103. watcher,
  104. onStart,
  105. onResult,
  106. onFailure
  107. )
  108. : _this._createParallelTestRun(
  109. tests,
  110. watcher,
  111. onStart,
  112. onResult,
  113. onFailure
  114. );
  115. })();
  116. }
  117. _createInBandTestRun(tests, watcher, onStart, onResult, onFailure) {
  118. var _this2 = this;
  119. return _asyncToGenerator(function*() {
  120. process.env.JEST_WORKER_ID = '1';
  121. const mutex = (0, _throat().default)(1);
  122. return tests.reduce(
  123. (promise, test) =>
  124. mutex(() =>
  125. promise
  126. .then(
  127. /*#__PURE__*/
  128. _asyncToGenerator(function*() {
  129. if (watcher.isInterrupted()) {
  130. throw new CancelRun();
  131. }
  132. yield onStart(test);
  133. return (0,
  134. _runTest.default)(test.path, _this2._globalConfig, test.context.config, test.context.resolver, _this2._context);
  135. })
  136. )
  137. .then(result => onResult(test, result))
  138. .catch(err => onFailure(test, err))
  139. ),
  140. Promise.resolve()
  141. );
  142. })();
  143. }
  144. _createParallelTestRun(tests, watcher, onStart, onResult, onFailure) {
  145. var _this3 = this;
  146. return _asyncToGenerator(function*() {
  147. const resolvers = new Map();
  148. var _iteratorNormalCompletion = true;
  149. var _didIteratorError = false;
  150. var _iteratorError = undefined;
  151. try {
  152. for (
  153. var _iterator = tests[Symbol.iterator](), _step;
  154. !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
  155. _iteratorNormalCompletion = true
  156. ) {
  157. const test = _step.value;
  158. if (!resolvers.has(test.context.config.name)) {
  159. resolvers.set(test.context.config.name, {
  160. config: test.context.config,
  161. serializableModuleMap: test.context.moduleMap.toJSON()
  162. });
  163. }
  164. }
  165. } catch (err) {
  166. _didIteratorError = true;
  167. _iteratorError = err;
  168. } finally {
  169. try {
  170. if (!_iteratorNormalCompletion && _iterator.return != null) {
  171. _iterator.return();
  172. }
  173. } finally {
  174. if (_didIteratorError) {
  175. throw _iteratorError;
  176. }
  177. }
  178. }
  179. const worker = new (_jestWorker()).default(TEST_WORKER_PATH, {
  180. exposedMethods: ['worker'],
  181. forkOptions: {
  182. stdio: 'pipe'
  183. },
  184. maxRetries: 3,
  185. numWorkers: _this3._globalConfig.maxWorkers,
  186. setupArgs: [
  187. {
  188. serializableResolvers: Array.from(resolvers.values())
  189. }
  190. ]
  191. });
  192. if (worker.getStdout()) worker.getStdout().pipe(process.stdout);
  193. if (worker.getStderr()) worker.getStderr().pipe(process.stderr);
  194. const mutex = (0, _throat().default)(_this3._globalConfig.maxWorkers); // Send test suites to workers continuously instead of all at once to track
  195. // the start time of individual tests.
  196. const runTestInWorker = test =>
  197. mutex(
  198. /*#__PURE__*/
  199. _asyncToGenerator(function*() {
  200. if (watcher.isInterrupted()) {
  201. return Promise.reject();
  202. }
  203. yield onStart(test);
  204. return worker.worker({
  205. config: test.context.config,
  206. context: _objectSpread({}, _this3._context, {
  207. changedFiles:
  208. _this3._context.changedFiles &&
  209. Array.from(_this3._context.changedFiles)
  210. }),
  211. globalConfig: _this3._globalConfig,
  212. path: test.path
  213. });
  214. })
  215. );
  216. const onError =
  217. /*#__PURE__*/
  218. (function() {
  219. var _ref3 = _asyncToGenerator(function*(err, test) {
  220. yield onFailure(test, err);
  221. if (err.type === 'ProcessTerminatedError') {
  222. console.error(
  223. 'A worker process has quit unexpectedly! ' +
  224. 'Most likely this is an initialization error.'
  225. );
  226. (0, _exit().default)(1);
  227. }
  228. });
  229. return function onError(_x, _x2) {
  230. return _ref3.apply(this, arguments);
  231. };
  232. })();
  233. const onInterrupt = new Promise((_, reject) => {
  234. watcher.on('change', state => {
  235. if (state.interrupted) {
  236. reject(new CancelRun());
  237. }
  238. });
  239. });
  240. const runAllTests = Promise.all(
  241. tests.map(test =>
  242. runTestInWorker(test)
  243. .then(testResult => onResult(test, testResult))
  244. .catch(error => onError(error, test))
  245. )
  246. );
  247. const cleanup = () => worker.end();
  248. return Promise.race([runAllTests, onInterrupt]).then(cleanup, cleanup);
  249. })();
  250. }
  251. }
  252. class CancelRun extends Error {
  253. constructor(message) {
  254. super(message);
  255. this.name = 'CancelRun';
  256. }
  257. }
  258. module.exports = TestRunner;