collectHandles.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = collectHandles;
  6. exports.formatHandleErrors = formatHandleErrors;
  7. function asyncHooks() {
  8. const data = _interopRequireWildcard(require('async_hooks'));
  9. asyncHooks = function () {
  10. return data;
  11. };
  12. return data;
  13. }
  14. function _stripAnsi() {
  15. const data = _interopRequireDefault(require('strip-ansi'));
  16. _stripAnsi = function () {
  17. return data;
  18. };
  19. return data;
  20. }
  21. function _jestMessageUtil() {
  22. const data = require('jest-message-util');
  23. _jestMessageUtil = function () {
  24. return data;
  25. };
  26. return data;
  27. }
  28. function _jestUtil() {
  29. const data = require('jest-util');
  30. _jestUtil = function () {
  31. return data;
  32. };
  33. return data;
  34. }
  35. function _interopRequireDefault(obj) {
  36. return obj && obj.__esModule ? obj : {default: obj};
  37. }
  38. function _getRequireWildcardCache() {
  39. if (typeof WeakMap !== 'function') return null;
  40. var cache = new WeakMap();
  41. _getRequireWildcardCache = function () {
  42. return cache;
  43. };
  44. return cache;
  45. }
  46. function _interopRequireWildcard(obj) {
  47. if (obj && obj.__esModule) {
  48. return obj;
  49. }
  50. if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
  51. return {default: obj};
  52. }
  53. var cache = _getRequireWildcardCache();
  54. if (cache && cache.has(obj)) {
  55. return cache.get(obj);
  56. }
  57. var newObj = {};
  58. var hasPropertyDescriptor =
  59. Object.defineProperty && Object.getOwnPropertyDescriptor;
  60. for (var key in obj) {
  61. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  62. var desc = hasPropertyDescriptor
  63. ? Object.getOwnPropertyDescriptor(obj, key)
  64. : null;
  65. if (desc && (desc.get || desc.set)) {
  66. Object.defineProperty(newObj, key, desc);
  67. } else {
  68. newObj[key] = obj[key];
  69. }
  70. }
  71. }
  72. newObj.default = obj;
  73. if (cache) {
  74. cache.set(obj, newObj);
  75. }
  76. return newObj;
  77. }
  78. /**
  79. * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  80. *
  81. * This source code is licensed under the MIT license found in the
  82. * LICENSE file in the root directory of this source tree.
  83. */
  84. /* eslint-disable local/ban-types-eventually */
  85. function stackIsFromUser(stack) {
  86. // Either the test file, or something required by it
  87. if (stack.includes('Runtime.requireModule')) {
  88. return true;
  89. } // jest-jasmine it or describe call
  90. if (stack.includes('asyncJestTest') || stack.includes('asyncJestLifecycle')) {
  91. return true;
  92. } // An async function call from within circus
  93. if (stack.includes('callAsyncCircusFn')) {
  94. // jest-circus it or describe call
  95. return (
  96. stack.includes('_callCircusTest') || stack.includes('_callCircusHook')
  97. );
  98. }
  99. return false;
  100. }
  101. const alwaysActive = () => true; // Inspired by https://github.com/mafintosh/why-is-node-running/blob/master/index.js
  102. // Extracted as we want to format the result ourselves
  103. function collectHandles() {
  104. const activeHandles = new Map();
  105. const hook = asyncHooks().createHook({
  106. destroy(asyncId) {
  107. activeHandles.delete(asyncId);
  108. },
  109. init: function initHook(asyncId, type, _triggerAsyncId, resource) {
  110. if (
  111. type === 'PROMISE' ||
  112. type === 'TIMERWRAP' ||
  113. type === 'ELDHISTOGRAM'
  114. ) {
  115. return;
  116. }
  117. const error = new (_jestUtil().ErrorWithStack)(type, initHook);
  118. if (stackIsFromUser(error.stack || '')) {
  119. let isActive;
  120. if (type === 'Timeout' || type === 'Immediate') {
  121. if ('hasRef' in resource) {
  122. // Timer that supports hasRef (Node v11+)
  123. // @ts-expect-error: doesn't exist in v10 typings
  124. isActive = resource.hasRef.bind(resource);
  125. } else {
  126. // Timer that doesn't support hasRef
  127. isActive = alwaysActive;
  128. }
  129. } else {
  130. // Any other async resource
  131. isActive = alwaysActive;
  132. }
  133. activeHandles.set(asyncId, {
  134. error,
  135. isActive
  136. });
  137. }
  138. }
  139. });
  140. hook.enable();
  141. return () => {
  142. hook.disable(); // Get errors for every async resource still referenced at this moment
  143. const result = Array.from(activeHandles.values())
  144. .filter(({isActive}) => isActive())
  145. .map(({error}) => error);
  146. activeHandles.clear();
  147. return result;
  148. };
  149. }
  150. function formatHandleErrors(errors, config) {
  151. const stacks = new Set();
  152. return (
  153. errors
  154. .map(err =>
  155. (0, _jestMessageUtil().formatExecError)(
  156. err,
  157. config,
  158. {
  159. noStackTrace: false
  160. },
  161. undefined,
  162. true
  163. )
  164. ) // E.g. timeouts might give multiple traces to the same line of code
  165. // This hairy filtering tries to remove entries with duplicate stack traces
  166. .filter(handle => {
  167. const ansiFree = (0, _stripAnsi().default)(handle);
  168. const match = ansiFree.match(/\s+at(.*)/);
  169. if (!match || match.length < 2) {
  170. return true;
  171. }
  172. const stack = ansiFree.substr(ansiFree.indexOf(match[1])).trim();
  173. if (stacks.has(stack)) {
  174. return false;
  175. }
  176. stacks.add(stack);
  177. return true;
  178. })
  179. );
  180. }