@@ -39,6 +39,25 @@ class PlaywrightEngine {
39
39
this . processor . $rewriteMetricName = function ( name , _type ) { return name ; }
40
40
}
41
41
42
+ //
43
+ // Tracing:
44
+ // Note that these variables are shared across VUs *within* a single worker thread, as each
45
+ // worker creates its own instance of the engine.
46
+ this . tracesRecordedCount = 0 ; // total count of traces recorded so far
47
+ this . MAX_TRACE_RECORDINGS = 5 ; // total limit on traces we'll record
48
+
49
+ this . enablePlaywrightTracing = typeof process . env . ENABLE_PLAYWRIGHT_TRACING !== 'undefined' ;
50
+
51
+ // We use this to make sure only one VU is recording at one time:
52
+ this . playwrightRecordTraceForNextVU = this . enablePlaywrightTracing ;
53
+
54
+ // We use this to limit the number of recordings that we save:
55
+ this . lastTraceRecordedTime = 0 ; // timestamp of last saved recording
56
+ this . TRACE_RECORDING_INTERVAL_MSEC = 1000 * 60 * 5 ; // minimum interval between saving new recordings
57
+
58
+ this . tracePaths = [ ] ;
59
+ this . traceOutputDir = process . env . PLAYWRIGHT_TRACING_OUTPUT_DIR || '/tmp' ;
60
+
42
61
return this ;
43
62
}
44
63
@@ -98,6 +117,12 @@ class PlaywrightEngine {
98
117
99
118
const context = await browser . newContext ( contextOptions ) ;
100
119
120
+ if ( self . playwrightRecordTraceForNextVU ) {
121
+ self . playwrightRecordTraceForNextVU = false ;
122
+ initialContext . vars . isRecording = true ; // used by the VU to discard the trace if needed
123
+ await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
124
+ }
125
+
101
126
context . setDefaultNavigationTimeout ( self . defaultNavigationTimeout ) ;
102
127
context . setDefaultTimeout ( self . defaultTimeout ) ;
103
128
if ( self . testIdAttribute ) {
@@ -248,22 +273,41 @@ class PlaywrightEngine {
248
273
await traceScenario ( page , initialContext , events , fn , spec . name )
249
274
} else {
250
275
await fn ( page , initialContext , events , test ) ;
251
- }
252
-
276
+ }
253
277
await page . close ( ) ;
254
-
278
+
255
279
if ( cb ) {
256
280
cb ( null , initialContext ) ;
257
281
}
258
282
return initialContext ;
259
283
} catch ( err ) {
260
- console . error ( err ) ;
284
+ if ( initialContext . vars . isRecording ) {
285
+ if ( Date . now ( ) - self . lastTraceRecordedTime > self . TRACE_RECORDING_INTERVAL_MSEC ) {
286
+ const tracePath = `${ self . traceOutputDir } /trace-${ initialContext . vars . $testId } -${ initialContext . vars . $uuid } -${ Date . now ( ) } .zip` ;
287
+ await context . tracing . stop ( { path : tracePath } ) ;
288
+ self . lastTraceRecordedTime = Date . now ( ) ;
289
+ self . tracesRecordedCount ++ ;
290
+ self . tracePaths . push ( tracePath ) ;
291
+ initialContext . vars . isRecording = false ; // for finally{} block
292
+ }
293
+ }
294
+
261
295
if ( cb ) {
262
296
cb ( err , initialContext ) ;
263
297
} else {
264
298
throw err ;
265
299
}
300
+
266
301
} finally {
302
+ if ( self . enablePlaywrightTracing && self . tracesRecordedCount < self . MAX_TRACE_RECORDINGS ) {
303
+ self . playwrightRecordTraceForNextVU = true ;
304
+ }
305
+
306
+ if ( initialContext . vars . isRecording ) {
307
+ // This VU was recording but completed successfully, drop the recording
308
+ await context . tracing . stop ( ) ;
309
+ }
310
+
267
311
await context . close ( ) ;
268
312
269
313
if ( self . useSeparateBrowserPerVU ) {
0 commit comments