in packages/jest-core/src/collectHandles.ts [50:142]
export default function collectHandles(): HandleCollectionResult {
const activeHandles = new Map<
number,
{error: Error; isActive: () => boolean}
>();
const hook = asyncHooks.createHook({
destroy(asyncId) {
activeHandles.delete(asyncId);
},
init: function initHook(
asyncId,
type,
triggerAsyncId,
resource: {} | NodeJS.Timeout,
) {
// 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 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: () => boolean;
if (type === 'Timeout' || type === 'Immediate') {
// Timer that supports hasRef (Node v11+)
if ('hasRef' in resource) {
if (hasWeakRef) {
// @ts-expect-error: doesn't exist in v12 typings
const ref = new WeakRef(resource);
isActive = () => {
return ref.deref()?.hasRef() ?? false;
};
} else {
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;
};
}