520 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			520 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | '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; |