web 3d图形渲染器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

319 lines
8.2 KiB

  1. 'use strict';
  2. function _chalk() {
  3. const data = _interopRequireDefault(require('chalk'));
  4. _chalk = function () {
  5. return data;
  6. };
  7. return data;
  8. }
  9. function _emittery() {
  10. const data = _interopRequireDefault(require('emittery'));
  11. _emittery = function () {
  12. return data;
  13. };
  14. return data;
  15. }
  16. function _exit() {
  17. const data = _interopRequireDefault(require('exit'));
  18. _exit = function () {
  19. return data;
  20. };
  21. return data;
  22. }
  23. function _throat() {
  24. const data = _interopRequireDefault(require('throat'));
  25. _throat = function () {
  26. return data;
  27. };
  28. return data;
  29. }
  30. function _jestUtil() {
  31. const data = require('jest-util');
  32. _jestUtil = function () {
  33. return data;
  34. };
  35. return data;
  36. }
  37. function _jestWorker() {
  38. const data = _interopRequireDefault(require('jest-worker'));
  39. _jestWorker = function () {
  40. return data;
  41. };
  42. return data;
  43. }
  44. var _runTest = _interopRequireDefault(require('./runTest'));
  45. function _interopRequireDefault(obj) {
  46. return obj && obj.__esModule ? obj : {default: obj};
  47. }
  48. function _defineProperty(obj, key, value) {
  49. if (key in obj) {
  50. Object.defineProperty(obj, key, {
  51. value: value,
  52. enumerable: true,
  53. configurable: true,
  54. writable: true
  55. });
  56. } else {
  57. obj[key] = value;
  58. }
  59. return obj;
  60. }
  61. const TEST_WORKER_PATH = require.resolve('./testWorker');
  62. class TestRunner {
  63. constructor(globalConfig, context) {
  64. _defineProperty(this, '_globalConfig', void 0);
  65. _defineProperty(this, '_context', void 0);
  66. _defineProperty(this, 'eventEmitter', new (_emittery().default.Typed)());
  67. _defineProperty(
  68. this,
  69. '__PRIVATE_UNSTABLE_API_supportsEventEmitters__',
  70. true
  71. );
  72. _defineProperty(this, 'isSerial', void 0);
  73. _defineProperty(this, 'on', this.eventEmitter.on.bind(this.eventEmitter));
  74. this._globalConfig = globalConfig;
  75. this._context = context || {};
  76. }
  77. async runTests(tests, watcher, onStart, onResult, onFailure, options) {
  78. return await (options.serial
  79. ? this._createInBandTestRun(tests, watcher, onStart, onResult, onFailure)
  80. : this._createParallelTestRun(
  81. tests,
  82. watcher,
  83. onStart,
  84. onResult,
  85. onFailure
  86. ));
  87. }
  88. async _createInBandTestRun(tests, watcher, onStart, onResult, onFailure) {
  89. process.env.JEST_WORKER_ID = '1';
  90. const mutex = (0, _throat().default)(1);
  91. return tests.reduce(
  92. (promise, test) =>
  93. mutex(() =>
  94. promise
  95. .then(async () => {
  96. if (watcher.isInterrupted()) {
  97. throw new CancelRun();
  98. }
  99. let sendMessageToJest; // Remove `if(onStart)` in Jest 27
  100. if (onStart) {
  101. await onStart(test);
  102. return (0, _runTest.default)(
  103. test.path,
  104. this._globalConfig,
  105. test.context.config,
  106. test.context.resolver,
  107. this._context,
  108. undefined
  109. );
  110. } else {
  111. // `deepCyclicCopy` used here to avoid mem-leak
  112. sendMessageToJest = (eventName, args) =>
  113. this.eventEmitter.emit(
  114. eventName,
  115. (0, _jestUtil().deepCyclicCopy)(args, {
  116. keepPrototype: false
  117. })
  118. );
  119. await this.eventEmitter.emit('test-file-start', [test]);
  120. return (0, _runTest.default)(
  121. test.path,
  122. this._globalConfig,
  123. test.context.config,
  124. test.context.resolver,
  125. this._context,
  126. sendMessageToJest
  127. );
  128. }
  129. })
  130. .then(result => {
  131. if (onResult) {
  132. return onResult(test, result);
  133. } else {
  134. return this.eventEmitter.emit('test-file-success', [
  135. test,
  136. result
  137. ]);
  138. }
  139. })
  140. .catch(err => {
  141. if (onFailure) {
  142. return onFailure(test, err);
  143. } else {
  144. return this.eventEmitter.emit('test-file-failure', [test, err]);
  145. }
  146. })
  147. ),
  148. Promise.resolve()
  149. );
  150. }
  151. async _createParallelTestRun(tests, watcher, onStart, onResult, onFailure) {
  152. const resolvers = new Map();
  153. for (const test of tests) {
  154. if (!resolvers.has(test.context.config.name)) {
  155. resolvers.set(test.context.config.name, {
  156. config: test.context.config,
  157. serializableModuleMap: test.context.moduleMap.toJSON()
  158. });
  159. }
  160. }
  161. const worker = new (_jestWorker().default)(TEST_WORKER_PATH, {
  162. exposedMethods: ['worker'],
  163. forkOptions: {
  164. stdio: 'pipe'
  165. },
  166. maxRetries: 3,
  167. numWorkers: this._globalConfig.maxWorkers,
  168. setupArgs: [
  169. {
  170. serializableResolvers: Array.from(resolvers.values())
  171. }
  172. ]
  173. });
  174. if (worker.getStdout()) worker.getStdout().pipe(process.stdout);
  175. if (worker.getStderr()) worker.getStderr().pipe(process.stderr);
  176. const mutex = (0, _throat().default)(this._globalConfig.maxWorkers); // Send test suites to workers continuously instead of all at once to track
  177. // the start time of individual tests.
  178. const runTestInWorker = test =>
  179. mutex(async () => {
  180. if (watcher.isInterrupted()) {
  181. return Promise.reject();
  182. } // Remove `if(onStart)` in Jest 27
  183. if (onStart) {
  184. await onStart(test);
  185. } else {
  186. await this.eventEmitter.emit('test-file-start', [test]);
  187. }
  188. const promise = worker.worker({
  189. config: test.context.config,
  190. context: {
  191. ...this._context,
  192. changedFiles:
  193. this._context.changedFiles &&
  194. Array.from(this._context.changedFiles),
  195. sourcesRelatedToTestsInChangedFiles:
  196. this._context.sourcesRelatedToTestsInChangedFiles &&
  197. Array.from(this._context.sourcesRelatedToTestsInChangedFiles)
  198. },
  199. globalConfig: this._globalConfig,
  200. path: test.path
  201. });
  202. if (promise.UNSTABLE_onCustomMessage) {
  203. // TODO: Get appropriate type for `onCustomMessage`
  204. promise.UNSTABLE_onCustomMessage(([event, payload]) => {
  205. this.eventEmitter.emit(event, payload);
  206. });
  207. }
  208. return promise;
  209. });
  210. const onError = async (err, test) => {
  211. // Remove `if(onFailure)` in Jest 27
  212. if (onFailure) {
  213. await onFailure(test, err);
  214. } else {
  215. await this.eventEmitter.emit('test-file-failure', [test, err]);
  216. }
  217. if (err.type === 'ProcessTerminatedError') {
  218. console.error(
  219. 'A worker process has quit unexpectedly! ' +
  220. 'Most likely this is an initialization error.'
  221. );
  222. (0, _exit().default)(1);
  223. }
  224. };
  225. const onInterrupt = new Promise((_, reject) => {
  226. watcher.on('change', state => {
  227. if (state.interrupted) {
  228. reject(new CancelRun());
  229. }
  230. });
  231. });
  232. const runAllTests = Promise.all(
  233. tests.map(test =>
  234. runTestInWorker(test)
  235. .then(result => {
  236. if (onResult) {
  237. return onResult(test, result);
  238. } else {
  239. return this.eventEmitter.emit('test-file-success', [
  240. test,
  241. result
  242. ]);
  243. }
  244. })
  245. .catch(error => onError(error, test))
  246. )
  247. );
  248. const cleanup = async () => {
  249. const {forceExited} = await worker.end();
  250. if (forceExited) {
  251. console.error(
  252. _chalk().default.yellow(
  253. 'A worker process has failed to exit gracefully and has been force exited. ' +
  254. 'This is likely caused by tests leaking due to improper teardown. ' +
  255. 'Try running with --detectOpenHandles to find leaks.'
  256. )
  257. );
  258. }
  259. };
  260. return Promise.race([runAllTests, onInterrupt]).then(cleanup, cleanup);
  261. }
  262. }
  263. class CancelRun extends Error {
  264. constructor(message) {
  265. super(message);
  266. this.name = 'CancelRun';
  267. }
  268. }
  269. module.exports = TestRunner;