@@ -30,6 +30,90 @@ describe("window.onunhandledrejection", function() {
3030 } ) ;
3131 } ) ;
3232
33+ // something, somewhere, (likely a browser extension) effectively casts PromiseRejectionEvents
34+ // to CustomEvents, moving the `promise` and `reason` attributes of the PRE into
35+ // the CustomEvent's `detail` attribute, since they're not part of CustomEvent's spec
36+ // see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent and
37+ // https://github.com/getsentry/sentry-javascript/issues/2380
38+ it ( "should capture PromiseRejectionEvent cast to CustomEvent with type unhandledrejection" , function ( ) {
39+ return runInSandbox ( sandbox , function ( ) {
40+ if ( supportsOnunhandledRejection ( ) ) {
41+ // this isn't how it happens in real life, in that the promise and reason
42+ // values come from an actual PromiseRejectionEvent, but it's enough to test
43+ // how the SDK handles the structure
44+ window . dispatchEvent (
45+ new CustomEvent ( "unhandledrejection" , {
46+ detail : {
47+ promise : new Promise ( ( ) => { } ) ,
48+ // we're testing with an error here but it could be anything - really
49+ // all we're testing is that it gets dug out correctly
50+ reason : new Error ( "test2" ) ,
51+ } ,
52+ } )
53+ ) ;
54+ Promise . reject ( ) ;
55+ } else {
56+ window . resolveTest ( { window : window } ) ;
57+ }
58+ } ) . then ( function ( summary ) {
59+ if ( summary . window . supportsOnunhandledRejection ( ) ) {
60+ assert . equal ( summary . events [ 0 ] . exception . values [ 0 ] . value , "test2" ) ;
61+ assert . equal ( summary . events [ 0 ] . exception . values [ 0 ] . type , "Error" ) ;
62+
63+ // Of course Safari had to screw up here...
64+ if ( ! / V e r s i o n \/ \d .+ S a f a r i \/ \d / . test ( window . navigator . userAgent ) ) {
65+ assert . isAtLeast (
66+ summary . events [ 0 ] . exception . values [ 0 ] . stacktrace . frames . length ,
67+ 1
68+ ) ;
69+ }
70+ assert . equal (
71+ summary . events [ 0 ] . exception . values [ 0 ] . mechanism . handled ,
72+ false
73+ ) ;
74+ assert . equal (
75+ summary . events [ 0 ] . exception . values [ 0 ] . mechanism . type ,
76+ "onunhandledrejection"
77+ ) ;
78+ // even though it's a regular Event (rather than a PRE) it should still only
79+ // come through this channel
80+ assert . equal ( summary . events . length , 1 ) ;
81+ }
82+ } ) ;
83+ } ) ;
84+
85+ // there's no evidence that this actually happens, but it could, and our code correctly
86+ // handles it, so might as well prevent future regression on that score
87+ it ( "should capture a random Event with type unhandledrejection" , function ( ) {
88+ return runInSandbox ( sandbox , function ( ) {
89+ if ( supportsOnunhandledRejection ( ) ) {
90+ window . dispatchEvent ( new Event ( "unhandledrejection" ) ) ;
91+ } else {
92+ window . resolveTest ( { window : window } ) ;
93+ }
94+ } ) . then ( function ( summary ) {
95+ if ( summary . window . supportsOnunhandledRejection ( ) ) {
96+ // non-error rejections don't provide stacktraces so we can skip that assertion
97+ assert . equal (
98+ summary . events [ 0 ] . exception . values [ 0 ] . value ,
99+ "Non-Error promise rejection captured with keys: currentTarget, isTrusted, target, type"
100+ ) ;
101+ assert . equal ( summary . events [ 0 ] . exception . values [ 0 ] . type , "Event" ) ;
102+ assert . equal (
103+ summary . events [ 0 ] . exception . values [ 0 ] . mechanism . handled ,
104+ false
105+ ) ;
106+ assert . equal (
107+ summary . events [ 0 ] . exception . values [ 0 ] . mechanism . type ,
108+ "onunhandledrejection"
109+ ) ;
110+ // even though it's a regular Event (rather than a PRE) it should sill only
111+ // come through this channel
112+ assert . equal ( summary . events . length , 1 ) ;
113+ }
114+ } ) ;
115+ } ) ;
116+
33117 it ( "should capture unhandledrejection with a string" , function ( ) {
34118 return runInSandbox ( sandbox , function ( ) {
35119 if ( supportsOnunhandledRejection ( ) ) {
@@ -39,7 +123,7 @@ describe("window.onunhandledrejection", function() {
39123 }
40124 } ) . then ( function ( summary ) {
41125 if ( summary . window . supportsOnunhandledRejection ( ) ) {
42- // non-error rejections doesnt provide stacktraces so we can skip the assertion
126+ // non-error rejections don't provide stacktraces so we can skip that assertion
43127 assert . equal (
44128 summary . events [ 0 ] . exception . values [ 0 ] . value ,
45129 "Non-Error promise rejection captured with value: test"
@@ -69,7 +153,7 @@ describe("window.onunhandledrejection", function() {
69153 }
70154 } ) . then ( function ( summary ) {
71155 if ( summary . window . supportsOnunhandledRejection ( ) ) {
72- // non-error rejections doesnt provide stacktraces so we can skip the assertion
156+ // non-error rejections don't provide stacktraces so we can skip that assertion
73157 assert . equal ( summary . events [ 0 ] . exception . values [ 0 ] . value . length , 253 ) ;
74158 assert . include (
75159 summary . events [ 0 ] . exception . values [ 0 ] . value ,
@@ -100,7 +184,7 @@ describe("window.onunhandledrejection", function() {
100184 }
101185 } ) . then ( function ( summary ) {
102186 if ( summary . window . supportsOnunhandledRejection ( ) ) {
103- // non-error rejections doesnt provide stacktraces so we can skip the assertion
187+ // non-error rejections don't provide stacktraces so we can skip that assertion
104188 assert . equal (
105189 summary . events [ 0 ] . exception . values [ 0 ] . value ,
106190 "Non-Error promise rejection captured with keys: a, b, c"
@@ -137,7 +221,7 @@ describe("window.onunhandledrejection", function() {
137221 }
138222 } ) . then ( function ( summary ) {
139223 if ( summary . window . supportsOnunhandledRejection ( ) ) {
140- // non-error rejections doesnt provide stacktraces so we can skip the assertion
224+ // non-error rejections don't provide stacktraces so we can skip that assertion
141225 assert . equal (
142226 summary . events [ 0 ] . exception . values [ 0 ] . value ,
143227 "Non-Error promise rejection captured with keys: a, b, c, d, e"
@@ -167,7 +251,7 @@ describe("window.onunhandledrejection", function() {
167251 }
168252 } ) . then ( function ( summary ) {
169253 if ( summary . window . supportsOnunhandledRejection ( ) ) {
170- // non-error rejections doesnt provide stacktraces so we can skip the assertion
254+ // non-error rejections don't provide stacktraces so we can skip that assertion
171255 assert . equal (
172256 summary . events [ 0 ] . exception . values [ 0 ] . value ,
173257 "Non-Error promise rejection captured with value: 1337"
@@ -197,7 +281,7 @@ describe("window.onunhandledrejection", function() {
197281 }
198282 } ) . then ( function ( summary ) {
199283 if ( summary . window . supportsOnunhandledRejection ( ) ) {
200- // non-error rejections doesnt provide stacktraces so we can skip the assertion
284+ // non-error rejections don't provide stacktraces so we can skip that assertion
201285 assert . equal (
202286 summary . events [ 0 ] . exception . values [ 0 ] . value ,
203287 "Non-Error promise rejection captured with value: null"
@@ -227,7 +311,7 @@ describe("window.onunhandledrejection", function() {
227311 }
228312 } ) . then ( function ( summary ) {
229313 if ( summary . window . supportsOnunhandledRejection ( ) ) {
230- // non-error rejections doesnt provide stacktraces so we can skip the assertion
314+ // non-error rejections don't provide stacktraces so we can skip that assertion
231315 assert . equal (
232316 summary . events [ 0 ] . exception . values [ 0 ] . value ,
233317 "Non-Error promise rejection captured with value: undefined"
0 commit comments