123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- 'use strict';
- Object.defineProperty(exports, '__esModule', {
- value: true
- });
- exports.default = collectHandles;
- exports.formatHandleErrors = formatHandleErrors;
- function asyncHooks() {
- const data = _interopRequireWildcard(require('async_hooks'));
- asyncHooks = function () {
- return data;
- };
- return data;
- }
- function _util() {
- const data = require('util');
- _util = function () {
- return data;
- };
- return data;
- }
- function _stripAnsi() {
- const data = _interopRequireDefault(require('strip-ansi'));
- _stripAnsi = function () {
- return data;
- };
- return data;
- }
- function _jestMessageUtil() {
- const data = require('jest-message-util');
- _jestMessageUtil = function () {
- return data;
- };
- return data;
- }
- function _jestUtil() {
- const data = require('jest-util');
- _jestUtil = function () {
- return data;
- };
- return data;
- }
- function _interopRequireDefault(obj) {
- return obj && obj.__esModule ? obj : {default: obj};
- }
- function _getRequireWildcardCache(nodeInterop) {
- if (typeof WeakMap !== 'function') return null;
- var cacheBabelInterop = new WeakMap();
- var cacheNodeInterop = new WeakMap();
- return (_getRequireWildcardCache = function (nodeInterop) {
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
- })(nodeInterop);
- }
- function _interopRequireWildcard(obj, nodeInterop) {
- if (!nodeInterop && obj && obj.__esModule) {
- return obj;
- }
- if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
- return {default: obj};
- }
- var cache = _getRequireWildcardCache(nodeInterop);
- if (cache && cache.has(obj)) {
- return cache.get(obj);
- }
- var newObj = {};
- var hasPropertyDescriptor =
- Object.defineProperty && Object.getOwnPropertyDescriptor;
- for (var key in obj) {
- if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
- var desc = hasPropertyDescriptor
- ? Object.getOwnPropertyDescriptor(obj, key)
- : null;
- if (desc && (desc.get || desc.set)) {
- Object.defineProperty(newObj, key, desc);
- } else {
- newObj[key] = obj[key];
- }
- }
- }
- newObj.default = obj;
- if (cache) {
- cache.set(obj, newObj);
- }
- return newObj;
- }
- /**
- * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
- /* eslint-disable local/ban-types-eventually */
- function stackIsFromUser(stack) {
- // Either the test file, or something required by it
- if (stack.includes('Runtime.requireModule')) {
- return true;
- } // jest-jasmine it or describe call
- if (stack.includes('asyncJestTest') || stack.includes('asyncJestLifecycle')) {
- return true;
- } // An async function call from within circus
- if (stack.includes('callAsyncCircusFn')) {
- // jest-circus it or describe call
- return (
- stack.includes('_callCircusTest') || stack.includes('_callCircusHook')
- );
- }
- return false;
- }
- const alwaysActive = () => true; // @ts-expect-error: doesn't exist in v10 typings
- const hasWeakRef = typeof WeakRef === 'function';
- const asyncSleep = (0, _util().promisify)(setTimeout); // Inspired by https://github.com/mafintosh/why-is-node-running/blob/master/index.js
- // Extracted as we want to format the result ourselves
- function collectHandles() {
- const activeHandles = new Map();
- const hook = asyncHooks().createHook({
- destroy(asyncId) {
- activeHandles.delete(asyncId);
- },
- init: function initHook(asyncId, type, triggerAsyncId, resource) {
- // Skip resources that should not generally prevent the process from
- // exiting, not last a meaningfully long time, or otherwise shouldn't be
- // tracked.
- if (
- type === 'PROMISE' ||
- type === 'TIMERWRAP' ||
- type === 'ELDHISTOGRAM' ||
- type === 'PerformanceObserver' ||
- type === 'RANDOMBYTESREQUEST' ||
- type === 'DNSCHANNEL' ||
- type === 'ZLIB'
- ) {
- return;
- }
- const error = new (_jestUtil().ErrorWithStack)(type, initHook, 100);
- let fromUser = stackIsFromUser(error.stack || ''); // If the async resource was not directly created by user code, but was
- // triggered by another async resource from user code, track it and use
- // the original triggering resource's stack.
- if (!fromUser) {
- const triggeringHandle = activeHandles.get(triggerAsyncId);
- if (triggeringHandle) {
- fromUser = true;
- error.stack = triggeringHandle.error.stack;
- }
- }
- if (fromUser) {
- let isActive;
- if (type === 'Timeout' || type === 'Immediate') {
- // Timer that supports hasRef (Node v11+)
- if ('hasRef' in resource) {
- if (hasWeakRef) {
- // @ts-expect-error: doesn't exist in v10 typings
- const ref = new WeakRef(resource);
- isActive = () => {
- var _ref$deref$hasRef, _ref$deref;
- return (_ref$deref$hasRef =
- (_ref$deref = ref.deref()) === null || _ref$deref === void 0
- ? void 0
- : _ref$deref.hasRef()) !== null &&
- _ref$deref$hasRef !== void 0
- ? _ref$deref$hasRef
- : false;
- };
- } else {
- // @ts-expect-error: doesn't exist in v10 typings
- isActive = resource.hasRef.bind(resource);
- }
- } else {
- // Timer that doesn't support hasRef
- isActive = alwaysActive;
- }
- } else {
- // Any other async resource
- isActive = alwaysActive;
- }
- activeHandles.set(asyncId, {
- error,
- isActive
- });
- }
- }
- });
- hook.enable();
- return async () => {
- // Wait briefly for any async resources that have been queued for
- // destruction to actually be destroyed.
- // For example, Node.js TCP Servers are not destroyed until *after* their
- // `close` callback runs. If someone finishes a test from the `close`
- // callback, we will not yet have seen the resource be destroyed here.
- await asyncSleep(100);
- hook.disable(); // Get errors for every async resource still referenced at this moment
- const result = Array.from(activeHandles.values())
- .filter(({isActive}) => isActive())
- .map(({error}) => error);
- activeHandles.clear();
- return result;
- };
- }
- function formatHandleErrors(errors, config) {
- const stacks = new Set();
- return (
- errors
- .map(err =>
- (0, _jestMessageUtil().formatExecError)(
- err,
- config,
- {
- noStackTrace: false
- },
- undefined,
- true
- )
- ) // E.g. timeouts might give multiple traces to the same line of code
- // This hairy filtering tries to remove entries with duplicate stack traces
- .filter(handle => {
- const ansiFree = (0, _stripAnsi().default)(handle);
- const match = ansiFree.match(/\s+at(.*)/);
- if (!match || match.length < 2) {
- return true;
- }
- const stack = ansiFree.substr(ansiFree.indexOf(match[1])).trim();
- if (stacks.has(stack)) {
- return false;
- }
- stacks.add(stack);
- return true;
- })
- );
- }
|