@@ -446,15 +446,14 @@ describe("breadcrumbs", function() {
446
446
} ) ;
447
447
} ) ;
448
448
449
- it ( "should bail out if accessing the `type` and ` target` properties of an event throw an exception" , function ( ) {
449
+ it ( "should bail out if accessing the `target` property of an event throws an exception" , function ( ) {
450
450
// see: https://github.com/getsentry/sentry-javascript/issues/768
451
451
return runInSandbox ( sandbox , function ( ) {
452
452
// click <input/>
453
453
var click = new MouseEvent ( "click" ) ;
454
454
function kaboom ( ) {
455
455
throw new Error ( "lol" ) ;
456
456
}
457
- Object . defineProperty ( click , "type" , { get : kaboom } ) ;
458
457
Object . defineProperty ( click , "target" , { get : kaboom } ) ;
459
458
460
459
var input = document . querySelector ( ".a" ) ; // leaf node
@@ -500,6 +499,121 @@ describe("breadcrumbs", function() {
500
499
} ) ;
501
500
} ) ;
502
501
502
+ it ( "should correctly capture multiple consecutive breadcrumbs if they are of different type" , function ( ) {
503
+ return runInSandbox ( sandbox , function ( ) {
504
+ var input = document . getElementsByTagName ( "input" ) [ 0 ] ;
505
+
506
+ var clickHandler = function ( ) { } ;
507
+ input . addEventListener ( "click" , clickHandler ) ;
508
+ var keypressHandler = function ( ) { } ;
509
+ input . addEventListener ( "keypress" , keypressHandler ) ;
510
+
511
+ input . dispatchEvent ( new MouseEvent ( "click" ) ) ;
512
+ input . dispatchEvent ( new KeyboardEvent ( "keypress" ) ) ;
513
+
514
+ Sentry . captureMessage ( "test" ) ;
515
+ } ) . then ( function ( summary ) {
516
+ if ( IS_LOADER ) {
517
+ // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs
518
+ assert . lengthOf ( summary . events , 1 ) ;
519
+ } else {
520
+ // Breadcrumb should be captured by the global event listeners, not a specific one
521
+ assert . equal ( summary . breadcrumbs . length , 2 ) ;
522
+ assert . equal ( summary . breadcrumbs [ 0 ] . category , "ui.click" ) ;
523
+ assert . equal (
524
+ summary . breadcrumbs [ 0 ] . message ,
525
+ 'body > form#foo-form > input[name="foo"]'
526
+ ) ;
527
+ assert . equal ( summary . breadcrumbs [ 1 ] . category , "ui.input" ) ;
528
+ assert . equal (
529
+ summary . breadcrumbs [ 0 ] . message ,
530
+ 'body > form#foo-form > input[name="foo"]'
531
+ ) ;
532
+ assert . equal ( summary . breadcrumbHints [ 0 ] . global , false ) ;
533
+ assert . equal ( summary . breadcrumbHints [ 1 ] . global , false ) ;
534
+ assert . isUndefined ( summary . events [ 0 ] . exception ) ;
535
+ }
536
+ } ) ;
537
+ } ) ;
538
+
539
+ it ( "should debounce multiple consecutive identical breadcrumbs but allow for switching to a different type" , function ( ) {
540
+ return runInSandbox ( sandbox , function ( ) {
541
+ var input = document . getElementsByTagName ( "input" ) [ 0 ] ;
542
+
543
+ var clickHandler = function ( ) { } ;
544
+ input . addEventListener ( "click" , clickHandler ) ;
545
+ var keypressHandler = function ( ) { } ;
546
+ input . addEventListener ( "keypress" , keypressHandler ) ;
547
+
548
+ input . dispatchEvent ( new MouseEvent ( "click" ) ) ;
549
+ input . dispatchEvent ( new MouseEvent ( "click" ) ) ;
550
+ input . dispatchEvent ( new MouseEvent ( "click" ) ) ;
551
+ input . dispatchEvent ( new KeyboardEvent ( "keypress" ) ) ;
552
+ input . dispatchEvent ( new KeyboardEvent ( "keypress" ) ) ;
553
+ input . dispatchEvent ( new KeyboardEvent ( "keypress" ) ) ;
554
+
555
+ Sentry . captureMessage ( "test" ) ;
556
+ } ) . then ( function ( summary ) {
557
+ if ( IS_LOADER ) {
558
+ // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs
559
+ assert . lengthOf ( summary . events , 1 ) ;
560
+ } else {
561
+ // Breadcrumb should be captured by the global event listeners, not a specific one
562
+ assert . equal ( summary . breadcrumbs . length , 2 ) ;
563
+ assert . equal ( summary . breadcrumbs [ 0 ] . category , "ui.click" ) ;
564
+ assert . equal (
565
+ summary . breadcrumbs [ 0 ] . message ,
566
+ 'body > form#foo-form > input[name="foo"]'
567
+ ) ;
568
+ assert . equal ( summary . breadcrumbs [ 1 ] . category , "ui.input" ) ;
569
+ assert . equal (
570
+ summary . breadcrumbs [ 0 ] . message ,
571
+ 'body > form#foo-form > input[name="foo"]'
572
+ ) ;
573
+ assert . equal ( summary . breadcrumbHints [ 0 ] . global , false ) ;
574
+ assert . equal ( summary . breadcrumbHints [ 1 ] . global , false ) ;
575
+ assert . isUndefined ( summary . events [ 0 ] . exception ) ;
576
+ }
577
+ } ) ;
578
+ } ) ;
579
+
580
+ it ( "should debounce multiple consecutive identical breadcrumbs but allow for switching to a different target" , function ( ) {
581
+ return runInSandbox ( sandbox , function ( ) {
582
+ var input = document . querySelector ( "#foo-form input" ) ;
583
+ var div = document . querySelector ( "#foo-form div" ) ;
584
+
585
+ var clickHandler = function ( ) { } ;
586
+ input . addEventListener ( "click" , clickHandler ) ;
587
+ div . addEventListener ( "click" , clickHandler ) ;
588
+
589
+ input . dispatchEvent ( new MouseEvent ( "click" ) ) ;
590
+ div . dispatchEvent ( new MouseEvent ( "click" ) ) ;
591
+
592
+ Sentry . captureMessage ( "test" ) ;
593
+ } ) . then ( function ( summary ) {
594
+ if ( IS_LOADER ) {
595
+ // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs
596
+ assert . lengthOf ( summary . events , 1 ) ;
597
+ } else {
598
+ // Breadcrumb should be captured by the global event listeners, not a specific one
599
+ assert . equal ( summary . breadcrumbs . length , 2 ) ;
600
+ assert . equal ( summary . breadcrumbs [ 0 ] . category , "ui.click" ) ;
601
+ assert . equal (
602
+ summary . breadcrumbs [ 0 ] . message ,
603
+ 'body > form#foo-form > input[name="foo"]'
604
+ ) ;
605
+ assert . equal ( summary . breadcrumbs [ 1 ] . category , "ui.click" ) ;
606
+ assert . equal (
607
+ summary . breadcrumbs [ 1 ] . message ,
608
+ "body > form#foo-form > div.contenteditable"
609
+ ) ;
610
+ assert . equal ( summary . breadcrumbHints [ 0 ] . global , false ) ;
611
+ assert . equal ( summary . breadcrumbHints [ 1 ] . global , false ) ;
612
+ assert . isUndefined ( summary . events [ 0 ] . exception ) ;
613
+ }
614
+ } ) ;
615
+ } ) ;
616
+
503
617
it (
504
618
optional (
505
619
"should flush keypress breadcrumbs when an error is thrown" ,
@@ -659,6 +773,42 @@ describe("breadcrumbs", function() {
659
773
} ) ;
660
774
} ) ;
661
775
776
+ it ( "should remove breadcrumb instrumentation when all event listeners are detached" , function ( ) {
777
+ return runInSandbox ( sandbox , function ( ) {
778
+ var input = document . getElementsByTagName ( "input" ) [ 0 ] ;
779
+
780
+ var clickHandler = function ( ) { } ;
781
+ var otherClickHandler = function ( ) { } ;
782
+ input . addEventListener ( "click" , clickHandler ) ;
783
+ input . addEventListener ( "click" , otherClickHandler ) ;
784
+ input . removeEventListener ( "click" , clickHandler ) ;
785
+ input . removeEventListener ( "click" , otherClickHandler ) ;
786
+
787
+ var keypressHandler = function ( ) { } ;
788
+ var otherKeypressHandler = function ( ) { } ;
789
+ input . addEventListener ( "keypress" , keypressHandler ) ;
790
+ input . addEventListener ( "keypress" , otherKeypressHandler ) ;
791
+ input . removeEventListener ( "keypress" , keypressHandler ) ;
792
+ input . removeEventListener ( "keypress" , otherKeypressHandler ) ;
793
+
794
+ input . dispatchEvent ( new MouseEvent ( "click" ) ) ;
795
+ input . dispatchEvent ( new KeyboardEvent ( "keypress" ) ) ;
796
+
797
+ Sentry . captureMessage ( "test" ) ;
798
+ } ) . then ( function ( summary ) {
799
+ if ( IS_LOADER ) {
800
+ // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs
801
+ assert . lengthOf ( summary . events , 1 ) ;
802
+ } else {
803
+ // Breadcrumb should be captured by the global event listeners, not a specific one
804
+ assert . equal ( summary . breadcrumbs . length , 2 ) ;
805
+ assert . equal ( summary . breadcrumbHints [ 0 ] . global , true ) ;
806
+ assert . equal ( summary . breadcrumbHints [ 1 ] . global , true ) ;
807
+ assert . isUndefined ( summary . events [ 0 ] . exception ) ;
808
+ }
809
+ } ) ;
810
+ } ) ;
811
+
662
812
it (
663
813
optional (
664
814
"should record history.[pushState|replaceState] changes as navigation breadcrumbs" ,
0 commit comments