@@ -83,16 +83,7 @@ export default function collectHandles(): HandleCollectionResult {
8383 // Skip resources that should not generally prevent the process from
8484 // exiting, not last a meaningfully long time, or otherwise shouldn't be
8585 // tracked.
86- if (
87- type === 'PROMISE' ||
88- type === 'TIMERWRAP' ||
89- type === 'ELDHISTOGRAM' ||
90- type === 'PerformanceObserver' ||
91- type === 'RANDOMBYTESREQUEST' ||
92- type === 'DNSCHANNEL' ||
93- type === 'ZLIB' ||
94- type === 'SIGNREQUEST'
95- ) {
86+ if ( type === 'PROMISE' ) {
9687 return ;
9788 }
9889 const error = new ErrorWithStack ( type , initHook , 100 ) ;
@@ -141,14 +132,18 @@ export default function collectHandles(): HandleCollectionResult {
141132 // For example, Node.js TCP Servers are not destroyed until *after* their
142133 // `close` callback runs. If someone finishes a test from the `close`
143134 // callback, we will not yet have seen the resource be destroyed here.
144- await asyncSleep ( 100 ) ;
135+ await asyncSleep ( 0 ) ;
145136
146137 if ( activeHandles . size > 0 ) {
147- // For some special objects such as `TLSWRAP`.
148- // Ref: https://github.com/jestjs/jest/issues/11665
149- runGC ( ) ;
138+ await asyncSleep ( 30 ) ;
150139
151- await asyncSleep ( 0 ) ;
140+ if ( activeHandles . size > 0 ) {
141+ // For some special objects such as `TLSWRAP`.
142+ // Ref: https://github.com/jestjs/jest/issues/11665
143+ runGC ( ) ;
144+
145+ await asyncSleep ( 0 ) ;
146+ }
152147 }
153148
154149 hook . disable ( ) ;
@@ -167,33 +162,44 @@ export function formatHandleErrors(
167162 errors : Array < Error > ,
168163 config : Config . ProjectConfig ,
169164) : Array < string > {
170- const stacks = new Set ( ) ;
171-
172- return (
173- errors
174- . map ( err =>
175- formatExecError ( err , config , { noStackTrace : false } , undefined , true ) ,
176- )
177- // E.g. timeouts might give multiple traces to the same line of code
178- // This hairy filtering tries to remove entries with duplicate stack traces
179- . filter ( handle => {
180- const ansiFree : string = stripAnsi ( handle ) ;
181-
182- const match = ansiFree . match ( / \s + a t ( .* ) / ) ;
183-
184- if ( ! match || match . length < 2 ) {
185- return true ;
186- }
165+ const stacks = new Map < string , { stack : string ; names : Set < string > } > ( ) ;
166+
167+ for ( const err of errors ) {
168+ const formatted = formatExecError (
169+ err ,
170+ config ,
171+ { noStackTrace : false } ,
172+ undefined ,
173+ true ,
174+ ) ;
187175
188- const stack = ansiFree . substr ( ansiFree . indexOf ( match [ 1 ] ) ) . trim ( ) ;
176+ // E.g. timeouts might give multiple traces to the same line of code
177+ // This hairy filtering tries to remove entries with duplicate stack traces
189178
190- if ( stacks . has ( stack ) ) {
191- return false ;
192- }
179+ const ansiFree : string = stripAnsi ( formatted ) ;
180+ const match = ansiFree . match ( / \s + a t ( .* ) / ) ;
181+ if ( ! match || match . length < 2 ) {
182+ continue ;
183+ }
193184
194- stacks . add ( stack ) ;
185+ const stackText = ansiFree . slice ( ansiFree . indexOf ( match [ 1 ] ) ) . trim ( ) ;
186+
187+ const name = ansiFree . match ( / (?< = ● { 2 } ) .* $ / m) ;
188+ if ( name == null || name . length === 0 ) {
189+ continue ;
190+ }
191+
192+ const stack = stacks . get ( stackText ) || {
193+ names : new Set ( ) ,
194+ stack : formatted . replace ( name [ 0 ] , '%%OBJECT_NAME%%' ) ,
195+ } ;
196+
197+ stack . names . add ( name [ 0 ] ) ;
198+
199+ stacks . set ( stackText , stack ) ;
200+ }
195201
196- return true ;
197- } )
202+ return Array . from ( stacks . values ( ) ) . map ( ( { stack , names } ) =>
203+ stack . replace ( '%%OBJECT_NAME%%' , Array . from ( names ) . join ( ',' ) ) ,
198204 ) ;
199205}
0 commit comments