@@ -12,6 +12,9 @@ const PUBLIC_DSN = 'https://username@domain/123';
1212// eslint-disable-next-line no-var
1313declare var global : any ;
1414
15+ const backendEventFromException = jest . spyOn ( TestBackend . prototype , 'eventFromException' ) ;
16+ const clientProcess = jest . spyOn ( TestClient . prototype as any , '_process' ) ;
17+
1518jest . mock ( '@sentry/utils' , ( ) => {
1619 const original = jest . requireActual ( '@sentry/utils' ) ;
1720 return {
@@ -57,7 +60,7 @@ describe('BaseClient', () => {
5760 } ) ;
5861
5962 afterEach ( ( ) => {
60- jest . restoreAllMocks ( ) ;
63+ jest . clearAllMocks ( ) ;
6164 } ) ;
6265
6366 describe ( 'constructor() / getDsn()' , ( ) => {
@@ -249,6 +252,28 @@ describe('BaseClient', () => {
249252 } ) ,
250253 ) ;
251254 } ) ;
255+
256+ test . each ( [
257+ [ '`Error` instance' , new Error ( 'Will I get caught twice?' ) ] ,
258+ [ 'plain object' , { 'Will I' : 'get caught twice?' } ] ,
259+ [ 'primitive wrapper' , new String ( 'Will I get caught twice?' ) ] ,
260+ // primitives aren't tested directly here because they need to be wrapped with `objectify` *before* being passed
261+ // to `captureException` (which is how we'd end up with a primitive wrapper as tested above)
262+ ] ) ( "doesn't capture the same exception twice - %s" , ( _name : string , thrown : any ) => {
263+ const client = new TestClient ( { dsn : PUBLIC_DSN } ) ;
264+
265+ expect ( thrown . __sentry_captured__ ) . toBeUndefined ( ) ;
266+
267+ client . captureException ( thrown ) ;
268+
269+ expect ( thrown . __sentry_captured__ ) . toBe ( true ) ;
270+ expect ( backendEventFromException ) . toHaveBeenCalledTimes ( 1 ) ;
271+
272+ client . captureException ( thrown ) ;
273+
274+ // `captureException` should bail right away this second time around and not get as far as calling this again
275+ expect ( backendEventFromException ) . toHaveBeenCalledTimes ( 1 ) ;
276+ } ) ;
252277 } ) ;
253278
254279 describe ( 'captureMessage' , ( ) => {
@@ -325,6 +350,30 @@ describe('BaseClient', () => {
325350 expect ( TestBackend . instance ! . event ) . toBeUndefined ( ) ;
326351 } ) ;
327352
353+ test . each ( [
354+ [ '`Error` instance' , new Error ( 'Will I get caught twice?' ) ] ,
355+ [ 'plain object' , { 'Will I' : 'get caught twice?' } ] ,
356+ [ 'primitive wrapper' , new String ( 'Will I get caught twice?' ) ] ,
357+ // primitives aren't tested directly here because they need to be wrapped with `objectify` *before* being passed
358+ // to `captureEvent` (which is how we'd end up with a primitive wrapper as tested above)
359+ ] ) ( "doesn't capture the same exception twice - %s" , ( _name : string , thrown : any ) => {
360+ const client = new TestClient ( { dsn : PUBLIC_DSN } ) ;
361+ const event = { exception : { values : [ { type : 'Error' , message : 'Will I get caught twice?' } ] } } ;
362+ const hint = { originalException : thrown } ;
363+
364+ expect ( thrown . __sentry_captured__ ) . toBeUndefined ( ) ;
365+
366+ client . captureEvent ( event , hint ) ;
367+
368+ expect ( thrown . __sentry_captured__ ) . toBe ( true ) ;
369+ expect ( clientProcess ) . toHaveBeenCalledTimes ( 1 ) ;
370+
371+ client . captureEvent ( event , hint ) ;
372+
373+ // `captureEvent` should bail right away this second time around and not get as far as calling this again
374+ expect ( clientProcess ) . toHaveBeenCalledTimes ( 1 ) ;
375+ } ) ;
376+
328377 test ( 'sends an event' , ( ) => {
329378 expect . assertions ( 2 ) ;
330379 const client = new TestClient ( { dsn : PUBLIC_DSN } ) ;
@@ -798,7 +847,7 @@ describe('BaseClient', () => {
798847 expect ( TestBackend . instance ! . event ) . toBeUndefined ( ) ;
799848 } ) ;
800849
801- test ( 'calls beforeSend gets an access to a hint as a second argument' , ( ) => {
850+ test ( 'beforeSend gets access to a hint as a second argument' , ( ) => {
802851 expect . assertions ( 2 ) ;
803852 const beforeSend = jest . fn ( ( event , hint ) => ( { ...event , data : hint . data } ) ) ;
804853 const client = new TestClient ( { dsn : PUBLIC_DSN , beforeSend } ) ;
0 commit comments