'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); exports.invariant = exports.addErrorToEachTestUnderDescribe = exports.getTestID = exports.makeRunResult = exports.getTestDuration = exports.callAsyncCircusFn = exports.describeBlockHasTests = exports.getEachHooksForTest = exports.getAllHooksForDescribe = exports.makeTest = exports.makeDescribe = void 0; var _jestUtil = require('jest-util'); var _isGeneratorFn = _interopRequireDefault(require('is-generator-fn')); var _co = _interopRequireDefault(require('co')); var _stackUtils = _interopRequireDefault(require('stack-utils')); var _prettyFormat = _interopRequireDefault(require('pretty-format')); var _state = require('./state'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : {default: obj}; } var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol; var jestNow = global[Symbol.for('jest-native-now')] || global.Date.now; var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol; var Promise = global[Symbol.for('jest-native-promise')] || global.Promise; var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol; const stackUtils = new _stackUtils.default({ cwd: 'A path that does not exist' }); const makeDescribe = (name, parent, mode) => { let _mode = mode; if (parent && !mode) { // If not set explicitly, inherit from the parent describe. _mode = parent.mode; } return { children: [], hooks: [], mode: _mode, name: (0, _jestUtil.convertDescriptorToString)(name), parent, tests: [] }; }; exports.makeDescribe = makeDescribe; const makeTest = (fn, mode, name, parent, timeout, asyncError) => ({ asyncError, duration: null, errors: [], fn, invocations: 0, mode, name: (0, _jestUtil.convertDescriptorToString)(name), parent, startedAt: null, status: null, timeout }); // 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 _getState = (0, _state.getState)(), hasFocusedTests = _getState.hasFocusedTests, testNamePattern = _getState.testNamePattern; const hasOwnEnabledTests = describeBlock.tests.some( test => !( test.mode === 'skip' || (hasFocusedTests && test.mode !== 'only') || (testNamePattern && !testNamePattern.test(getTestID(test))) ) ); return hasOwnEnabledTests || describeBlock.children.some(hasEnabledTest); }; const getAllHooksForDescribe = describe => { const result = { afterAll: [], beforeAll: [] }; if (hasEnabledTest(describe)) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for ( var _iterator = describe.hooks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true ) { const hook = _step.value; switch (hook.type) { case 'beforeAll': result.beforeAll.push(hook); break; case 'afterAll': result.afterAll.push(hook); break; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } return result; }; exports.getAllHooksForDescribe = getAllHooksForDescribe; const getEachHooksForTest = test => { const result = { afterEach: [], beforeEach: [] }; let block = test.parent; do { const beforeEachForCurrentBlock = []; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for ( var _iterator2 = block.hooks[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true ) { const hook = _step2.value; switch (hook.type) { case 'beforeEach': beforeEachForCurrentBlock.push(hook); break; case 'afterEach': result.afterEach.push(hook); break; } } // 'beforeEach' hooks are executed from top to bottom, the opposite of the // way we traversed it. } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return != null) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } result.beforeEach = [...beforeEachForCurrentBlock, ...result.beforeEach]; } while ((block = block.parent)); return result; }; exports.getEachHooksForTest = getEachHooksForTest; const describeBlockHasTests = describe => describe.tests.length > 0 || describe.children.some(describeBlockHasTests); exports.describeBlockHasTests = describeBlockHasTests; const _makeTimeoutMessage = (timeout, isHook) => `Exceeded timeout of ${timeout}ms for a ${ isHook ? 'hook' : 'test' }.\nUse jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.`; // Global values can be overwritten by mocks or tests. We'll capture // the original values in the variables before we require any files. const _global = global, setTimeout = _global.setTimeout, clearTimeout = _global.clearTimeout; function checkIsError(error) { return !!(error && error.message && error.stack); } const callAsyncCircusFn = (fn, testContext, {isHook, timeout}) => { let timeoutID; let completed = false; return new Promise((resolve, reject) => { timeoutID = setTimeout( () => reject(_makeTimeoutMessage(timeout, !!isHook)), timeout ); // If this fn accepts `done` callback we return a promise that fulfills as // soon as `done` called. if (fn.length) { const done = reason => { const errorAsErrorObject = checkIsError(reason) ? reason : new Error( `Failed: ${(0, _prettyFormat.default)(reason, { maxDepth: 3 })}` ); // Consider always throwing, regardless if `reason` is set or not if (completed && reason) { errorAsErrorObject.message = 'Caught error after test environment was torn down\n\n' + errorAsErrorObject.message; throw errorAsErrorObject; } return reason ? reject(errorAsErrorObject) : resolve(); }; return fn.call(testContext, done); } let returnedValue; if ((0, _isGeneratorFn.default)(fn)) { returnedValue = _co.default.wrap(fn).call({}); } else { try { returnedValue = fn.call(testContext); } catch (error) { return reject(error); } } // If it's a Promise, return it. Test for an object with a `then` function // to support custom Promise implementations. if ( typeof returnedValue === 'object' && returnedValue !== null && typeof returnedValue.then === 'function' ) { return returnedValue.then(resolve, reject); } if (!isHook && returnedValue !== void 0) { return reject( new Error(` test functions can only return Promise or undefined. Returned value: ${String(returnedValue)} `) ); } // Otherwise this test is synchronous, and if it didn't throw it means // it passed. return resolve(); }) .then(() => { completed = true; // If timeout is not cleared/unrefed the node process won't exit until // it's resolved. timeoutID.unref && timeoutID.unref(); clearTimeout(timeoutID); }) .catch(error => { completed = true; timeoutID.unref && timeoutID.unref(); clearTimeout(timeoutID); throw error; }); }; exports.callAsyncCircusFn = callAsyncCircusFn; const getTestDuration = test => { const startedAt = test.startedAt; return typeof startedAt === 'number' ? jestNow() - startedAt : null; }; exports.getTestDuration = getTestDuration; const makeRunResult = (describeBlock, unhandledErrors) => ({ testResults: makeTestResults(describeBlock), unhandledErrors: unhandledErrors.map(_formatError) }); exports.makeRunResult = makeRunResult; const makeTestResults = describeBlock => { const _getState2 = (0, _state.getState)(), includeTestLocationInResult = _getState2.includeTestLocationInResult; let testResults = []; var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for ( var _iterator3 = describeBlock.tests[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true ) { const test = _step3.value; const testPath = []; let parent = test; do { testPath.unshift(parent.name); } while ((parent = parent.parent)); const status = test.status; if (!status) { throw new Error('Status should be present after tests are run.'); } let location = null; if (includeTestLocationInResult) { const stackLine = test.asyncError.stack.split('\n')[1]; const parsedLine = stackUtils.parseLine(stackLine); if ( parsedLine && typeof parsedLine.column === 'number' && typeof parsedLine.line === 'number' ) { location = { column: parsedLine.column, line: parsedLine.line }; } } testResults.push({ duration: test.duration, errors: test.errors.map(_formatError), invocations: test.invocations, location, status, testPath }); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return != null) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for ( var _iterator4 = describeBlock.children[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true ) { const child = _step4.value; testResults = testResults.concat(makeTestResults(child)); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return != null) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } return testResults; }; // Return a string that identifies the test (concat of parent describe block // names + test title) const getTestID = test => { const titles = []; let parent = test; do { titles.unshift(parent.name); } while ((parent = parent.parent)); titles.shift(); // remove TOP_DESCRIBE_BLOCK_NAME return titles.join(' '); }; exports.getTestID = getTestID; const _formatError = errors => { let error; let asyncError; if (Array.isArray(errors)) { error = errors[0]; asyncError = errors[1]; } else { error = errors; asyncError = new Error(); } if (error) { if (error.stack) { return error.stack; } if (error.message) { return error.message; } } asyncError.message = `thrown: ${(0, _prettyFormat.default)(error, { maxDepth: 3 })}`; return asyncError.stack; }; const addErrorToEachTestUnderDescribe = (describeBlock, error, asyncError) => { var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for ( var _iterator5 = describeBlock.tests[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true ) { const test = _step5.value; test.errors.push([error, asyncError]); } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return != null) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for ( var _iterator6 = describeBlock.children[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true ) { const child = _step6.value; addErrorToEachTestUnderDescribe(child, error, asyncError); } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return != null) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } }; exports.addErrorToEachTestUnderDescribe = addErrorToEachTestUnderDescribe; const invariant = (condition, message) => { if (!condition) { throw new Error(message); } }; exports.invariant = invariant;