jest-circus
Version:
1,424 lines (1,353 loc) • 70.3 kB
JavaScript
/*!
* /**
* * 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)))