UNPKG

jest-circus

Version:
1,424 lines (1,353 loc) 70.3 kB
/*! * /** * * Copyright (c) Meta Platforms, Inc. and affiliates. * * * * This source code is licensed under the MIT license found in the * * LICENSE file in the root directory of this source tree. * * / */ /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./src/eventHandler.ts": /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports["default"] = void 0; var _jestUtil = require("jest-util"); var _globalErrorHandlers = __webpack_require__("./src/globalErrorHandlers.ts"); var _types = __webpack_require__("./src/types.ts"); var _utils = __webpack_require__("./src/utils.ts"); var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol; var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol; var jestNow = globalThis[Symbol.for('jest-native-now')] || globalThis.Date.now; /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const eventHandler = (event, state) => { switch (event.name) { case 'include_test_location_in_result': { state.includeTestLocationInResult = true; break; } case 'hook_start': { event.hook.seenDone = false; break; } case 'start_describe_definition': { const { blockName, mode } = event; const { currentDescribeBlock, currentlyRunningTest } = state; if (currentlyRunningTest) { currentlyRunningTest.errors.push(new Error(`Cannot nest a describe inside a test. Describe block "${blockName}" cannot run because it is nested within "${currentlyRunningTest.name}".`)); break; } const describeBlock = (0, _utils.makeDescribe)(blockName, currentDescribeBlock, mode); currentDescribeBlock.children.push(describeBlock); state.currentDescribeBlock = describeBlock; break; } case 'finish_describe_definition': { const { currentDescribeBlock } = state; (0, _jestUtil.invariant)(currentDescribeBlock, 'currentDescribeBlock must be there'); if (!(0, _utils.describeBlockHasTests)(currentDescribeBlock)) { for (const hook of currentDescribeBlock.hooks) { hook.asyncError.message = `Invalid: ${hook.type}() may not be used in a describe block containing no tests.`; state.unhandledErrors.push(hook.asyncError); } } // pass mode of currentDescribeBlock to tests // but do not when there is already a single test with "only" mode const shouldPassMode = !(currentDescribeBlock.mode === 'only' && currentDescribeBlock.children.some(child => child.type === 'test' && child.mode === 'only')); if (shouldPassMode) { for (const child of currentDescribeBlock.children) { if (child.type === 'test' && !child.mode) { child.mode = currentDescribeBlock.mode; } } } if (!state.hasFocusedTests && currentDescribeBlock.mode !== 'skip' && currentDescribeBlock.children.some(child => child.type === 'test' && child.mode === 'only')) { state.hasFocusedTests = true; } if (currentDescribeBlock.parent) { state.currentDescribeBlock = currentDescribeBlock.parent; } break; } case 'add_hook': { const { currentDescribeBlock, currentlyRunningTest, hasStarted } = state; const { asyncError, fn, hookType: type, timeout } = event; if (currentlyRunningTest) { currentlyRunningTest.errors.push(new Error(`Hooks cannot be defined inside tests. Hook of type "${type}" is nested within "${currentlyRunningTest.name}".`)); break; } else if (hasStarted) { state.unhandledErrors.push(new Error('Cannot add a hook after tests have started running. Hooks must be defined synchronously.')); break; } const parent = currentDescribeBlock; currentDescribeBlock.hooks.push({ asyncError, fn, parent, seenDone: false, timeout, type }); break; } case 'add_test': { const { currentDescribeBlock, currentlyRunningTest, hasStarted } = state; const { asyncError, fn, mode, testName: name, timeout, concurrent, failing } = event; if (currentlyRunningTest) { currentlyRunningTest.errors.push(new Error(`Tests cannot be nested. Test "${name}" cannot run because it is nested within "${currentlyRunningTest.name}".`)); break; } else if (hasStarted) { state.unhandledErrors.push(new Error('Cannot add a test after tests have started running. Tests must be defined synchronously.')); break; } const test = (0, _utils.makeTest)(fn, mode, concurrent, name, currentDescribeBlock, timeout, asyncError, failing); if (currentDescribeBlock.mode !== 'skip' && test.mode === 'only') { state.hasFocusedTests = true; } currentDescribeBlock.children.push(test); currentDescribeBlock.tests.push(test); break; } case 'hook_failure': { const { test, describeBlock, error, hook } = event; const { asyncError, type } = hook; if (type === 'beforeAll') { (0, _jestUtil.invariant)(describeBlock, 'always present for `*All` hooks'); (0, _utils.addErrorToEachTestUnderDescribe)(describeBlock, error, asyncError); } else if (type === 'afterAll') { // Attaching `afterAll` errors to each test makes execution flow // too complicated, so we'll consider them to be global. state.unhandledErrors.push([error, asyncError]); } else { (0, _jestUtil.invariant)(test, 'always present for `*Each` hooks'); test.errors.push([error, asyncError]); } break; } case 'test_skip': { event.test.status = 'skip'; break; } case 'test_todo': { event.test.status = 'todo'; break; } case 'test_done': { event.test.duration = (0, _utils.getTestDuration)(event.test); event.test.status = 'done'; state.currentlyRunningTest = null; break; } case 'test_start': { state.currentlyRunningTest = event.test; event.test.startedAt = jestNow(); event.test.invocations += 1; break; } case 'test_fn_start': { event.test.seenDone = false; break; } case 'test_fn_failure': { const { error, test: { asyncError } } = event; event.test.errors.push([error, asyncError]); break; } case 'test_retry': { const logErrorsBeforeRetry = globalThis[_types.LOG_ERRORS_BEFORE_RETRY] || false; if (logErrorsBeforeRetry) { event.test.retryReasons.push(...event.test.errors); } event.test.errors = []; break; } case 'run_start': { state.hasStarted = true; if (globalThis[_types.TEST_TIMEOUT_SYMBOL]) { state.testTimeout = globalThis[_types.TEST_TIMEOUT_SYMBOL]; } break; } case 'run_finish': { break; } case 'setup': { // Uncaught exception handlers should be defined on the parent process // object. If defined on the VM's process object they just no op and let // the parent process crash. It might make sense to return a `dispatch` // function to the parent process and register handlers there instead, but // i'm not sure if this is works. For now i just replicated whatever // jasmine was doing -- dabramov state.parentProcess = event.parentProcess; (0, _jestUtil.invariant)(state.parentProcess); state.originalGlobalErrorHandlers = (0, _globalErrorHandlers.injectGlobalErrorHandlers)(state.parentProcess); if (event.testNamePattern) { state.testNamePattern = new RegExp(event.testNamePattern, 'i'); } break; } case 'teardown': { (0, _jestUtil.invariant)(state.originalGlobalErrorHandlers); (0, _jestUtil.invariant)(state.parentProcess); (0, _globalErrorHandlers.restoreGlobalErrorHandlers)(state.parentProcess, state.originalGlobalErrorHandlers); break; } case 'error': { // It's very likely for long-running async tests to throw errors. In this // case we want to catch them and fail the current test. At the same time // there's a possibility that one test sets a long timeout, that will // eventually throw after this test finishes but during some other test // execution, which will result in one test's error failing another test. // In any way, it should be possible to track where the error was thrown // from. if (state.currentlyRunningTest) { if (event.promise) { state.currentlyRunningTest.unhandledRejectionErrorByPromise.set(event.promise, event.error); } else { state.currentlyRunningTest.errors.push(event.error); } } else { if (event.promise) { state.unhandledRejectionErrorByPromise.set(event.promise, event.error); } else { state.unhandledErrors.push(event.error); } } break; } case 'error_handled': { if (state.currentlyRunningTest) { state.currentlyRunningTest.unhandledRejectionErrorByPromise.delete(event.promise); } else { state.unhandledRejectionErrorByPromise.delete(event.promise); } break; } } }; var _default = exports["default"] = eventHandler; /***/ }), /***/ "./src/formatNodeAssertErrors.ts": /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports["default"] = void 0; var _assert = require("assert"); var _chalk = _interopRequireDefault(require("chalk")); var _jestMatcherUtils = require("jest-matcher-utils"); var _prettyFormat = require("pretty-format"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const assertOperatorsMap = { '!=': 'notEqual', '!==': 'notStrictEqual', '==': 'equal', '===': 'strictEqual' }; const humanReadableOperators = { deepEqual: 'to deeply equal', deepStrictEqual: 'to deeply and strictly equal', equal: 'to be equal', notDeepEqual: 'not to deeply equal', notDeepStrictEqual: 'not to deeply and strictly equal', notEqual: 'to not be equal', notStrictEqual: 'not be strictly equal', strictEqual: 'to strictly be equal' }; const formatNodeAssertErrors = (event, state) => { if (event.name === 'test_done') { event.test.errors = event.test.errors.map(errors => { let error; if (Array.isArray(errors)) { const [originalError, asyncError] = errors; if (originalError == null) { error = asyncError; } else if (originalError.stack) { error = originalError; } else { error = asyncError; error.message = originalError.message || `thrown: ${(0, _prettyFormat.format)(originalError, { maxDepth: 3 })}`; } } else { error = errors; } return isAssertionError(error) ? { message: assertionErrorMessage(error, { expand: state.expand }) } : errors; }); } }; const getOperatorName = (operator, stack) => { if (typeof operator === 'string') { return assertOperatorsMap[operator] || operator; } if (stack.match('.doesNotThrow')) { return 'doesNotThrow'; } if (stack.match('.throws')) { return 'throws'; } return ''; }; const operatorMessage = operator => { const niceOperatorName = getOperatorName(operator, ''); const humanReadableOperator = humanReadableOperators[niceOperatorName]; return typeof operator === 'string' ? `${humanReadableOperator || niceOperatorName} to:\n` : ''; }; const assertThrowingMatcherHint = operatorName => operatorName ? _chalk.default.dim('assert') + _chalk.default.dim(`.${operatorName}(`) + _chalk.default.red('function') + _chalk.default.dim(')') : ''; const assertMatcherHint = (operator, operatorName, expected) => { let message = ''; if (operator === '==' && expected === true) { message = _chalk.default.dim('assert') + _chalk.default.dim('(') + _chalk.default.red('received') + _chalk.default.dim(')'); } else if (operatorName) { message = _chalk.default.dim('assert') + _chalk.default.dim(`.${operatorName}(`) + _chalk.default.red('received') + _chalk.default.dim(', ') + _chalk.default.green('expected') + _chalk.default.dim(')'); } return message; }; function assertionErrorMessage(error, options) { const { expected, actual, generatedMessage, message, operator, stack } = error; const diffString = (0, _jestMatcherUtils.diff)(expected, actual, options); const hasCustomMessage = !generatedMessage; const operatorName = getOperatorName(operator, stack); const trimmedStack = stack.replace(message, '').replaceAll(/AssertionError(.*)/g, ''); if (operatorName === 'doesNotThrow') { return ( // eslint-disable-next-line prefer-template buildHintString(assertThrowingMatcherHint(operatorName)) + _chalk.default.reset('Expected the function not to throw an error.\n') + _chalk.default.reset('Instead, it threw:\n') + ` ${(0, _jestMatcherUtils.printReceived)(actual)}` + _chalk.default.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : '') + trimmedStack ); } if (operatorName === 'throws') { if (error.generatedMessage) { return buildHintString(assertThrowingMatcherHint(operatorName)) + _chalk.default.reset(error.message) + _chalk.default.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : '') + trimmedStack; } return buildHintString(assertThrowingMatcherHint(operatorName)) + _chalk.default.reset('Expected the function to throw an error.\n') + _chalk.default.reset("But it didn't throw anything.") + _chalk.default.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : '') + trimmedStack; } if (operatorName === 'fail') { return buildHintString(assertMatcherHint(operator, operatorName, expected)) + _chalk.default.reset(hasCustomMessage ? `Message:\n ${message}` : '') + trimmedStack; } return ( // eslint-disable-next-line prefer-template buildHintString(assertMatcherHint(operator, operatorName, expected)) + _chalk.default.reset(`Expected value ${operatorMessage(operator)}`) + ` ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + _chalk.default.reset('Received:\n') + ` ${(0, _jestMatcherUtils.printReceived)(actual)}` + _chalk.default.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : '') + (diffString ? `\n\nDifference:\n\n${diffString}` : '') + trimmedStack ); } function isAssertionError(error) { return error && (error instanceof _assert.AssertionError || error.name === _assert.AssertionError.name || error.code === 'ERR_ASSERTION'); } function buildHintString(hint) { return hint ? `${hint}\n\n` : ''; } var _default = exports["default"] = formatNodeAssertErrors; /***/ }), /***/ "./src/globalErrorHandlers.ts": /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.restoreGlobalErrorHandlers = exports.injectGlobalErrorHandlers = void 0; var _state = __webpack_require__("./src/state.ts"); /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const uncaughtExceptionListener = error => { (0, _state.dispatchSync)({ error, name: 'error' }); }; const unhandledRejectionListener = (error, promise) => { (0, _state.dispatchSync)({ error, name: 'error', promise }); }; const rejectionHandledListener = promise => { (0, _state.dispatchSync)({ name: 'error_handled', promise }); }; const injectGlobalErrorHandlers = parentProcess => { const uncaughtException = [...process.listeners('uncaughtException')]; const unhandledRejection = [...process.listeners('unhandledRejection')]; const rejectionHandled = [...process.listeners('rejectionHandled')]; parentProcess.removeAllListeners('uncaughtException'); parentProcess.removeAllListeners('unhandledRejection'); parentProcess.removeAllListeners('rejectionHandled'); parentProcess.on('uncaughtException', uncaughtExceptionListener); parentProcess.on('unhandledRejection', unhandledRejectionListener); parentProcess.on('rejectionHandled', rejectionHandledListener); return { rejectionHandled, uncaughtException, unhandledRejection }; }; exports.injectGlobalErrorHandlers = injectGlobalErrorHandlers; const restoreGlobalErrorHandlers = (parentProcess, originalErrorHandlers) => { parentProcess.removeListener('uncaughtException', uncaughtExceptionListener); parentProcess.removeListener('unhandledRejection', unhandledRejectionListener); parentProcess.removeListener('rejectionHandled', rejectionHandledListener); for (const listener of originalErrorHandlers.uncaughtException) { parentProcess.on('uncaughtException', listener); } for (const listener of originalErrorHandlers.unhandledRejection) { parentProcess.on('unhandledRejection', listener); } for (const listener of originalErrorHandlers.rejectionHandled) { parentProcess.on('rejectionHandled', listener); } }; exports.restoreGlobalErrorHandlers = restoreGlobalErrorHandlers; /***/ }), /***/ "./src/index.ts": /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "addEventHandler", ({ enumerable: true, get: function () { return _state.addEventHandler; } })); exports.describe = exports["default"] = exports.beforeEach = exports.beforeAll = exports.afterEach = exports.afterAll = void 0; Object.defineProperty(exports, "getState", ({ enumerable: true, get: function () { return _state.getState; } })); exports.it = void 0; Object.defineProperty(exports, "removeEventHandler", ({ enumerable: true, get: function () { return _state.removeEventHandler; } })); Object.defineProperty(exports, "resetState", ({ enumerable: true, get: function () { return _state.resetState; } })); Object.defineProperty(exports, "run", ({ enumerable: true, get: function () { return _run.default; } })); Object.defineProperty(exports, "setState", ({ enumerable: true, get: function () { return _state.setState; } })); exports.test = void 0; var _jestEach = require("jest-each"); var _jestUtil = require("jest-util"); var _state = __webpack_require__("./src/state.ts"); var _run = _interopRequireDefault(__webpack_require__("./src/run.ts")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const describe = exports.describe = (() => { const describe = (blockName, blockFn) => _dispatchDescribe(blockFn, blockName, describe); const only = (blockName, blockFn) => _dispatchDescribe(blockFn, blockName, only, 'only'); const skip = (blockName, blockFn) => _dispatchDescribe(blockFn, blockName, skip, 'skip'); describe.each = (0, _jestEach.bind)(describe, false); only.each = (0, _jestEach.bind)(only, false); skip.each = (0, _jestEach.bind)(skip, false); describe.only = only; describe.skip = skip; return describe; })(); const _dispatchDescribe = (blockFn, blockName, describeFn, mode) => { const asyncError = new _jestUtil.ErrorWithStack(undefined, describeFn); if (blockFn === undefined) { asyncError.message = 'Missing second argument. It must be a callback function.'; throw asyncError; } if (typeof blockFn !== 'function') { asyncError.message = `Invalid second argument, ${blockFn}. It must be a callback function.`; throw asyncError; } try { blockName = (0, _jestUtil.convertDescriptorToString)(blockName); } catch (error) { asyncError.message = error.message; throw asyncError; } (0, _state.dispatchSync)({ asyncError, blockName, mode, name: 'start_describe_definition' }); const describeReturn = blockFn(); if ((0, _jestUtil.isPromise)(describeReturn)) { throw new _jestUtil.ErrorWithStack('Returning a Promise from "describe" is not supported. Tests must be defined synchronously.', describeFn); } else if (describeReturn !== undefined) { throw new _jestUtil.ErrorWithStack('A "describe" callback must not return a value.', describeFn); } (0, _state.dispatchSync)({ blockName, mode, name: 'finish_describe_definition' }); }; const _addHook = (fn, hookType, hookFn, timeout) => { const asyncError = new _jestUtil.ErrorWithStack(undefined, hookFn); if (typeof fn !== 'function') { asyncError.message = 'Invalid first argument. It must be a callback function.'; throw asyncError; } (0, _state.dispatchSync)({ asyncError, fn, hookType, name: 'add_hook', timeout }); }; // Hooks have to pass themselves to the HOF in order for us to trim stack traces. const beforeEach = (fn, timeout) => _addHook(fn, 'beforeEach', beforeEach, timeout); exports.beforeEach = beforeEach; const beforeAll = (fn, timeout) => _addHook(fn, 'beforeAll', beforeAll, timeout); exports.beforeAll = beforeAll; const afterEach = (fn, timeout) => _addHook(fn, 'afterEach', afterEach, timeout); exports.afterEach = afterEach; const afterAll = (fn, timeout) => _addHook(fn, 'afterAll', afterAll, timeout); exports.afterAll = afterAll; const test = exports.test = (() => { const test = (testName, fn, timeout) => _addTest(testName, undefined, false, fn, test, timeout); const skip = (testName, fn, timeout) => _addTest(testName, 'skip', false, fn, skip, timeout); const only = (testName, fn, timeout) => _addTest(testName, 'only', false, fn, test.only, timeout); const concurrentTest = (testName, fn, timeout) => _addTest(testName, undefined, true, fn, concurrentTest, timeout); const concurrentOnly = (testName, fn, timeout) => _addTest(testName, 'only', true, fn, concurrentOnly, timeout); const bindFailing = (concurrent, mode) => { const failing = (testName, fn, timeout, eachError) => _addTest(testName, mode, concurrent, fn, failing, timeout, true, eachError); failing.each = (0, _jestEach.bind)(failing, false, true); return failing; }; test.todo = (testName, ...rest) => { if (rest.length > 0 || typeof testName !== 'string') { throw new _jestUtil.ErrorWithStack('Todo must be called with only a description.', test.todo); } // eslint-disable-next-line @typescript-eslint/no-empty-function return _addTest(testName, 'todo', false, () => {}, test.todo); }; const _addTest = (testName, mode, concurrent, fn, testFn, timeout, failing, asyncError = new _jestUtil.ErrorWithStack(undefined, testFn)) => { try { testName = (0, _jestUtil.convertDescriptorToString)(testName); } catch (error) { asyncError.message = error.message; throw asyncError; } if (fn === undefined) { asyncError.message = 'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.'; throw asyncError; } if (typeof fn !== 'function') { asyncError.message = `Invalid second argument, ${fn}. It must be a callback function.`; throw asyncError; } return (0, _state.dispatchSync)({ asyncError, concurrent, failing: failing === undefined ? false : failing, fn, mode, name: 'add_test', testName, timeout }); }; test.each = (0, _jestEach.bind)(test); only.each = (0, _jestEach.bind)(only); skip.each = (0, _jestEach.bind)(skip); concurrentTest.each = (0, _jestEach.bind)(concurrentTest, false); concurrentOnly.each = (0, _jestEach.bind)(concurrentOnly, false); only.failing = bindFailing(false, 'only'); skip.failing = bindFailing(false, 'skip'); test.failing = bindFailing(false); test.only = only; test.skip = skip; test.concurrent = concurrentTest; concurrentTest.only = concurrentOnly; concurrentTest.skip = skip; concurrentTest.failing = bindFailing(true); concurrentOnly.failing = bindFailing(true, 'only'); return test; })(); const it = exports.it = test; var _default = exports["default"] = { afterAll, afterEach, beforeAll, beforeEach, describe, it, test }; /***/ }), /***/ "./src/run.ts": /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports["default"] = void 0; var _async_hooks = require("async_hooks"); var _pLimit = _interopRequireDefault(require("p-limit")); var _expect = require("@jest/expect"); var _jestUtil = require("jest-util"); var _shuffleArray = _interopRequireWildcard(__webpack_require__("./src/shuffleArray.ts")); var _state = __webpack_require__("./src/state.ts"); var _types = __webpack_require__("./src/types.ts"); var _utils = __webpack_require__("./src/utils.ts"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol; var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol; var Promise = globalThis[Symbol.for('jest-native-promise')] || globalThis.Promise; /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ // Global values can be overwritten by mocks or tests. We'll capture // the original values in the variables before we require any files. const { setTimeout } = globalThis; const run = async () => { const { rootDescribeBlock, seed, randomize } = (0, _state.getState)(); const rng = randomize ? (0, _shuffleArray.rngBuilder)(seed) : undefined; await (0, _state.dispatch)({ name: 'run_start' }); await _runTestsForDescribeBlock(rootDescribeBlock, rng, true); await (0, _state.dispatch)({ name: 'run_finish' }); return (0, _utils.makeRunResult)((0, _state.getState)().rootDescribeBlock, (0, _state.getState)().unhandledErrors); }; const _runTestsForDescribeBlock = async (describeBlock, rng, isRootBlock = false) => { await (0, _state.dispatch)({ describeBlock, name: 'run_describe_start' }); const { beforeAll, afterAll } = (0, _utils.getAllHooksForDescribe)(describeBlock); const isSkipped = describeBlock.mode === 'skip'; if (!isSkipped) { for (const hook of beforeAll) { await _callCircusHook({ describeBlock, hook }); } } if (isRootBlock) { const concurrentTests = collectConcurrentTests(describeBlock); if (concurrentTests.length > 0) { startTestsConcurrently(concurrentTests, isSkipped); } } // Tests that fail and are retried we run after other tests const retryTimes = Number.parseInt(globalThis[_types.RETRY_TIMES], 10) || 0; const waitBeforeRetry = Number.parseInt(globalThis[_types.WAIT_BEFORE_RETRY], 10) || 0; const retryImmediately = globalThis[_types.RETRY_IMMEDIATELY] || false; const deferredRetryTests = []; if (rng) { describeBlock.children = (0, _shuffleArray.default)(describeBlock.children, rng); } const rerunTest = async test => { let numRetriesAvailable = retryTimes; while (numRetriesAvailable > 0 && test.errors.length > 0) { // Clear errors so retries occur await (0, _state.dispatch)({ name: 'test_retry', test }); if (waitBeforeRetry > 0) { await new Promise(resolve => setTimeout(resolve, waitBeforeRetry)); } await _runTest(test, isSkipped); numRetriesAvailable--; } }; const handleRetry = async (test, hasErrorsBeforeTestRun, hasRetryTimes) => { // no retry if the test passed or had errors before the test ran if (test.errors.length === 0 || hasErrorsBeforeTestRun || !hasRetryTimes) { return; } if (!retryImmediately) { deferredRetryTests.push(test); return; } // If immediate retry is set, we retry the test immediately after the first run await rerunTest(test); }; const concurrentTests = []; for (const child of describeBlock.children) { switch (child.type) { case 'describeBlock': { await _runTestsForDescribeBlock(child, rng); break; } case 'test': { const hasErrorsBeforeTestRun = child.errors.length > 0; const hasRetryTimes = retryTimes > 0; if (child.concurrent) { concurrentTests.push(child.done.then(() => handleRetry(child, hasErrorsBeforeTestRun, hasRetryTimes))); } else { await _runTest(child, isSkipped); await handleRetry(child, hasErrorsBeforeTestRun, hasRetryTimes); } break; } } } // wait for concurrent tests to finish await Promise.all(concurrentTests); // Re-run failed tests n-times if configured for (const test of deferredRetryTests) { await rerunTest(test); } if (!isSkipped) { for (const hook of afterAll) { await _callCircusHook({ describeBlock, hook }); } } await (0, _state.dispatch)({ describeBlock, name: 'run_describe_finish' }); }; function collectConcurrentTests(describeBlock) { if (describeBlock.mode === 'skip') { return []; } return describeBlock.children.flatMap(child => { switch (child.type) { case 'describeBlock': return collectConcurrentTests(child); case 'test': if (child.concurrent) { return [child]; } return []; } }); } function startTestsConcurrently(concurrentTests, parentSkipped) { const mutex = (0, _pLimit.default)((0, _state.getState)().maxConcurrency); const testNameStorage = new _async_hooks.AsyncLocalStorage(); _expect.jestExpect.setState({ currentConcurrentTestName: () => testNameStorage.getStore() }); for (const test of concurrentTests) { try { const promise = mutex(() => testNameStorage.run((0, _utils.getTestID)(test), () => _runTest(test, parentSkipped))); // Avoid triggering the uncaught promise rejection handler in case the // test fails before being awaited on. // eslint-disable-next-line @typescript-eslint/no-empty-function promise.catch(() => {}); test.done = promise; } catch (error) { test.fn = () => { throw error; }; } } } const _runTest = async (test, parentSkipped) => { await (0, _state.dispatch)({ name: 'test_start', test }); const testContext = Object.create(null); const { hasFocusedTests, testNamePattern } = (0, _state.getState)(); const isSkipped = parentSkipped || test.mode === 'skip' || hasFocusedTests && test.mode === undefined || testNamePattern && !testNamePattern.test((0, _utils.getTestID)(test)); if (isSkipped) { await (0, _state.dispatch)({ name: 'test_skip', test }); return; } if (test.mode === 'todo') { await (0, _state.dispatch)({ name: 'test_todo', test }); return; } await (0, _state.dispatch)({ name: 'test_started', test }); const { afterEach, beforeEach } = (0, _utils.getEachHooksForTest)(test); for (const hook of beforeEach) { if (test.errors.length > 0) { // If any of the before hooks failed already, we don't run any // hooks after that. break; } await _callCircusHook({ hook, test, testContext }); } await _callCircusTest(test, testContext); for (const hook of afterEach) { await _callCircusHook({ hook, test, testContext }); } // `afterAll` hooks should not affect test status (pass or fail), because if // we had a global `afterAll` hook it would block all existing tests until // this hook is executed. So we dispatch `test_done` right away. await (0, _state.dispatch)({ name: 'test_done', test }); }; const _callCircusHook = async ({ hook, test, describeBlock, testContext = {} }) => { await (0, _state.dispatch)({ hook, name: 'hook_start' }); const timeout = hook.timeout || (0, _state.getState)().testTimeout; try { await (0, _utils.callAsyncCircusFn)(hook, testContext, { isHook: true, timeout }); await (0, _state.dispatch)({ describeBlock, hook, name: 'hook_success', test }); } catch (error) { await (0, _state.dispatch)({ describeBlock, error, hook, name: 'hook_failure', test }); } }; const _callCircusTest = async (test, testContext) => { await (0, _state.dispatch)({ name: 'test_fn_start', test }); const timeout = test.timeout || (0, _state.getState)().testTimeout; (0, _jestUtil.invariant)(test.fn, "Tests with no 'fn' should have 'mode' set to 'skipped'"); if (test.errors.length > 0) { return; // We don't run the test if there's already an error in before hooks. } try { await (0, _utils.callAsyncCircusFn)(test, testContext, { isHook: false, timeout }); if (test.failing) { test.asyncError.message = 'Failing test passed even though it was supposed to fail. Remove `.failing` to remove error.'; await (0, _state.dispatch)({ error: test.asyncError, name: 'test_fn_failure', test }); } else { await (0, _state.dispatch)({ name: 'test_fn_success', test }); } } catch (error) { if (test.failing) { await (0, _state.dispatch)({ name: 'test_fn_success', test }); } else { await (0, _state.dispatch)({ error, name: 'test_fn_failure', test }); } } }; var _default = exports["default"] = run; /***/ }), /***/ "./src/shuffleArray.ts": /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports["default"] = shuffleArray; exports.rngBuilder = void 0; var _pureRand = require("pure-rand"); /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ // Generates [from, to] inclusive const rngBuilder = seed => { const gen = (0, _pureRand.xoroshiro128plus)(seed); return { next: (from, to) => (0, _pureRand.unsafeUniformIntDistribution)(from, to, gen) }; }; // Fisher-Yates shuffle // This is performed in-place exports.rngBuilder = rngBuilder; function shuffleArray(array, random) { const length = array.length; if (length === 0) { return []; } for (let i = 0; i < length; i++) { const n = random.next(i, length - 1); const value = array[i]; array[i] = array[n]; array[n] = value; } return array; } /***/ }), /***/ "./src/state.ts": /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.setState = exports.resetState = exports.removeEventHandler = exports.getState = exports.dispatchSync = exports.dispatch = exports.addEventHandler = exports.ROOT_DESCRIBE_BLOCK_NAME = void 0; var _jestUtil = require("jest-util"); var _eventHandler = _interopRequireDefault(__webpack_require__("./src/eventHandler.ts")); var _formatNodeAssertErrors = _interopRequireDefault(__webpack_require__("./src/formatNodeAssertErrors.ts")); var _types = __webpack_require__("./src/types.ts"); var _utils = __webpack_require__("./src/utils.ts"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const handlers = globalThis[_types.EVENT_HANDLERS] || [_eventHandler.default, _formatNodeAssertErrors.default]; (0, _jestUtil.setGlobal)(globalThis, _types.EVENT_HANDLERS, handlers, 'retain'); const ROOT_DESCRIBE_BLOCK_NAME = exports.ROOT_DESCRIBE_BLOCK_NAME = 'ROOT_DESCRIBE_BLOCK'; const createState = () => { const ROOT_DESCRIBE_BLOCK = (0, _utils.makeDescribe)(ROOT_DESCRIBE_BLOCK_NAME); return { currentDescribeBlock: ROOT_DESCRIBE_BLOCK, currentlyRunningTest: null, expand: undefined, hasFocusedTests: false, hasStarted: false, includeTestLocationInResult: false, maxConcurrency: 5, parentProcess: null, rootDescribeBlock: ROOT_DESCRIBE_BLOCK, seed: 0, testNamePattern: null, testTimeout: 5000, unhandledErrors: [], unhandledRejectionErrorByPromise: new Map() }; }; const getState = () => globalThis[_types.STATE_SYM]; exports.getState = getState; const setState = state => { (0, _jestUtil.setGlobal)(globalThis, _types.STATE_SYM, state); (0, _jestUtil.protectProperties)(state, ['hasFocusedTests', 'hasStarted', 'includeTestLocationInResult', 'maxConcurrency', 'seed', 'testNamePattern', 'testTimeout', 'unhandledErrors', 'unhandledRejectionErrorByPromise']); return state; }; exports.setState = setState; const resetState = () => { setState(createState()); }; exports.resetState = resetState; resetState(); const dispatch = async event => { for (const handler of handlers) { await handler(event, getState()); } }; exports.dispatch = dispatch; const dispatchSync = event => { for (const handler of handlers) { handler(event, getState()); } }; exports.dispatchSync = dispatchSync; const addEventHandler = handler => { handlers.push(handler); }; exports.addEventHandler = addEventHandler; const removeEventHandler = handler => { const index = handlers.lastIndexOf(handler); if (index !== -1) { handlers.splice(index, 1); } }; exports.removeEventHandler = removeEventHandler; /***/ }), /***/ "./src/testCaseReportHandler.ts": /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports["default"] = void 0; var _utils = __webpack_require__("./src/utils.ts"); /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const testCaseReportHandler = (testPath, sendMessageToJest) => event => { switch (event.name) { case 'test_started': { const testCaseStartInfo = (0, _utils.createTestCaseStartInfo)(event.test); sendMessageToJest('test-case-start', [testPath, testCaseStartInfo]); break; } case 'test_todo': case 'test_done': { const testResult = (0, _utils.makeSingleTestResult)(event.test); const testCaseResult = (0, _utils.parseSingleTestResult)(testResult); sendMessageToJest('test-case-result', [testPath, testCaseResult]); break; } } }; var _default = exports["default"] = testCaseReportHandler; /***/ }), /***/ "./src/types.ts": /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.WAIT_BEFORE_RETRY = exports.TEST_TIMEOUT_SYMBOL = exports.STATE_SYM = exports.RETRY_TIMES = exports.RETRY_IMMEDIATELY = exports.LOG_ERRORS_BEFORE_RETRY = exports.EVENT_HANDLERS = void 0; var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol; /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const STATE_SYM = exports.STATE_SYM = Symbol('JEST_STATE_SYMBOL'); const RETRY_TIMES = exports.RETRY_TIMES = Symbol.for('RETRY_TIMES'); const RETRY_IMMEDIATELY = exports.RETRY_IMMEDIATELY = Symbol.for('RETRY_IMMEDIATELY'); const WAIT_BEFORE_RETRY = exports.WAIT_BEFORE_RETRY = Symbol.for('WAIT_BEFORE_RETRY'); // To pass this value from Runtime object to state we need to use global[sym] const TEST_TIMEOUT_SYMBOL = exports.TEST_TIMEOUT_SYMBOL = Symbol.for('TEST_TIMEOUT_SYMBOL'); const EVENT_HANDLERS = exports.EVENT_HANDLERS = Symbol.for('EVENT_HANDLERS'); const LOG_ERRORS_BEFORE_RETRY = exports.LOG_ERRORS_BEFORE_RETRY = Symbol.for('LOG_ERRORS_BEFORE_RETRY'); /***/ }), /***/ "./src/unhandledRejectionHandler.ts": /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.unhandledRejectionHandler = void 0; var _jestUtil = require("jest-util"); var _utils = __webpack_require__("./src/utils.ts"); var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol; var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol; var Promise = globalThis[Symbol.for('jest-native-promise')] || globalThis.Promise; /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ // Global values can be overwritten by mocks or tests. We'll capture // the original values in the variables before we require any files. const { setTimeout } = globalThis; const untilNextEventLoopTurn = async () => { return new Promise(resolve => { setTimeout(resolve, 0); }); }; const unhandledRejectionHandler = (runtime, waitForUnhandledRejections) => { return async (event, state) => { if (event.name === 'hook_start') { runtime.enterTestCode(); } else if (event.name === 'hook_success' || event.name === 'hook_failure') { runtime.leaveTestCode(); if (waitForUnhandledRejections) { // We need to give event loop the time to actually execute `rejectionHandled`, `uncaughtException` or `unhandledRejection` events await untilNextEventLoopTurn(); } const { test, describeBlock, hook } = event; const { asyncError, type } = hook; if (type === 'beforeAll') { (0, _jestUtil.invariant)(describeBlock, 'always present for `*All` hooks'); for (const error of state.unhandledRejectionErrorByPromise.values()) { (0, _utils.addErrorToEachTestUnderDescribe)(describeBlock, error, asyncError); } } else if (type === 'afterAll') { // Attaching `afterAll` errors to each test makes execution flow // too complicated, so we'll consider them to be global. for (const error of state.unhandledRejectionErrorByPromise.values()) { state.unhandledErrors.push([error, asyncError]); } } else { (0, _jestUtil.invariant)(test, 'always present for `*Each` hooks'); for (const error of test.unhandledRejectionErrorByPromise.values()) { test.errors.push([error, asyncError]); } } } else if (event.name === 'test_fn_start') { runtime.enterTestCode(); } else if (event.name === 'test_fn_success' || event.name === 'test_fn_failure') { runtime.leaveTestCode(); if (waitForUnhandledRejections) { // We need to give event loop the time to actually execute `rejectionHandled`, `uncaughtException` or `unhandledRejection` events await untilNextEventLoopTurn(); } const { test } = event; (0, _jestUtil.invariant)(test, 'always present for `*Each` hooks'); for (const error of test.unhandledRejectionErrorByPromise.values()) { test.errors.push([error, event.test.asyncError]); } } else if (event.name === 'teardown') { if (waitForUnhandledRejections) { // We need to give event loop the time to actually execute `rejectionHandled`, `uncaughtException` or `unhandledRejection` events await untilNextEventLoopTurn(); } state.unhandledErrors.push(...state.unhandledRejectionErrorByPromise.values()); } }; }; exports.unhandledRejectionHandler = unhandledRejectionHandler; /***/ }), /***/ "./src/utils.ts": /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.parseSingleTestResult = exports.makeTest = exports.makeSingleTestResult = exports.makeRunResult = exports.makeDescribe = exports.getTestID = exports.getTestDuration = exports.getEachHooksForTest = exports.getAllHooksForDescribe = exports.describeBlockHasTests = exports.createTestCaseStartInfo = exports.callAsyncCircusFn = exports.addErrorToEachTestUnderDescribe = void 0; var path = _interopRequireWildcard(require("path")); var _co = _interopRequireDefault(require("co")); var _dedent = _interopRequireDefault(require("dedent")); var _isGeneratorFn = _interopRequireDefault(require("is-generator-fn")); var _slash = _interopRequireDefault(require("slash")); var _stackUtils = _interopRequireDefault(require("stack-utils")); var _jestUtil = require("jest-util"); var _prettyFormat = require("pretty-format"); var _state = __webpack_require__("./src/state.ts"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol; var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol; var jestNow = globalThis[Symbol.for('jest-native-now')] || globalThis.Date.now; var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol; var Promise = globalThis[Symbol.for('jest-native-promise')] || globalThis.Promise; /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const stackUtils = new _stackUtils.default({ cwd: 'A path that does not exist' }); const jestEachBuildDir = (0, _slash.default)(path.dirname(require.resolve('jest-each'))); function takesDoneCallback(fn) { return fn.length > 0; } function isGeneratorFunction(fn) { return (0, _isGeneratorFn.default)(fn); } const makeDescribe = (name, parent, mode) => { let _mode = mode; if (parent && !mode) { // If not set explicitly, inherit from the parent describe. _mode = parent.mode; } return { type: 'describeBlock', // eslint-disable-next-line sort-keys children: [], hooks: [], mode: _mode, name: (0, _jestUtil.convertDescriptorToString)(name), parent, tests: [] }; }; exports.makeDescribe = makeDescribe; const makeTest = (fn, mode, concurrent, name, parent, timeout, asyncError, failing) => ({ type: 'test', // eslint-disable-next-line sort-keys asyncError, concurrent, duration: null, errors: [], failing, fn, invocations: 0, mode, name: (0, _jestUtil.convertDescriptorToString)(name), numPassingAsserts: 0, parent, retryReasons: [], seenDone: false, startedAt: null, status: null, timeout, unhandledRejectionErrorByPromise: new Map() }); // Traverse the tree of describe blocks and return true if at least one describe // block has an enabled test. exports.makeTest = makeTest; const hasEnabledTest = describeBlock => { const { hasFocusedTests, testNamePattern } = (0, _state.getState)(); return describeBlock.children.some(child => child.type === 'describeBlock' ? hasEnabledTest(child) : !(child.mode === 'skip' || hasFocusedTests && child.mode !== 'only' || testNamePattern && !testNamePattern.test(getTestID(child)))