index.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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) { return obj && obj.__esModule ? obj : { default: obj }; }
  19. function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /**
  20. * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  21. *
  22. * This source code is licensed under the MIT license found in the
  23. * LICENSE file in the root directory of this source tree.
  24. *
  25. *
  26. */
  27. const TEST_WORKER_PATH = require.resolve('./test_worker');
  28. class TestRunner {
  29. constructor(globalConfig) {
  30. this._globalConfig = globalConfig;
  31. }
  32. runTests(tests, watcher, onStart, onResult, onFailure, options) {
  33. var _this = this;
  34. return _asyncToGenerator(function* () {
  35. return yield options.serial ? _this._createInBandTestRun(tests, watcher, onStart, onResult, onFailure) : _this._createParallelTestRun(tests, watcher, onStart, onResult, onFailure);
  36. })();
  37. }
  38. _createInBandTestRun(tests, watcher, onStart, onResult, onFailure) {
  39. var _this2 = this;
  40. return _asyncToGenerator(function* () {
  41. const mutex = (0, (_throat || _load_throat()).default)(1);
  42. return tests.reduce(function (promise, test) {
  43. return mutex(function () {
  44. return promise.then(_asyncToGenerator(function* () {
  45. if (watcher.isInterrupted()) {
  46. throw new CancelRun();
  47. }
  48. yield onStart(test);
  49. return (0, (_run_test || _load_run_test()).default)(test.path, _this2._globalConfig, test.context.config, test.context.resolver);
  50. })).then(function (result) {
  51. return onResult(test, result);
  52. }).catch(function (err) {
  53. return onFailure(test, err);
  54. });
  55. });
  56. }, Promise.resolve());
  57. })();
  58. }
  59. _createParallelTestRun(tests, watcher, onStart, onResult, onFailure) {
  60. var _this3 = this;
  61. return _asyncToGenerator(function* () {
  62. // $FlowFixMe: class object is augmented with worker when instantiating.
  63. const worker = new (_jestWorker || _load_jestWorker()).default(TEST_WORKER_PATH, {
  64. exposedMethods: ['worker'],
  65. forkOptions: { stdio: 'inherit' },
  66. maxRetries: 3,
  67. numWorkers: _this3._globalConfig.maxWorkers
  68. });
  69. const mutex = (0, (_throat || _load_throat()).default)(_this3._globalConfig.maxWorkers);
  70. // Send test suites to workers continuously instead of all at once to track
  71. // the start time of individual tests.
  72. const runTestInWorker = function (test) {
  73. return mutex(_asyncToGenerator(function* () {
  74. if (watcher.isInterrupted()) {
  75. return Promise.reject();
  76. }
  77. yield onStart(test);
  78. return worker.worker({
  79. config: test.context.config,
  80. globalConfig: _this3._globalConfig,
  81. path: test.path,
  82. rawModuleMap: watcher.isWatchMode() ? test.context.moduleMap.getRawModuleMap() : null
  83. });
  84. }));
  85. };
  86. const onError = (() => {
  87. var _ref3 = _asyncToGenerator(function* (err, test) {
  88. yield onFailure(test, err);
  89. if (err.type === 'ProcessTerminatedError') {
  90. console.error('A worker process has quit unexpectedly! ' + 'Most likely this is an initialization error.');
  91. (0, (_exit || _load_exit()).default)(1);
  92. }
  93. });
  94. return function onError(_x, _x2) {
  95. return _ref3.apply(this, arguments);
  96. };
  97. })();
  98. const onInterrupt = new Promise(function (_, reject) {
  99. watcher.on('change', function (state) {
  100. if (state.interrupted) {
  101. reject(new CancelRun());
  102. }
  103. });
  104. });
  105. const runAllTests = Promise.all(tests.map(function (test) {
  106. return runTestInWorker(test).then(function (testResult) {
  107. return onResult(test, testResult);
  108. }).catch(function (error) {
  109. return onError(error, test);
  110. });
  111. }));
  112. const cleanup = function () {
  113. return worker.end();
  114. };
  115. return Promise.race([runAllTests, onInterrupt]).then(cleanup, cleanup);
  116. })();
  117. }
  118. }
  119. class CancelRun extends Error {
  120. constructor(message) {
  121. super(message);
  122. this.name = 'CancelRun';
  123. }
  124. }
  125. module.exports = TestRunner;