299 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| function _exit() {
 | |
|   const data = _interopRequireDefault(require('exit'));
 | |
| 
 | |
|   _exit = function _exit() {
 | |
|     return data;
 | |
|   };
 | |
| 
 | |
|   return data;
 | |
| }
 | |
| 
 | |
| function _throat() {
 | |
|   const data = _interopRequireDefault(require('throat'));
 | |
| 
 | |
|   _throat = function _throat() {
 | |
|     return data;
 | |
|   };
 | |
| 
 | |
|   return data;
 | |
| }
 | |
| 
 | |
| function _jestWorker() {
 | |
|   const data = _interopRequireDefault(require('jest-worker'));
 | |
| 
 | |
|   _jestWorker = function _jestWorker() {
 | |
|     return data;
 | |
|   };
 | |
| 
 | |
|   return data;
 | |
| }
 | |
| 
 | |
| var _runTest = _interopRequireDefault(require('./runTest'));
 | |
| 
 | |
| var _testWorker = require('./testWorker');
 | |
| 
 | |
| function _interopRequireDefault(obj) {
 | |
|   return obj && obj.__esModule ? obj : {default: obj};
 | |
| }
 | |
| 
 | |
| function _objectSpread(target) {
 | |
|   for (var i = 1; i < arguments.length; i++) {
 | |
|     var source = arguments[i] != null ? arguments[i] : {};
 | |
|     var ownKeys = Object.keys(source);
 | |
|     if (typeof Object.getOwnPropertySymbols === 'function') {
 | |
|       ownKeys = ownKeys.concat(
 | |
|         Object.getOwnPropertySymbols(source).filter(function(sym) {
 | |
|           return Object.getOwnPropertyDescriptor(source, sym).enumerable;
 | |
|         })
 | |
|       );
 | |
|     }
 | |
|     ownKeys.forEach(function(key) {
 | |
|       _defineProperty(target, key, source[key]);
 | |
|     });
 | |
|   }
 | |
|   return target;
 | |
| }
 | |
| 
 | |
| function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
 | |
|   try {
 | |
|     var info = gen[key](arg);
 | |
|     var value = info.value;
 | |
|   } catch (error) {
 | |
|     reject(error);
 | |
|     return;
 | |
|   }
 | |
|   if (info.done) {
 | |
|     resolve(value);
 | |
|   } else {
 | |
|     Promise.resolve(value).then(_next, _throw);
 | |
|   }
 | |
| }
 | |
| 
 | |
| function _asyncToGenerator(fn) {
 | |
|   return function() {
 | |
|     var self = this,
 | |
|       args = arguments;
 | |
|     return new Promise(function(resolve, reject) {
 | |
|       var gen = fn.apply(self, args);
 | |
|       function _next(value) {
 | |
|         asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
 | |
|       }
 | |
|       function _throw(err) {
 | |
|         asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
 | |
|       }
 | |
|       _next(undefined);
 | |
|     });
 | |
|   };
 | |
| }
 | |
| 
 | |
| function _defineProperty(obj, key, value) {
 | |
|   if (key in obj) {
 | |
|     Object.defineProperty(obj, key, {
 | |
|       value: value,
 | |
|       enumerable: true,
 | |
|       configurable: true,
 | |
|       writable: true
 | |
|     });
 | |
|   } else {
 | |
|     obj[key] = value;
 | |
|   }
 | |
|   return obj;
 | |
| }
 | |
| 
 | |
| const TEST_WORKER_PATH = require.resolve('./testWorker');
 | |
| 
 | |
| /* eslint-disable-next-line no-redeclare */
 | |
| class TestRunner {
 | |
|   constructor(globalConfig, context) {
 | |
|     _defineProperty(this, '_globalConfig', void 0);
 | |
| 
 | |
|     _defineProperty(this, '_context', void 0);
 | |
| 
 | |
|     this._globalConfig = globalConfig;
 | |
|     this._context = context || {};
 | |
|   }
 | |
| 
 | |
|   runTests(tests, watcher, onStart, onResult, onFailure, options) {
 | |
|     var _this = this;
 | |
| 
 | |
|     return _asyncToGenerator(function*() {
 | |
|       return yield options.serial
 | |
|         ? _this._createInBandTestRun(
 | |
|             tests,
 | |
|             watcher,
 | |
|             onStart,
 | |
|             onResult,
 | |
|             onFailure
 | |
|           )
 | |
|         : _this._createParallelTestRun(
 | |
|             tests,
 | |
|             watcher,
 | |
|             onStart,
 | |
|             onResult,
 | |
|             onFailure
 | |
|           );
 | |
|     })();
 | |
|   }
 | |
| 
 | |
|   _createInBandTestRun(tests, watcher, onStart, onResult, onFailure) {
 | |
|     var _this2 = this;
 | |
| 
 | |
|     return _asyncToGenerator(function*() {
 | |
|       process.env.JEST_WORKER_ID = '1';
 | |
|       const mutex = (0, _throat().default)(1);
 | |
|       return tests.reduce(
 | |
|         (promise, test) =>
 | |
|           mutex(() =>
 | |
|             promise
 | |
|               .then(
 | |
|                 /*#__PURE__*/
 | |
|                 _asyncToGenerator(function*() {
 | |
|                   if (watcher.isInterrupted()) {
 | |
|                     throw new CancelRun();
 | |
|                   }
 | |
| 
 | |
|                   yield onStart(test);
 | |
|                   return (0,
 | |
|                   _runTest.default)(test.path, _this2._globalConfig, test.context.config, test.context.resolver, _this2._context);
 | |
|                 })
 | |
|               )
 | |
|               .then(result => onResult(test, result))
 | |
|               .catch(err => onFailure(test, err))
 | |
|           ),
 | |
|         Promise.resolve()
 | |
|       );
 | |
|     })();
 | |
|   }
 | |
| 
 | |
|   _createParallelTestRun(tests, watcher, onStart, onResult, onFailure) {
 | |
|     var _this3 = this;
 | |
| 
 | |
|     return _asyncToGenerator(function*() {
 | |
|       const resolvers = new Map();
 | |
|       var _iteratorNormalCompletion = true;
 | |
|       var _didIteratorError = false;
 | |
|       var _iteratorError = undefined;
 | |
| 
 | |
|       try {
 | |
|         for (
 | |
|           var _iterator = tests[Symbol.iterator](), _step;
 | |
|           !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
 | |
|           _iteratorNormalCompletion = true
 | |
|         ) {
 | |
|           const test = _step.value;
 | |
| 
 | |
|           if (!resolvers.has(test.context.config.name)) {
 | |
|             resolvers.set(test.context.config.name, {
 | |
|               config: test.context.config,
 | |
|               serializableModuleMap: test.context.moduleMap.toJSON()
 | |
|             });
 | |
|           }
 | |
|         }
 | |
|       } catch (err) {
 | |
|         _didIteratorError = true;
 | |
|         _iteratorError = err;
 | |
|       } finally {
 | |
|         try {
 | |
|           if (!_iteratorNormalCompletion && _iterator.return != null) {
 | |
|             _iterator.return();
 | |
|           }
 | |
|         } finally {
 | |
|           if (_didIteratorError) {
 | |
|             throw _iteratorError;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       const worker = new (_jestWorker()).default(TEST_WORKER_PATH, {
 | |
|         exposedMethods: ['worker'],
 | |
|         forkOptions: {
 | |
|           stdio: 'pipe'
 | |
|         },
 | |
|         maxRetries: 3,
 | |
|         numWorkers: _this3._globalConfig.maxWorkers,
 | |
|         setupArgs: [
 | |
|           {
 | |
|             serializableResolvers: Array.from(resolvers.values())
 | |
|           }
 | |
|         ]
 | |
|       });
 | |
|       if (worker.getStdout()) worker.getStdout().pipe(process.stdout);
 | |
|       if (worker.getStderr()) worker.getStderr().pipe(process.stderr);
 | |
|       const mutex = (0, _throat().default)(_this3._globalConfig.maxWorkers); // Send test suites to workers continuously instead of all at once to track
 | |
|       // the start time of individual tests.
 | |
| 
 | |
|       const runTestInWorker = test =>
 | |
|         mutex(
 | |
|           /*#__PURE__*/
 | |
|           _asyncToGenerator(function*() {
 | |
|             if (watcher.isInterrupted()) {
 | |
|               return Promise.reject();
 | |
|             }
 | |
| 
 | |
|             yield onStart(test);
 | |
|             return worker.worker({
 | |
|               config: test.context.config,
 | |
|               context: _objectSpread({}, _this3._context, {
 | |
|                 changedFiles:
 | |
|                   _this3._context.changedFiles &&
 | |
|                   Array.from(_this3._context.changedFiles)
 | |
|               }),
 | |
|               globalConfig: _this3._globalConfig,
 | |
|               path: test.path
 | |
|             });
 | |
|           })
 | |
|         );
 | |
| 
 | |
|       const onError =
 | |
|         /*#__PURE__*/
 | |
|         (function() {
 | |
|           var _ref3 = _asyncToGenerator(function*(err, test) {
 | |
|             yield onFailure(test, err);
 | |
| 
 | |
|             if (err.type === 'ProcessTerminatedError') {
 | |
|               console.error(
 | |
|                 'A worker process has quit unexpectedly! ' +
 | |
|                   'Most likely this is an initialization error.'
 | |
|               );
 | |
|               (0, _exit().default)(1);
 | |
|             }
 | |
|           });
 | |
| 
 | |
|           return function onError(_x, _x2) {
 | |
|             return _ref3.apply(this, arguments);
 | |
|           };
 | |
|         })();
 | |
| 
 | |
|       const onInterrupt = new Promise((_, reject) => {
 | |
|         watcher.on('change', state => {
 | |
|           if (state.interrupted) {
 | |
|             reject(new CancelRun());
 | |
|           }
 | |
|         });
 | |
|       });
 | |
|       const runAllTests = Promise.all(
 | |
|         tests.map(test =>
 | |
|           runTestInWorker(test)
 | |
|             .then(testResult => onResult(test, testResult))
 | |
|             .catch(error => onError(error, test))
 | |
|         )
 | |
|       );
 | |
| 
 | |
|       const cleanup = () => worker.end();
 | |
| 
 | |
|       return Promise.race([runAllTests, onInterrupt]).then(cleanup, cleanup);
 | |
|     })();
 | |
|   }
 | |
| }
 | |
| 
 | |
| class CancelRun extends Error {
 | |
|   constructor(message) {
 | |
|     super(message);
 | |
|     this.name = 'CancelRun';
 | |
|   }
 | |
| }
 | |
| 
 | |
| module.exports = TestRunner;
 |