@@ -411,6 +411,187 @@ describe('_INTERNAL_captureLog', () => {
411
411
beforeCaptureLogSpy . mockRestore ( ) ;
412
412
} ) ;
413
413
414
+ describe ( 'replay integration with onlyIfSampled' , ( ) => {
415
+ it ( 'includes replay ID for sampled sessions' , ( ) => {
416
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , enableLogs : true } ) ;
417
+ const client = new TestClient ( options ) ;
418
+ const scope = new Scope ( ) ;
419
+ scope . setClient ( client ) ;
420
+
421
+ // Mock replay integration with sampled session
422
+ const mockReplayIntegration = {
423
+ getReplayId : vi . fn ( ( onlyIfSampled ?: boolean ) => {
424
+ // Simulate behavior: return ID for sampled sessions
425
+ return onlyIfSampled ? 'sampled-replay-id' : 'any-replay-id' ;
426
+ } ) ,
427
+ } ;
428
+
429
+ vi . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( mockReplayIntegration as any ) ;
430
+
431
+ _INTERNAL_captureLog ( { level : 'info' , message : 'test log with sampled replay' } , scope ) ;
432
+
433
+ // Verify getReplayId was called with onlyIfSampled=true
434
+ expect ( mockReplayIntegration . getReplayId ) . toHaveBeenCalledWith ( true ) ;
435
+
436
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
437
+ expect ( logAttributes ) . toEqual ( {
438
+ 'sentry.replay_id' : {
439
+ value : 'sampled-replay-id' ,
440
+ type : 'string' ,
441
+ } ,
442
+ } ) ;
443
+ } ) ;
444
+
445
+ it ( 'excludes replay ID for unsampled sessions when onlyIfSampled=true' , ( ) => {
446
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , enableLogs : true } ) ;
447
+ const client = new TestClient ( options ) ;
448
+ const scope = new Scope ( ) ;
449
+ scope . setClient ( client ) ;
450
+
451
+ // Mock replay integration with unsampled session
452
+ const mockReplayIntegration = {
453
+ getReplayId : vi . fn ( ( onlyIfSampled ?: boolean ) => {
454
+ // Simulate behavior: return undefined for unsampled when onlyIfSampled=true
455
+ return onlyIfSampled ? undefined : 'unsampled-replay-id' ;
456
+ } ) ,
457
+ } ;
458
+
459
+ vi . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( mockReplayIntegration as any ) ;
460
+
461
+ _INTERNAL_captureLog ( { level : 'info' , message : 'test log with unsampled replay' } , scope ) ;
462
+
463
+ // Verify getReplayId was called with onlyIfSampled=true
464
+ expect ( mockReplayIntegration . getReplayId ) . toHaveBeenCalledWith ( true ) ;
465
+
466
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
467
+ // Should not include sentry.replay_id attribute
468
+ expect ( logAttributes ) . toEqual ( { } ) ;
469
+ } ) ;
470
+
471
+ it ( 'includes replay ID for buffer mode sessions' , ( ) => {
472
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , enableLogs : true } ) ;
473
+ const client = new TestClient ( options ) ;
474
+ const scope = new Scope ( ) ;
475
+ scope . setClient ( client ) ;
476
+
477
+ // Mock replay integration with buffer mode session
478
+ const mockReplayIntegration = {
479
+ getReplayId : vi . fn ( ( _onlyIfSampled ?: boolean ) => {
480
+ // Buffer mode should still return ID even with onlyIfSampled=true
481
+ return 'buffer-replay-id' ;
482
+ } ) ,
483
+ } ;
484
+
485
+ vi . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( mockReplayIntegration as any ) ;
486
+
487
+ _INTERNAL_captureLog ( { level : 'info' , message : 'test log with buffer replay' } , scope ) ;
488
+
489
+ expect ( mockReplayIntegration . getReplayId ) . toHaveBeenCalledWith ( true ) ;
490
+
491
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
492
+ expect ( logAttributes ) . toEqual ( {
493
+ 'sentry.replay_id' : {
494
+ value : 'buffer-replay-id' ,
495
+ type : 'string' ,
496
+ } ,
497
+ } ) ;
498
+ } ) ;
499
+
500
+ it ( 'handles missing replay integration gracefully' , ( ) => {
501
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , enableLogs : true } ) ;
502
+ const client = new TestClient ( options ) ;
503
+ const scope = new Scope ( ) ;
504
+ scope . setClient ( client ) ;
505
+
506
+ // Mock no replay integration found
507
+ vi . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( undefined ) ;
508
+
509
+ _INTERNAL_captureLog ( { level : 'info' , message : 'test log without replay' } , scope ) ;
510
+
511
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
512
+ // Should not include sentry.replay_id attribute
513
+ expect ( logAttributes ) . toEqual ( { } ) ;
514
+ } ) ;
515
+
516
+ it ( 'combines replay ID with other log attributes' , ( ) => {
517
+ const options = getDefaultTestClientOptions ( {
518
+ dsn : PUBLIC_DSN ,
519
+ enableLogs : true ,
520
+ release : '1.0.0' ,
521
+ environment : 'test' ,
522
+ } ) ;
523
+ const client = new TestClient ( options ) ;
524
+ const scope = new Scope ( ) ;
525
+ scope . setClient ( client ) ;
526
+
527
+ // Mock replay integration
528
+ const mockReplayIntegration = {
529
+ getReplayId : vi . fn ( ( ) => 'test-replay-id' ) ,
530
+ } ;
531
+
532
+ vi . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( mockReplayIntegration as any ) ;
533
+
534
+ _INTERNAL_captureLog (
535
+ {
536
+ level : 'info' ,
537
+ message : 'test log with replay and other attributes' ,
538
+ attributes : { component : 'auth' , action : 'login' } ,
539
+ } ,
540
+ scope ,
541
+ ) ;
542
+
543
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
544
+ expect ( logAttributes ) . toEqual ( {
545
+ component : {
546
+ value : 'auth' ,
547
+ type : 'string' ,
548
+ } ,
549
+ action : {
550
+ value : 'login' ,
551
+ type : 'string' ,
552
+ } ,
553
+ 'sentry.release' : {
554
+ value : '1.0.0' ,
555
+ type : 'string' ,
556
+ } ,
557
+ 'sentry.environment' : {
558
+ value : 'test' ,
559
+ type : 'string' ,
560
+ } ,
561
+ 'sentry.replay_id' : {
562
+ value : 'test-replay-id' ,
563
+ type : 'string' ,
564
+ } ,
565
+ } ) ;
566
+ } ) ;
567
+
568
+ it ( 'does not set replay ID attribute when getReplayId returns null or undefined' , ( ) => {
569
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , enableLogs : true } ) ;
570
+ const client = new TestClient ( options ) ;
571
+ const scope = new Scope ( ) ;
572
+ scope . setClient ( client ) ;
573
+
574
+ const testCases = [ null , undefined ] ;
575
+
576
+ testCases . forEach ( returnValue => {
577
+ // Clear buffer for each test
578
+ _INTERNAL_getLogBuffer ( client ) ?. splice ( 0 ) ;
579
+
580
+ const mockReplayIntegration = {
581
+ getReplayId : vi . fn ( ( ) => returnValue ) ,
582
+ } ;
583
+
584
+ vi . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( mockReplayIntegration as any ) ;
585
+
586
+ _INTERNAL_captureLog ( { level : 'info' , message : `test log with replay returning ${ returnValue } ` } , scope ) ;
587
+
588
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
589
+ expect ( logAttributes ) . toEqual ( { } ) ;
590
+ expect ( logAttributes ) . not . toHaveProperty ( 'sentry.replay_id' ) ;
591
+ } ) ;
592
+ } ) ;
593
+ } ) ;
594
+
414
595
describe ( 'user functionality' , ( ) => {
415
596
it ( 'includes user data in log attributes' , ( ) => {
416
597
const options = getDefaultTestClientOptions ( {
0 commit comments