UNPKG

7.39 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6exports.default = collectHandles;
7exports.formatHandleErrors = formatHandleErrors;
8
9function asyncHooks() {
10 const data = _interopRequireWildcard(require('async_hooks'));
11
12 asyncHooks = function () {
13 return data;
14 };
15
16 return data;
17}
18
19function _util() {
20 const data = require('util');
21
22 _util = function () {
23 return data;
24 };
25
26 return data;
27}
28
29function _stripAnsi() {
30 const data = _interopRequireDefault(require('strip-ansi'));
31
32 _stripAnsi = function () {
33 return data;
34 };
35
36 return data;
37}
38
39function _jestMessageUtil() {
40 const data = require('jest-message-util');
41
42 _jestMessageUtil = function () {
43 return data;
44 };
45
46 return data;
47}
48
49function _jestUtil() {
50 const data = require('jest-util');
51
52 _jestUtil = function () {
53 return data;
54 };
55
56 return data;
57}
58
59function _interopRequireDefault(obj) {
60 return obj && obj.__esModule ? obj : {default: obj};
61}
62
63function _getRequireWildcardCache(nodeInterop) {
64 if (typeof WeakMap !== 'function') return null;
65 var cacheBabelInterop = new WeakMap();
66 var cacheNodeInterop = new WeakMap();
67 return (_getRequireWildcardCache = function (nodeInterop) {
68 return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
69 })(nodeInterop);
70}
71
72function _interopRequireWildcard(obj, nodeInterop) {
73 if (!nodeInterop && obj && obj.__esModule) {
74 return obj;
75 }
76 if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
77 return {default: obj};
78 }
79 var cache = _getRequireWildcardCache(nodeInterop);
80 if (cache && cache.has(obj)) {
81 return cache.get(obj);
82 }
83 var newObj = {};
84 var hasPropertyDescriptor =
85 Object.defineProperty && Object.getOwnPropertyDescriptor;
86 for (var key in obj) {
87 if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
88 var desc = hasPropertyDescriptor
89 ? Object.getOwnPropertyDescriptor(obj, key)
90 : null;
91 if (desc && (desc.get || desc.set)) {
92 Object.defineProperty(newObj, key, desc);
93 } else {
94 newObj[key] = obj[key];
95 }
96 }
97 }
98 newObj.default = obj;
99 if (cache) {
100 cache.set(obj, newObj);
101 }
102 return newObj;
103}
104
105/**
106 * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
107 *
108 * This source code is licensed under the MIT license found in the
109 * LICENSE file in the root directory of this source tree.
110 */
111
112/* eslint-disable local/ban-types-eventually */
113function stackIsFromUser(stack) {
114 // Either the test file, or something required by it
115 if (stack.includes('Runtime.requireModule')) {
116 return true;
117 } // jest-jasmine it or describe call
118
119 if (stack.includes('asyncJestTest') || stack.includes('asyncJestLifecycle')) {
120 return true;
121 } // An async function call from within circus
122
123 if (stack.includes('callAsyncCircusFn')) {
124 // jest-circus it or describe call
125 return (
126 stack.includes('_callCircusTest') || stack.includes('_callCircusHook')
127 );
128 }
129
130 return false;
131}
132
133const alwaysActive = () => true; // @ts-expect-error: doesn't exist in v10 typings
134
135const hasWeakRef = typeof WeakRef === 'function';
136const asyncSleep = (0, _util().promisify)(setTimeout); // Inspired by https://github.com/mafintosh/why-is-node-running/blob/master/index.js
137// Extracted as we want to format the result ourselves
138
139function collectHandles() {
140 const activeHandles = new Map();
141 const hook = asyncHooks().createHook({
142 destroy(asyncId) {
143 activeHandles.delete(asyncId);
144 },
145
146 init: function initHook(asyncId, type, triggerAsyncId, resource) {
147 // Skip resources that should not generally prevent the process from
148 // exiting, not last a meaningfully long time, or otherwise shouldn't be
149 // tracked.
150 if (
151 type === 'PROMISE' ||
152 type === 'TIMERWRAP' ||
153 type === 'ELDHISTOGRAM' ||
154 type === 'PerformanceObserver' ||
155 type === 'RANDOMBYTESREQUEST' ||
156 type === 'DNSCHANNEL'
157 ) {
158 return;
159 }
160
161 const error = new (_jestUtil().ErrorWithStack)(type, initHook, 100);
162 let fromUser = stackIsFromUser(error.stack || ''); // If the async resource was not directly created by user code, but was
163 // triggered by another async resource from user code, track it and use
164 // the original triggering resource's stack.
165
166 if (!fromUser) {
167 const triggeringHandle = activeHandles.get(triggerAsyncId);
168
169 if (triggeringHandle) {
170 fromUser = true;
171 error.stack = triggeringHandle.error.stack;
172 }
173 }
174
175 if (fromUser) {
176 let isActive;
177
178 if (type === 'Timeout' || type === 'Immediate') {
179 // Timer that supports hasRef (Node v11+)
180 if ('hasRef' in resource) {
181 if (hasWeakRef) {
182 // @ts-expect-error: doesn't exist in v10 typings
183 const ref = new WeakRef(resource);
184
185 isActive = () => {
186 var _ref$deref$hasRef, _ref$deref;
187
188 return (_ref$deref$hasRef =
189 (_ref$deref = ref.deref()) === null || _ref$deref === void 0
190 ? void 0
191 : _ref$deref.hasRef()) !== null &&
192 _ref$deref$hasRef !== void 0
193 ? _ref$deref$hasRef
194 : false;
195 };
196 } else {
197 // @ts-expect-error: doesn't exist in v10 typings
198 isActive = resource.hasRef.bind(resource);
199 }
200 } else {
201 // Timer that doesn't support hasRef
202 isActive = alwaysActive;
203 }
204 } else {
205 // Any other async resource
206 isActive = alwaysActive;
207 }
208
209 activeHandles.set(asyncId, {
210 error,
211 isActive
212 });
213 }
214 }
215 });
216 hook.enable();
217 return async () => {
218 // Wait briefly for any async resources that have been queued for
219 // destruction to actually be destroyed.
220 // For example, Node.js TCP Servers are not destroyed until *after* their
221 // `close` callback runs. If someone finishes a test from the `close`
222 // callback, we will not yet have seen the resource be destroyed here.
223 await asyncSleep(100);
224 hook.disable(); // Get errors for every async resource still referenced at this moment
225
226 const result = Array.from(activeHandles.values())
227 .filter(({isActive}) => isActive())
228 .map(({error}) => error);
229 activeHandles.clear();
230 return result;
231 };
232}
233
234function formatHandleErrors(errors, config) {
235 const stacks = new Set();
236 return (
237 errors
238 .map(err =>
239 (0, _jestMessageUtil().formatExecError)(
240 err,
241 config,
242 {
243 noStackTrace: false
244 },
245 undefined,
246 true
247 )
248 ) // E.g. timeouts might give multiple traces to the same line of code
249 // This hairy filtering tries to remove entries with duplicate stack traces
250 .filter(handle => {
251 const ansiFree = (0, _stripAnsi().default)(handle);
252 const match = ansiFree.match(/\s+at(.*)/);
253
254 if (!match || match.length < 2) {
255 return true;
256 }
257
258 const stack = ansiFree.substr(ansiFree.indexOf(match[1])).trim();
259
260 if (stacks.has(stack)) {
261 return false;
262 }
263
264 stacks.add(stack);
265 return true;
266 })
267 );
268}