@@ -83,16 +83,7 @@ export default function collectHandles(): HandleCollectionResult {
83
83
// Skip resources that should not generally prevent the process from
84
84
// exiting, not last a meaningfully long time, or otherwise shouldn't be
85
85
// 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' ) {
96
87
return ;
97
88
}
98
89
const error = new ErrorWithStack ( type , initHook , 100 ) ;
@@ -141,14 +132,18 @@ export default function collectHandles(): HandleCollectionResult {
141
132
// For example, Node.js TCP Servers are not destroyed until *after* their
142
133
// `close` callback runs. If someone finishes a test from the `close`
143
134
// callback, we will not yet have seen the resource be destroyed here.
144
- await asyncSleep ( 100 ) ;
135
+ await asyncSleep ( 0 ) ;
145
136
146
137
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 ) ;
150
139
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
+ }
152
147
}
153
148
154
149
hook . disable ( ) ;
@@ -167,33 +162,44 @@ export function formatHandleErrors(
167
162
errors : Array < Error > ,
168
163
config : Config . ProjectConfig ,
169
164
) : 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
+ ) ;
187
175
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
189
178
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
+ }
193
184
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
+ }
195
201
196
- return true ;
197
- } )
202
+ return Array . from ( stacks . values ( ) ) . map ( ( { stack , names } ) =>
203
+ stack . replace ( '%%OBJECT_NAME%%' , Array . from ( names ) . join ( ',' ) ) ,
198
204
) ;
199
205
}
0 commit comments