run.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _async_hooks = require('async_hooks');
  7. var _pLimit = _interopRequireDefault(require('p-limit'));
  8. var _expect = require('@jest/expect');
  9. var _jestUtil = require('jest-util');
  10. var _shuffleArray = _interopRequireWildcard(require('./shuffleArray'));
  11. var _state = require('./state');
  12. var _types = require('./types');
  13. var _utils = require('./utils');
  14. function _getRequireWildcardCache(nodeInterop) {
  15. if (typeof WeakMap !== 'function') return null;
  16. var cacheBabelInterop = new WeakMap();
  17. var cacheNodeInterop = new WeakMap();
  18. return (_getRequireWildcardCache = function (nodeInterop) {
  19. return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
  20. })(nodeInterop);
  21. }
  22. function _interopRequireWildcard(obj, nodeInterop) {
  23. if (!nodeInterop && obj && obj.__esModule) {
  24. return obj;
  25. }
  26. if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
  27. return {default: obj};
  28. }
  29. var cache = _getRequireWildcardCache(nodeInterop);
  30. if (cache && cache.has(obj)) {
  31. return cache.get(obj);
  32. }
  33. var newObj = {};
  34. var hasPropertyDescriptor =
  35. Object.defineProperty && Object.getOwnPropertyDescriptor;
  36. for (var key in obj) {
  37. if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
  38. var desc = hasPropertyDescriptor
  39. ? Object.getOwnPropertyDescriptor(obj, key)
  40. : null;
  41. if (desc && (desc.get || desc.set)) {
  42. Object.defineProperty(newObj, key, desc);
  43. } else {
  44. newObj[key] = obj[key];
  45. }
  46. }
  47. }
  48. newObj.default = obj;
  49. if (cache) {
  50. cache.set(obj, newObj);
  51. }
  52. return newObj;
  53. }
  54. function _interopRequireDefault(obj) {
  55. return obj && obj.__esModule ? obj : {default: obj};
  56. }
  57. /**
  58. * Copyright (c) Meta Platforms, Inc. and affiliates.
  59. *
  60. * This source code is licensed under the MIT license found in the
  61. * LICENSE file in the root directory of this source tree.
  62. */
  63. const run = async () => {
  64. const {rootDescribeBlock, seed, randomize} = (0, _state.getState)();
  65. const rng = randomize ? (0, _shuffleArray.rngBuilder)(seed) : undefined;
  66. await (0, _state.dispatch)({
  67. name: 'run_start'
  68. });
  69. await _runTestsForDescribeBlock(rootDescribeBlock, rng, true);
  70. await (0, _state.dispatch)({
  71. name: 'run_finish'
  72. });
  73. return (0, _utils.makeRunResult)(
  74. (0, _state.getState)().rootDescribeBlock,
  75. (0, _state.getState)().unhandledErrors
  76. );
  77. };
  78. const _runTestsForDescribeBlock = async (
  79. describeBlock,
  80. rng,
  81. isRootBlock = false
  82. ) => {
  83. await (0, _state.dispatch)({
  84. describeBlock,
  85. name: 'run_describe_start'
  86. });
  87. const {beforeAll, afterAll} = (0, _utils.getAllHooksForDescribe)(
  88. describeBlock
  89. );
  90. const isSkipped = describeBlock.mode === 'skip';
  91. if (!isSkipped) {
  92. for (const hook of beforeAll) {
  93. await _callCircusHook({
  94. describeBlock,
  95. hook
  96. });
  97. }
  98. }
  99. if (isRootBlock) {
  100. const concurrentTests = collectConcurrentTests(describeBlock);
  101. if (concurrentTests.length > 0) {
  102. startTestsConcurrently(concurrentTests);
  103. }
  104. }
  105. // Tests that fail and are retried we run after other tests
  106. // eslint-disable-next-line no-restricted-globals
  107. const retryTimes = parseInt(global[_types.RETRY_TIMES], 10) || 0;
  108. const deferredRetryTests = [];
  109. if (rng) {
  110. describeBlock.children = (0, _shuffleArray.default)(
  111. describeBlock.children,
  112. rng
  113. );
  114. }
  115. for (const child of describeBlock.children) {
  116. switch (child.type) {
  117. case 'describeBlock': {
  118. await _runTestsForDescribeBlock(child, rng);
  119. break;
  120. }
  121. case 'test': {
  122. const hasErrorsBeforeTestRun = child.errors.length > 0;
  123. await _runTest(child, isSkipped);
  124. if (
  125. hasErrorsBeforeTestRun === false &&
  126. retryTimes > 0 &&
  127. child.errors.length > 0
  128. ) {
  129. deferredRetryTests.push(child);
  130. }
  131. break;
  132. }
  133. }
  134. }
  135. // Re-run failed tests n-times if configured
  136. for (const test of deferredRetryTests) {
  137. let numRetriesAvailable = retryTimes;
  138. while (numRetriesAvailable > 0 && test.errors.length > 0) {
  139. // Clear errors so retries occur
  140. await (0, _state.dispatch)({
  141. name: 'test_retry',
  142. test
  143. });
  144. await _runTest(test, isSkipped);
  145. numRetriesAvailable--;
  146. }
  147. }
  148. if (!isSkipped) {
  149. for (const hook of afterAll) {
  150. await _callCircusHook({
  151. describeBlock,
  152. hook
  153. });
  154. }
  155. }
  156. await (0, _state.dispatch)({
  157. describeBlock,
  158. name: 'run_describe_finish'
  159. });
  160. };
  161. function collectConcurrentTests(describeBlock) {
  162. if (describeBlock.mode === 'skip') {
  163. return [];
  164. }
  165. const {hasFocusedTests, testNamePattern} = (0, _state.getState)();
  166. return describeBlock.children.flatMap(child => {
  167. switch (child.type) {
  168. case 'describeBlock':
  169. return collectConcurrentTests(child);
  170. case 'test':
  171. const skip =
  172. !child.concurrent ||
  173. child.mode === 'skip' ||
  174. (hasFocusedTests && child.mode !== 'only') ||
  175. (testNamePattern &&
  176. !testNamePattern.test((0, _utils.getTestID)(child)));
  177. return skip ? [] : [child];
  178. }
  179. });
  180. }
  181. function startTestsConcurrently(concurrentTests) {
  182. const mutex = (0, _pLimit.default)((0, _state.getState)().maxConcurrency);
  183. const testNameStorage = new _async_hooks.AsyncLocalStorage();
  184. _expect.jestExpect.setState({
  185. currentConcurrentTestName: () => testNameStorage.getStore()
  186. });
  187. for (const test of concurrentTests) {
  188. try {
  189. const testFn = test.fn;
  190. const promise = mutex(() =>
  191. testNameStorage.run((0, _utils.getTestID)(test), testFn)
  192. );
  193. // Avoid triggering the uncaught promise rejection handler in case the
  194. // test fails before being awaited on.
  195. // eslint-disable-next-line @typescript-eslint/no-empty-function
  196. promise.catch(() => {});
  197. test.fn = () => promise;
  198. } catch (err) {
  199. test.fn = () => {
  200. throw err;
  201. };
  202. }
  203. }
  204. }
  205. const _runTest = async (test, parentSkipped) => {
  206. await (0, _state.dispatch)({
  207. name: 'test_start',
  208. test
  209. });
  210. const testContext = Object.create(null);
  211. const {hasFocusedTests, testNamePattern} = (0, _state.getState)();
  212. const isSkipped =
  213. parentSkipped ||
  214. test.mode === 'skip' ||
  215. (hasFocusedTests && test.mode === undefined) ||
  216. (testNamePattern && !testNamePattern.test((0, _utils.getTestID)(test)));
  217. if (isSkipped) {
  218. await (0, _state.dispatch)({
  219. name: 'test_skip',
  220. test
  221. });
  222. return;
  223. }
  224. if (test.mode === 'todo') {
  225. await (0, _state.dispatch)({
  226. name: 'test_todo',
  227. test
  228. });
  229. return;
  230. }
  231. await (0, _state.dispatch)({
  232. name: 'test_started',
  233. test
  234. });
  235. const {afterEach, beforeEach} = (0, _utils.getEachHooksForTest)(test);
  236. for (const hook of beforeEach) {
  237. if (test.errors.length) {
  238. // If any of the before hooks failed already, we don't run any
  239. // hooks after that.
  240. break;
  241. }
  242. await _callCircusHook({
  243. hook,
  244. test,
  245. testContext
  246. });
  247. }
  248. await _callCircusTest(test, testContext);
  249. for (const hook of afterEach) {
  250. await _callCircusHook({
  251. hook,
  252. test,
  253. testContext
  254. });
  255. }
  256. // `afterAll` hooks should not affect test status (pass or fail), because if
  257. // we had a global `afterAll` hook it would block all existing tests until
  258. // this hook is executed. So we dispatch `test_done` right away.
  259. await (0, _state.dispatch)({
  260. name: 'test_done',
  261. test
  262. });
  263. };
  264. const _callCircusHook = async ({
  265. hook,
  266. test,
  267. describeBlock,
  268. testContext = {}
  269. }) => {
  270. await (0, _state.dispatch)({
  271. hook,
  272. name: 'hook_start'
  273. });
  274. const timeout = hook.timeout || (0, _state.getState)().testTimeout;
  275. try {
  276. await (0, _utils.callAsyncCircusFn)(hook, testContext, {
  277. isHook: true,
  278. timeout
  279. });
  280. await (0, _state.dispatch)({
  281. describeBlock,
  282. hook,
  283. name: 'hook_success',
  284. test
  285. });
  286. } catch (error) {
  287. await (0, _state.dispatch)({
  288. describeBlock,
  289. error,
  290. hook,
  291. name: 'hook_failure',
  292. test
  293. });
  294. }
  295. };
  296. const _callCircusTest = async (test, testContext) => {
  297. await (0, _state.dispatch)({
  298. name: 'test_fn_start',
  299. test
  300. });
  301. const timeout = test.timeout || (0, _state.getState)().testTimeout;
  302. (0, _jestUtil.invariant)(
  303. test.fn,
  304. "Tests with no 'fn' should have 'mode' set to 'skipped'"
  305. );
  306. if (test.errors.length) {
  307. return; // We don't run the test if there's already an error in before hooks.
  308. }
  309. try {
  310. await (0, _utils.callAsyncCircusFn)(test, testContext, {
  311. isHook: false,
  312. timeout
  313. });
  314. if (test.failing) {
  315. test.asyncError.message =
  316. 'Failing test passed even though it was supposed to fail. Remove `.failing` to remove error.';
  317. await (0, _state.dispatch)({
  318. error: test.asyncError,
  319. name: 'test_fn_failure',
  320. test
  321. });
  322. } else {
  323. await (0, _state.dispatch)({
  324. name: 'test_fn_success',
  325. test
  326. });
  327. }
  328. } catch (error) {
  329. if (test.failing) {
  330. await (0, _state.dispatch)({
  331. name: 'test_fn_success',
  332. test
  333. });
  334. } else {
  335. await (0, _state.dispatch)({
  336. error,
  337. name: 'test_fn_failure',
  338. test
  339. });
  340. }
  341. }
  342. };
  343. var _default = run;
  344. exports.default = _default;