@@ -2759,6 +2759,113 @@ describe('Client', () => {
27592759 ) ;
27602760 } ) ;
27612761
2762+ test ( 'drops the transaction and its non-ignored spans when `beforeSendTransaction` rejects' , async ( ) => {
2763+ vi . useFakeTimers ( ) ;
2764+
2765+ const exception = new Error ( 'beforeSendTransaction failed' ) ;
2766+ const beforeSendTransaction = vi . fn ( ( ) => Promise . reject ( exception ) ) ;
2767+ const options = getDefaultTestClientOptions ( {
2768+ dsn : PUBLIC_DSN ,
2769+ beforeSendTransaction,
2770+ ignoreSpans : [ 'ignored span' ] ,
2771+ } ) ;
2772+ const client = new TestClient ( options ) ;
2773+ const captureExceptionSpy = vi . spyOn ( client , 'captureException' ) ;
2774+ const recordDroppedEventSpy = vi . spyOn ( client , 'recordDroppedEvent' ) ;
2775+ const debugErrorSpy = vi . spyOn ( debugLoggerModule . debug , 'error' ) ;
2776+
2777+ client . captureEvent ( {
2778+ transaction : '/dogs/are/great' ,
2779+ type : 'transaction' ,
2780+ spans : [ 'first span' , 'ignored span' , 'second span' ] . map ( ( description , i ) => ( {
2781+ description,
2782+ span_id : `${ i } ` . padStart ( 16 , '0' ) ,
2783+ start_timestamp : 1591603196.637835 ,
2784+ trace_id : '86f39e84263a4de99c326acab3bfe3bd' ,
2785+ data : { } ,
2786+ status : 'ok' ,
2787+ } ) ) ,
2788+ } ) ;
2789+ await vi . runOnlyPendingTimersAsync ( ) ;
2790+
2791+ expect ( TestClient . instance ! . event ) . toBeUndefined ( ) ;
2792+ expect ( captureExceptionSpy ) . not . toHaveBeenCalled ( ) ;
2793+ expect ( recordDroppedEventSpy ) . toHaveBeenCalledTimes ( 3 ) ;
2794+ expect ( recordDroppedEventSpy ) . toHaveBeenCalledWith ( 'ignored' , 'span' , 1 ) ;
2795+ expect ( recordDroppedEventSpy ) . toHaveBeenCalledWith ( 'callback_error' , 'transaction' ) ;
2796+ expect ( recordDroppedEventSpy ) . toHaveBeenCalledWith ( 'callback_error' , 'span' , 3 ) ;
2797+ expect ( debugErrorSpy ) . toHaveBeenCalledWith (
2798+ 'The `beforeSendTransaction` callback threw an error, dropping the event:' ,
2799+ exception ,
2800+ ) ;
2801+ } ) ;
2802+
2803+ test . each ( [
2804+ [ 'sync' , ( ) => undefined ] ,
2805+ [ 'async' , ( ) => Promise . resolve ( undefined ) ] ,
2806+ ] ) ( 'records a `before_send` outcome when `beforeSend` returns an invalid value (%s)' , async ( _ , beforeSend ) => {
2807+ vi . useFakeTimers ( ) ;
2808+
2809+ // @ts -expect-error we need to test regular-js behavior
2810+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , beforeSend } ) ;
2811+ const client = new TestClient ( options ) ;
2812+ const captureExceptionSpy = vi . spyOn ( client , 'captureException' ) ;
2813+ const recordDroppedEventSpy = vi . spyOn ( client , 'recordDroppedEvent' ) ;
2814+ const loggerWarnSpy = vi . spyOn ( debugLoggerModule . debug , 'warn' ) ;
2815+
2816+ client . captureEvent ( { message : 'hello' } ) ;
2817+ await vi . runOnlyPendingTimersAsync ( ) ;
2818+
2819+ expect ( TestClient . instance ! . event ) . toBeUndefined ( ) ;
2820+ expect ( captureExceptionSpy ) . not . toHaveBeenCalled ( ) ;
2821+ expect ( recordDroppedEventSpy ) . toHaveBeenCalledTimes ( 1 ) ;
2822+ expect ( recordDroppedEventSpy ) . toHaveBeenCalledWith ( 'before_send' , 'error' ) ;
2823+ expect ( loggerWarnSpy ) . toHaveBeenCalledWith ( 'before send for type `error` must return `null` or a valid event.' ) ;
2824+ } ) ;
2825+
2826+ test . each ( [
2827+ [ 'sync' , ( ) => undefined ] ,
2828+ [ 'async' , ( ) => Promise . resolve ( undefined ) ] ,
2829+ ] ) (
2830+ 'records `before_send` outcomes for the transaction and its spans when `beforeSendTransaction` returns an invalid value (%s)' ,
2831+ async ( _ , beforeSendTransaction ) => {
2832+ vi . useFakeTimers ( ) ;
2833+
2834+ const options = getDefaultTestClientOptions ( {
2835+ dsn : PUBLIC_DSN ,
2836+ // @ts -expect-error we need to test regular-js behavior
2837+ beforeSendTransaction,
2838+ ignoreSpans : [ 'ignored span' ] ,
2839+ } ) ;
2840+ const client = new TestClient ( options ) ;
2841+ const recordDroppedEventSpy = vi . spyOn ( client , 'recordDroppedEvent' ) ;
2842+ const loggerWarnSpy = vi . spyOn ( debugLoggerModule . debug , 'warn' ) ;
2843+
2844+ client . captureEvent ( {
2845+ transaction : '/dogs/are/great' ,
2846+ type : 'transaction' ,
2847+ spans : [ 'first span' , 'ignored span' ] . map ( ( description , i ) => ( {
2848+ description,
2849+ span_id : `${ i } ` . padStart ( 16 , '0' ) ,
2850+ start_timestamp : 1591603196.637835 ,
2851+ trace_id : '86f39e84263a4de99c326acab3bfe3bd' ,
2852+ data : { } ,
2853+ status : 'ok' ,
2854+ } ) ) ,
2855+ } ) ;
2856+ await vi . runOnlyPendingTimersAsync ( ) ;
2857+
2858+ expect ( TestClient . instance ! . event ) . toBeUndefined ( ) ;
2859+ expect ( recordDroppedEventSpy ) . toHaveBeenCalledTimes ( 3 ) ;
2860+ expect ( recordDroppedEventSpy ) . toHaveBeenCalledWith ( 'ignored' , 'span' , 1 ) ;
2861+ expect ( recordDroppedEventSpy ) . toHaveBeenCalledWith ( 'before_send' , 'transaction' ) ;
2862+ expect ( recordDroppedEventSpy ) . toHaveBeenCalledWith ( 'before_send' , 'span' , 2 ) ;
2863+ expect ( loggerWarnSpy ) . toHaveBeenCalledWith (
2864+ 'before send for type `transaction` must return `null` or a valid event.' ,
2865+ ) ;
2866+ } ,
2867+ ) ;
2868+
27622869 test ( 'captures an internal event when the event processing pipeline itself throws' , async ( ) => {
27632870 vi . useFakeTimers ( ) ;
27642871
0 commit comments