@@ -411,6 +411,187 @@ describe('_INTERNAL_captureLog', () => {
411411 beforeCaptureLogSpy . mockRestore ( ) ;
412412 } ) ;
413413
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+
414595 describe ( 'user functionality' , ( ) => {
415596 it ( 'includes user data in log attributes' , ( ) => {
416597 const options = getDefaultTestClientOptions ( {
0 commit comments