runTest.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = runTest;
  6. function _console() {
  7. const data = require('@jest/console');
  8. _console = function _console() {
  9. return data;
  10. };
  11. return data;
  12. }
  13. function _gracefulFs() {
  14. const data = _interopRequireDefault(require('graceful-fs'));
  15. _gracefulFs = function _gracefulFs() {
  16. return data;
  17. };
  18. return data;
  19. }
  20. function _jestUtil() {
  21. const data = require('jest-util');
  22. _jestUtil = function _jestUtil() {
  23. return data;
  24. };
  25. return data;
  26. }
  27. function _jestLeakDetector() {
  28. const data = _interopRequireDefault(require('jest-leak-detector'));
  29. _jestLeakDetector = function _jestLeakDetector() {
  30. return data;
  31. };
  32. return data;
  33. }
  34. function _jestConfig() {
  35. const data = require('jest-config');
  36. _jestConfig = function _jestConfig() {
  37. return data;
  38. };
  39. return data;
  40. }
  41. function docblock() {
  42. const data = _interopRequireWildcard(require('jest-docblock'));
  43. docblock = function docblock() {
  44. return data;
  45. };
  46. return data;
  47. }
  48. function _jestMessageUtil() {
  49. const data = require('jest-message-util');
  50. _jestMessageUtil = function _jestMessageUtil() {
  51. return data;
  52. };
  53. return data;
  54. }
  55. function _sourceMapSupport() {
  56. const data = _interopRequireDefault(require('source-map-support'));
  57. _sourceMapSupport = function _sourceMapSupport() {
  58. return data;
  59. };
  60. return data;
  61. }
  62. function _chalk() {
  63. const data = _interopRequireDefault(require('chalk'));
  64. _chalk = function _chalk() {
  65. return data;
  66. };
  67. return data;
  68. }
  69. function _interopRequireWildcard(obj) {
  70. if (obj && obj.__esModule) {
  71. return obj;
  72. } else {
  73. var newObj = {};
  74. if (obj != null) {
  75. for (var key in obj) {
  76. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  77. var desc =
  78. Object.defineProperty && Object.getOwnPropertyDescriptor
  79. ? Object.getOwnPropertyDescriptor(obj, key)
  80. : {};
  81. if (desc.get || desc.set) {
  82. Object.defineProperty(newObj, key, desc);
  83. } else {
  84. newObj[key] = obj[key];
  85. }
  86. }
  87. }
  88. }
  89. newObj.default = obj;
  90. return newObj;
  91. }
  92. }
  93. function _interopRequireDefault(obj) {
  94. return obj && obj.__esModule ? obj : {default: obj};
  95. }
  96. function _objectSpread(target) {
  97. for (var i = 1; i < arguments.length; i++) {
  98. var source = arguments[i] != null ? arguments[i] : {};
  99. var ownKeys = Object.keys(source);
  100. if (typeof Object.getOwnPropertySymbols === 'function') {
  101. ownKeys = ownKeys.concat(
  102. Object.getOwnPropertySymbols(source).filter(function(sym) {
  103. return Object.getOwnPropertyDescriptor(source, sym).enumerable;
  104. })
  105. );
  106. }
  107. ownKeys.forEach(function(key) {
  108. _defineProperty(target, key, source[key]);
  109. });
  110. }
  111. return target;
  112. }
  113. function _defineProperty(obj, key, value) {
  114. if (key in obj) {
  115. Object.defineProperty(obj, key, {
  116. value: value,
  117. enumerable: true,
  118. configurable: true,
  119. writable: true
  120. });
  121. } else {
  122. obj[key] = value;
  123. }
  124. return obj;
  125. }
  126. function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  127. try {
  128. var info = gen[key](arg);
  129. var value = info.value;
  130. } catch (error) {
  131. reject(error);
  132. return;
  133. }
  134. if (info.done) {
  135. resolve(value);
  136. } else {
  137. Promise.resolve(value).then(_next, _throw);
  138. }
  139. }
  140. function _asyncToGenerator(fn) {
  141. return function() {
  142. var self = this,
  143. args = arguments;
  144. return new Promise(function(resolve, reject) {
  145. var gen = fn.apply(self, args);
  146. function _next(value) {
  147. asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
  148. }
  149. function _throw(err) {
  150. asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
  151. }
  152. _next(undefined);
  153. });
  154. };
  155. }
  156. function freezeConsole(testConsole, config) {
  157. // @ts-ignore: `_log` is `private` - we should figure out some proper API here
  158. testConsole._log = function fakeConsolePush(_type, message) {
  159. const error = new (_jestUtil()).ErrorWithStack(
  160. `${_chalk().default.red(
  161. `${_chalk().default.bold(
  162. 'Cannot log after tests are done.'
  163. )} Did you forget to wait for something async in your test?`
  164. )}\nAttempted to log "${message}".`,
  165. fakeConsolePush
  166. );
  167. const formattedError = (0, _jestMessageUtil().formatExecError)(
  168. error,
  169. config,
  170. {
  171. noStackTrace: false
  172. },
  173. undefined,
  174. true
  175. );
  176. process.stderr.write('\n' + formattedError + '\n'); // TODO: set exit code in Jest 25
  177. // process.exitCode = 1;
  178. };
  179. } // Keeping the core of "runTest" as a separate function (as "runTestInternal")
  180. // is key to be able to detect memory leaks. Since all variables are local to
  181. // the function, when "runTestInternal" finishes its execution, they can all be
  182. // freed, UNLESS something else is leaking them (and that's why we can detect
  183. // the leak!).
  184. //
  185. // If we had all the code in a single function, we should manually nullify all
  186. // references to verify if there is a leak, which is not maintainable and error
  187. // prone. That's why "runTestInternal" CANNOT be inlined inside "runTest".
  188. function runTestInternal(_x, _x2, _x3, _x4, _x5) {
  189. return _runTestInternal.apply(this, arguments);
  190. }
  191. function _runTestInternal() {
  192. _runTestInternal = _asyncToGenerator(function*(
  193. path,
  194. globalConfig,
  195. config,
  196. resolver,
  197. context
  198. ) {
  199. const testSource = _gracefulFs().default.readFileSync(path, 'utf8');
  200. const docblockPragmas = docblock().parse(docblock().extract(testSource));
  201. const customEnvironment = docblockPragmas['jest-environment'];
  202. let testEnvironment = config.testEnvironment;
  203. if (customEnvironment) {
  204. if (Array.isArray(customEnvironment)) {
  205. throw new Error(
  206. `You can only define a single test environment through docblocks, got "${customEnvironment.join(
  207. ', '
  208. )}"`
  209. );
  210. }
  211. testEnvironment = (0, _jestConfig().getTestEnvironment)(
  212. _objectSpread({}, config, {
  213. testEnvironment: customEnvironment
  214. })
  215. );
  216. }
  217. const TestEnvironment = (0, _jestUtil().interopRequireDefault)(
  218. require(testEnvironment)
  219. ).default;
  220. const testFramework =
  221. process.env.JEST_CIRCUS === '1'
  222. ? require('jest-circus/runner') // eslint-disable-line import/no-extraneous-dependencies
  223. : require(config.testRunner);
  224. const Runtime = config.moduleLoader
  225. ? require(config.moduleLoader)
  226. : require('jest-runtime');
  227. let runtime = undefined;
  228. const consoleOut = globalConfig.useStderr ? process.stderr : process.stdout;
  229. const consoleFormatter = (type, message) =>
  230. (0, _console().getConsoleOutput)(
  231. config.cwd,
  232. !!globalConfig.verbose, // 4 = the console call is buried 4 stack frames deep
  233. _console().BufferedConsole.write(
  234. [],
  235. type,
  236. message,
  237. 4,
  238. runtime && runtime.getSourceMaps()
  239. )
  240. );
  241. let testConsole;
  242. if (globalConfig.silent) {
  243. testConsole = new (_console()).NullConsole(
  244. consoleOut,
  245. consoleOut,
  246. consoleFormatter
  247. );
  248. } else if (globalConfig.verbose) {
  249. testConsole = new (_console()).CustomConsole(
  250. consoleOut,
  251. consoleOut,
  252. consoleFormatter
  253. );
  254. } else {
  255. testConsole = new (_console()).BufferedConsole(
  256. () => runtime && runtime.getSourceMaps()
  257. );
  258. }
  259. const environment = new TestEnvironment(config, {
  260. console: testConsole,
  261. docblockPragmas,
  262. testPath: path
  263. });
  264. const leakDetector = config.detectLeaks
  265. ? new (_jestLeakDetector()).default(environment)
  266. : null;
  267. const cacheFS = {
  268. [path]: testSource
  269. };
  270. (0, _jestUtil().setGlobal)(environment.global, 'console', testConsole);
  271. runtime = new Runtime(config, environment, resolver, cacheFS, {
  272. changedFiles: context && context.changedFiles,
  273. collectCoverage: globalConfig.collectCoverage,
  274. collectCoverageFrom: globalConfig.collectCoverageFrom,
  275. collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom
  276. });
  277. const start = Date.now();
  278. const sourcemapOptions = {
  279. environment: 'node',
  280. handleUncaughtExceptions: false,
  281. retrieveSourceMap: source => {
  282. const sourceMaps = runtime && runtime.getSourceMaps();
  283. const sourceMapSource = sourceMaps && sourceMaps[source];
  284. if (sourceMapSource) {
  285. try {
  286. return {
  287. map: JSON.parse(
  288. _gracefulFs().default.readFileSync(sourceMapSource, 'utf8')
  289. ),
  290. url: source
  291. };
  292. } catch (e) {}
  293. }
  294. return null;
  295. }
  296. }; // For tests
  297. runtime
  298. .requireInternalModule(
  299. require.resolve('source-map-support'),
  300. 'source-map-support'
  301. )
  302. .install(sourcemapOptions); // For runtime errors
  303. _sourceMapSupport().default.install(sourcemapOptions);
  304. if (
  305. environment.global &&
  306. environment.global.process &&
  307. environment.global.process.exit
  308. ) {
  309. const realExit = environment.global.process.exit;
  310. environment.global.process.exit = function exit(...args) {
  311. const error = new (_jestUtil()).ErrorWithStack(
  312. `process.exit called with "${args.join(', ')}"`,
  313. exit
  314. );
  315. const formattedError = (0, _jestMessageUtil().formatExecError)(
  316. error,
  317. config,
  318. {
  319. noStackTrace: false
  320. },
  321. undefined,
  322. true
  323. );
  324. process.stderr.write(formattedError);
  325. return realExit(...args);
  326. };
  327. }
  328. try {
  329. yield environment.setup();
  330. let result;
  331. try {
  332. result = yield testFramework(
  333. globalConfig,
  334. config,
  335. environment,
  336. runtime,
  337. path
  338. );
  339. } catch (err) {
  340. // Access stack before uninstalling sourcemaps
  341. err.stack;
  342. throw err;
  343. }
  344. freezeConsole(testConsole, config);
  345. const testCount =
  346. result.numPassingTests +
  347. result.numFailingTests +
  348. result.numPendingTests +
  349. result.numTodoTests;
  350. result.perfStats = {
  351. end: Date.now(),
  352. start
  353. };
  354. result.testFilePath = path;
  355. result.console = testConsole.getBuffer();
  356. result.skipped = testCount === result.numPendingTests;
  357. result.displayName = config.displayName;
  358. const coverage = runtime.getAllCoverageInfoCopy();
  359. if (coverage) {
  360. const coverageKeys = Object.keys(coverage);
  361. if (coverageKeys.length) {
  362. result.coverage = coverage;
  363. result.sourceMaps = runtime.getSourceMapInfo(new Set(coverageKeys));
  364. }
  365. }
  366. if (globalConfig.logHeapUsage) {
  367. if (global.gc) {
  368. global.gc();
  369. }
  370. result.memoryUsage = process.memoryUsage().heapUsed;
  371. } // Delay the resolution to allow log messages to be output.
  372. return new Promise(resolve => {
  373. setImmediate(() =>
  374. resolve({
  375. leakDetector,
  376. result
  377. })
  378. );
  379. });
  380. } finally {
  381. yield environment.teardown();
  382. _sourceMapSupport().default.resetRetrieveHandlers();
  383. }
  384. });
  385. return _runTestInternal.apply(this, arguments);
  386. }
  387. function runTest(_x6, _x7, _x8, _x9, _x10) {
  388. return _runTest.apply(this, arguments);
  389. }
  390. function _runTest() {
  391. _runTest = _asyncToGenerator(function*(
  392. path,
  393. globalConfig,
  394. config,
  395. resolver,
  396. context
  397. ) {
  398. const _ref = yield runTestInternal(
  399. path,
  400. globalConfig,
  401. config,
  402. resolver,
  403. context
  404. ),
  405. leakDetector = _ref.leakDetector,
  406. result = _ref.result;
  407. if (leakDetector) {
  408. // We wanna allow a tiny but time to pass to allow last-minute cleanup
  409. yield new Promise(resolve => setTimeout(resolve, 100)); // Resolve leak detector, outside the "runTestInternal" closure.
  410. result.leaks = leakDetector.isLeaking();
  411. } else {
  412. result.leaks = false;
  413. }
  414. return result;
  415. });
  416. return _runTest.apply(this, arguments);
  417. }