eventHandler.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _jestUtil = require('jest-util');
  7. var _globalErrorHandlers = require('./globalErrorHandlers');
  8. var _types = require('./types');
  9. var _utils = require('./utils');
  10. var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
  11. var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
  12. var jestNow = globalThis[Symbol.for('jest-native-now')] || globalThis.Date.now;
  13. /**
  14. * Copyright (c) Meta Platforms, Inc. and affiliates.
  15. *
  16. * This source code is licensed under the MIT license found in the
  17. * LICENSE file in the root directory of this source tree.
  18. */
  19. const eventHandler = (event, state) => {
  20. switch (event.name) {
  21. case 'include_test_location_in_result': {
  22. state.includeTestLocationInResult = true;
  23. break;
  24. }
  25. case 'hook_start': {
  26. event.hook.seenDone = false;
  27. break;
  28. }
  29. case 'start_describe_definition': {
  30. const {blockName, mode} = event;
  31. const {currentDescribeBlock, currentlyRunningTest} = state;
  32. if (currentlyRunningTest) {
  33. currentlyRunningTest.errors.push(
  34. new Error(
  35. `Cannot nest a describe inside a test. Describe block "${blockName}" cannot run because it is nested within "${currentlyRunningTest.name}".`
  36. )
  37. );
  38. break;
  39. }
  40. const describeBlock = (0, _utils.makeDescribe)(
  41. blockName,
  42. currentDescribeBlock,
  43. mode
  44. );
  45. currentDescribeBlock.children.push(describeBlock);
  46. state.currentDescribeBlock = describeBlock;
  47. break;
  48. }
  49. case 'finish_describe_definition': {
  50. const {currentDescribeBlock} = state;
  51. (0, _jestUtil.invariant)(
  52. currentDescribeBlock,
  53. 'currentDescribeBlock must be there'
  54. );
  55. if (!(0, _utils.describeBlockHasTests)(currentDescribeBlock)) {
  56. currentDescribeBlock.hooks.forEach(hook => {
  57. hook.asyncError.message = `Invalid: ${hook.type}() may not be used in a describe block containing no tests.`;
  58. state.unhandledErrors.push(hook.asyncError);
  59. });
  60. }
  61. // pass mode of currentDescribeBlock to tests
  62. // but do not when there is already a single test with "only" mode
  63. const shouldPassMode = !(
  64. currentDescribeBlock.mode === 'only' &&
  65. currentDescribeBlock.children.some(
  66. child => child.type === 'test' && child.mode === 'only'
  67. )
  68. );
  69. if (shouldPassMode) {
  70. currentDescribeBlock.children.forEach(child => {
  71. if (child.type === 'test' && !child.mode) {
  72. child.mode = currentDescribeBlock.mode;
  73. }
  74. });
  75. }
  76. if (
  77. !state.hasFocusedTests &&
  78. currentDescribeBlock.mode !== 'skip' &&
  79. currentDescribeBlock.children.some(
  80. child => child.type === 'test' && child.mode === 'only'
  81. )
  82. ) {
  83. state.hasFocusedTests = true;
  84. }
  85. if (currentDescribeBlock.parent) {
  86. state.currentDescribeBlock = currentDescribeBlock.parent;
  87. }
  88. break;
  89. }
  90. case 'add_hook': {
  91. const {currentDescribeBlock, currentlyRunningTest, hasStarted} = state;
  92. const {asyncError, fn, hookType: type, timeout} = event;
  93. if (currentlyRunningTest) {
  94. currentlyRunningTest.errors.push(
  95. new Error(
  96. `Hooks cannot be defined inside tests. Hook of type "${type}" is nested within "${currentlyRunningTest.name}".`
  97. )
  98. );
  99. break;
  100. } else if (hasStarted) {
  101. state.unhandledErrors.push(
  102. new Error(
  103. 'Cannot add a hook after tests have started running. Hooks must be defined synchronously.'
  104. )
  105. );
  106. break;
  107. }
  108. const parent = currentDescribeBlock;
  109. currentDescribeBlock.hooks.push({
  110. asyncError,
  111. fn,
  112. parent,
  113. seenDone: false,
  114. timeout,
  115. type
  116. });
  117. break;
  118. }
  119. case 'add_test': {
  120. const {currentDescribeBlock, currentlyRunningTest, hasStarted} = state;
  121. const {
  122. asyncError,
  123. fn,
  124. mode,
  125. testName: name,
  126. timeout,
  127. concurrent,
  128. failing
  129. } = event;
  130. if (currentlyRunningTest) {
  131. currentlyRunningTest.errors.push(
  132. new Error(
  133. `Tests cannot be nested. Test "${name}" cannot run because it is nested within "${currentlyRunningTest.name}".`
  134. )
  135. );
  136. break;
  137. } else if (hasStarted) {
  138. state.unhandledErrors.push(
  139. new Error(
  140. 'Cannot add a test after tests have started running. Tests must be defined synchronously.'
  141. )
  142. );
  143. break;
  144. }
  145. const test = (0, _utils.makeTest)(
  146. fn,
  147. mode,
  148. concurrent,
  149. name,
  150. currentDescribeBlock,
  151. timeout,
  152. asyncError,
  153. failing
  154. );
  155. if (currentDescribeBlock.mode !== 'skip' && test.mode === 'only') {
  156. state.hasFocusedTests = true;
  157. }
  158. currentDescribeBlock.children.push(test);
  159. currentDescribeBlock.tests.push(test);
  160. break;
  161. }
  162. case 'hook_failure': {
  163. const {test, describeBlock, error, hook} = event;
  164. const {asyncError, type} = hook;
  165. if (type === 'beforeAll') {
  166. (0, _jestUtil.invariant)(
  167. describeBlock,
  168. 'always present for `*All` hooks'
  169. );
  170. (0, _utils.addErrorToEachTestUnderDescribe)(
  171. describeBlock,
  172. error,
  173. asyncError
  174. );
  175. } else if (type === 'afterAll') {
  176. // Attaching `afterAll` errors to each test makes execution flow
  177. // too complicated, so we'll consider them to be global.
  178. state.unhandledErrors.push([error, asyncError]);
  179. } else {
  180. (0, _jestUtil.invariant)(test, 'always present for `*Each` hooks');
  181. test.errors.push([error, asyncError]);
  182. }
  183. break;
  184. }
  185. case 'test_skip': {
  186. event.test.status = 'skip';
  187. break;
  188. }
  189. case 'test_todo': {
  190. event.test.status = 'todo';
  191. break;
  192. }
  193. case 'test_done': {
  194. event.test.duration = (0, _utils.getTestDuration)(event.test);
  195. event.test.status = 'done';
  196. state.currentlyRunningTest = null;
  197. break;
  198. }
  199. case 'test_start': {
  200. state.currentlyRunningTest = event.test;
  201. event.test.startedAt = jestNow();
  202. event.test.invocations += 1;
  203. break;
  204. }
  205. case 'test_fn_start': {
  206. event.test.seenDone = false;
  207. break;
  208. }
  209. case 'test_fn_failure': {
  210. const {
  211. error,
  212. test: {asyncError}
  213. } = event;
  214. event.test.errors.push([error, asyncError]);
  215. break;
  216. }
  217. case 'test_retry': {
  218. const logErrorsBeforeRetry =
  219. // eslint-disable-next-line no-restricted-globals
  220. global[_types.LOG_ERRORS_BEFORE_RETRY] || false;
  221. if (logErrorsBeforeRetry) {
  222. event.test.retryReasons.push(...event.test.errors);
  223. }
  224. event.test.errors = [];
  225. break;
  226. }
  227. case 'run_start': {
  228. state.hasStarted = true;
  229. /* eslint-disable no-restricted-globals */
  230. global[_types.TEST_TIMEOUT_SYMBOL] &&
  231. (state.testTimeout = global[_types.TEST_TIMEOUT_SYMBOL]);
  232. /* eslint-enable */
  233. break;
  234. }
  235. case 'run_finish': {
  236. break;
  237. }
  238. case 'setup': {
  239. // Uncaught exception handlers should be defined on the parent process
  240. // object. If defined on the VM's process object they just no op and let
  241. // the parent process crash. It might make sense to return a `dispatch`
  242. // function to the parent process and register handlers there instead, but
  243. // i'm not sure if this is works. For now i just replicated whatever
  244. // jasmine was doing -- dabramov
  245. state.parentProcess = event.parentProcess;
  246. (0, _jestUtil.invariant)(state.parentProcess);
  247. state.originalGlobalErrorHandlers = (0,
  248. _globalErrorHandlers.injectGlobalErrorHandlers)(state.parentProcess);
  249. if (event.testNamePattern) {
  250. state.testNamePattern = new RegExp(event.testNamePattern, 'i');
  251. }
  252. break;
  253. }
  254. case 'teardown': {
  255. (0, _jestUtil.invariant)(state.originalGlobalErrorHandlers);
  256. (0, _jestUtil.invariant)(state.parentProcess);
  257. (0, _globalErrorHandlers.restoreGlobalErrorHandlers)(
  258. state.parentProcess,
  259. state.originalGlobalErrorHandlers
  260. );
  261. break;
  262. }
  263. case 'error': {
  264. // It's very likely for long-running async tests to throw errors. In this
  265. // case we want to catch them and fail the current test. At the same time
  266. // there's a possibility that one test sets a long timeout, that will
  267. // eventually throw after this test finishes but during some other test
  268. // execution, which will result in one test's error failing another test.
  269. // In any way, it should be possible to track where the error was thrown
  270. // from.
  271. state.currentlyRunningTest
  272. ? state.currentlyRunningTest.errors.push(event.error)
  273. : state.unhandledErrors.push(event.error);
  274. break;
  275. }
  276. }
  277. };
  278. var _default = eventHandler;
  279. exports.default = _default;