@@ -899,6 +899,18 @@ describe('BaseClient', () => {
899
899
expect ( TestClient . instance ! . event ! . message ) . toEqual ( 'hello' ) ;
900
900
} ) ;
901
901
902
+ test ( 'calls `beforeSendTransaction` and uses original event without any changes' , ( ) => {
903
+ expect . assertions ( 1 ) ;
904
+
905
+ const beforeSendTransaction = jest . fn ( event => event ) ;
906
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , beforeSendTransaction } ) ;
907
+ const client = new TestClient ( options ) ;
908
+
909
+ client . captureEvent ( { transaction : '/dogs/are/great' , type : 'transaction' } ) ;
910
+
911
+ expect ( TestClient . instance ! . event ! . transaction ) . toBe ( '/dogs/are/great' ) ;
912
+ } ) ;
913
+
902
914
test ( 'calls `beforeSend` and uses the modified event' , ( ) => {
903
915
expect . assertions ( 1 ) ;
904
916
@@ -914,6 +926,21 @@ describe('BaseClient', () => {
914
926
expect ( TestClient . instance ! . event ! . message ) . toEqual ( 'changed1' ) ;
915
927
} ) ;
916
928
929
+ test ( 'calls `beforeSendTransaction` and uses the modified event' , ( ) => {
930
+ expect . assertions ( 1 ) ;
931
+
932
+ const beforeSendTransaction = jest . fn ( event => {
933
+ event . transaction = '/adopt/dont/shop' ;
934
+ return event ;
935
+ } ) ;
936
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , beforeSendTransaction } ) ;
937
+ const client = new TestClient ( options ) ;
938
+
939
+ client . captureEvent ( { transaction : '/dogs/are/great' , type : 'transaction' } ) ;
940
+
941
+ expect ( TestClient . instance ! . event ! . transaction ) . toBe ( '/adopt/dont/shop' ) ;
942
+ } ) ;
943
+
917
944
test ( 'calls `beforeSend` and discards the event' , ( ) => {
918
945
expect . assertions ( 3 ) ;
919
946
@@ -932,6 +959,24 @@ describe('BaseClient', () => {
932
959
expect ( loggerWarnSpy ) . toBeCalledWith ( '`beforeSend` returned `null`, will not send event.' ) ;
933
960
} ) ;
934
961
962
+ test ( 'calls `beforeSendTransaction` and discards the event' , ( ) => {
963
+ expect . assertions ( 2 ) ;
964
+
965
+ const beforeSendTransaction = jest . fn ( ( ) => null ) ;
966
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , beforeSendTransaction } ) ;
967
+ const client = new TestClient ( options ) ;
968
+ const captureExceptionSpy = jest . spyOn ( client , 'captureException' ) ;
969
+ const loggerWarnSpy = jest . spyOn ( logger , 'log' ) ;
970
+
971
+ client . captureEvent ( { transaction : '/dogs/are/great' , type : 'transaction' } ) ;
972
+
973
+ expect ( TestClient . instance ! . event ) . toBeUndefined ( ) ;
974
+ // This proves that the reason the event didn't send/didn't get set on the test client is not because there was an
975
+ // error, but because `beforeSendTransaction` returned `null`
976
+ expect ( captureExceptionSpy ) . not . toBeCalled ( ) ;
977
+ expect ( loggerWarnSpy ) . toBeCalledWith ( '`beforeSendTransaction` returned `null`, will not send event.' ) ;
978
+ } ) ;
979
+
935
980
test ( 'calls `beforeSend` and logs info about invalid return value' , ( ) => {
936
981
const invalidValues = [ undefined , false , true , [ ] , 1 ] ;
937
982
expect . assertions ( invalidValues . length * 2 ) ;
@@ -950,6 +995,26 @@ describe('BaseClient', () => {
950
995
}
951
996
} ) ;
952
997
998
+ test ( 'calls `beforeSendTransaction` and logs info about invalid return value' , ( ) => {
999
+ const invalidValues = [ undefined , false , true , [ ] , 1 ] ;
1000
+ expect . assertions ( invalidValues . length * 2 ) ;
1001
+
1002
+ for ( const val of invalidValues ) {
1003
+ const beforeSendTransaction = jest . fn ( ( ) => val ) ;
1004
+ // @ts -ignore we need to test regular-js behavior
1005
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , beforeSendTransaction } ) ;
1006
+ const client = new TestClient ( options ) ;
1007
+ const loggerWarnSpy = jest . spyOn ( logger , 'warn' ) ;
1008
+
1009
+ client . captureEvent ( { transaction : '/dogs/are/great' , type : 'transaction' } ) ;
1010
+
1011
+ expect ( TestClient . instance ! . event ) . toBeUndefined ( ) ;
1012
+ expect ( loggerWarnSpy ) . toBeCalledWith (
1013
+ new SentryError ( '`beforeSendTransaction` must return `null` or a valid event.' ) ,
1014
+ ) ;
1015
+ }
1016
+ } ) ;
1017
+
953
1018
test ( 'calls async `beforeSend` and uses original event without any changes' , done => {
954
1019
jest . useFakeTimers ( ) ;
955
1020
expect . assertions ( 1 ) ;
@@ -979,6 +1044,35 @@ describe('BaseClient', () => {
979
1044
jest . runOnlyPendingTimers ( ) ;
980
1045
} ) ;
981
1046
1047
+ test ( 'calls async `beforeSendTransaction` and uses original event without any changes' , done => {
1048
+ jest . useFakeTimers ( ) ;
1049
+ expect . assertions ( 1 ) ;
1050
+
1051
+ const beforeSendTransaction = jest . fn (
1052
+ async event =>
1053
+ new Promise < Event > ( resolve => {
1054
+ setTimeout ( ( ) => {
1055
+ resolve ( event ) ;
1056
+ } , 1 ) ;
1057
+ } ) ,
1058
+ ) ;
1059
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , beforeSendTransaction } ) ;
1060
+ const client = new TestClient ( options ) ;
1061
+
1062
+ client . captureEvent ( { transaction : '/dogs/are/great' , type : 'transaction' } ) ;
1063
+ jest . runOnlyPendingTimers ( ) ;
1064
+
1065
+ TestClient . sendEventCalled = ( event : Event ) => {
1066
+ expect ( event . transaction ) . toBe ( '/dogs/are/great' ) ;
1067
+ } ;
1068
+
1069
+ setTimeout ( ( ) => {
1070
+ done ( ) ;
1071
+ } , 5 ) ;
1072
+
1073
+ jest . runOnlyPendingTimers ( ) ;
1074
+ } ) ;
1075
+
982
1076
test ( 'calls async `beforeSend` and uses the modified event' , done => {
983
1077
jest . useFakeTimers ( ) ;
984
1078
expect . assertions ( 1 ) ;
@@ -1008,6 +1102,35 @@ describe('BaseClient', () => {
1008
1102
jest . runOnlyPendingTimers ( ) ;
1009
1103
} ) ;
1010
1104
1105
+ test ( 'calls async `beforeSendTransaction` and uses the modified event' , done => {
1106
+ jest . useFakeTimers ( ) ;
1107
+ expect . assertions ( 1 ) ;
1108
+
1109
+ const beforeSendTransaction = jest . fn ( async event => {
1110
+ event . transaction = '/adopt/dont/shop' ;
1111
+ return new Promise < Event > ( resolve => {
1112
+ setTimeout ( ( ) => {
1113
+ resolve ( event ) ;
1114
+ } , 1 ) ;
1115
+ } ) ;
1116
+ } ) ;
1117
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , beforeSendTransaction } ) ;
1118
+ const client = new TestClient ( options ) ;
1119
+
1120
+ client . captureEvent ( { transaction : '/dogs/are/great' , type : 'transaction' } ) ;
1121
+ jest . runOnlyPendingTimers ( ) ;
1122
+
1123
+ TestClient . sendEventCalled = ( event : Event ) => {
1124
+ expect ( event . transaction ) . toBe ( '/adopt/dont/shop' ) ;
1125
+ } ;
1126
+
1127
+ setTimeout ( ( ) => {
1128
+ done ( ) ;
1129
+ } , 5 ) ;
1130
+
1131
+ jest . runOnlyPendingTimers ( ) ;
1132
+ } ) ;
1133
+
1011
1134
test ( 'calls async `beforeSend` and discards the event' , ( ) => {
1012
1135
jest . useFakeTimers ( ) ;
1013
1136
expect . assertions ( 1 ) ;
@@ -1029,6 +1152,27 @@ describe('BaseClient', () => {
1029
1152
expect ( TestClient . instance ! . event ) . toBeUndefined ( ) ;
1030
1153
} ) ;
1031
1154
1155
+ test ( 'calls async `beforeSendTransaction` and discards the event' , ( ) => {
1156
+ jest . useFakeTimers ( ) ;
1157
+ expect . assertions ( 1 ) ;
1158
+
1159
+ const beforeSendTransaction = jest . fn (
1160
+ async ( ) =>
1161
+ new Promise < null > ( resolve => {
1162
+ setTimeout ( ( ) => {
1163
+ resolve ( null ) ;
1164
+ } ) ;
1165
+ } ) ,
1166
+ ) ;
1167
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , beforeSendTransaction } ) ;
1168
+ const client = new TestClient ( options ) ;
1169
+
1170
+ client . captureEvent ( { transaction : '/dogs/are/great' , type : 'transaction' } ) ;
1171
+ jest . runAllTimers ( ) ;
1172
+
1173
+ expect ( TestClient . instance ! . event ) . toBeUndefined ( ) ;
1174
+ } ) ;
1175
+
1032
1176
test ( '`beforeSend` gets access to a hint as a second argument' , ( ) => {
1033
1177
expect . assertions ( 2 ) ;
1034
1178
@@ -1042,6 +1186,22 @@ describe('BaseClient', () => {
1042
1186
expect ( ( TestClient . instance ! . event ! as any ) . data ) . toEqual ( 'someRandomThing' ) ;
1043
1187
} ) ;
1044
1188
1189
+ test ( '`beforeSendTransaction` gets access to a hint as a second argument' , ( ) => {
1190
+ expect . assertions ( 2 ) ;
1191
+
1192
+ const beforeSendTransaction = jest . fn ( ( event , hint ) => ( { ...event , data : hint . data } ) ) ;
1193
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , beforeSendTransaction } ) ;
1194
+ const client = new TestClient ( options ) ;
1195
+
1196
+ client . captureEvent (
1197
+ { transaction : '/dogs/are/great' , type : 'transaction' } ,
1198
+ { data : { dogs : 'yes' , cats : 'maybe' } } ,
1199
+ ) ;
1200
+
1201
+ expect ( TestClient . instance ! . event ! . transaction ) . toBe ( '/dogs/are/great' ) ;
1202
+ expect ( ( TestClient . instance ! . event ! as any ) . data ) . toEqual ( { dogs : 'yes' , cats : 'maybe' } ) ;
1203
+ } ) ;
1204
+
1045
1205
test ( '`beforeSend` records dropped events' , ( ) => {
1046
1206
expect . assertions ( 1 ) ;
1047
1207
@@ -1061,7 +1221,26 @@ describe('BaseClient', () => {
1061
1221
expect ( recordLostEventSpy ) . toHaveBeenCalledWith ( 'before_send' , 'error' ) ;
1062
1222
} ) ;
1063
1223
1064
- test ( 'event processor drops the event when it returns `null`' , ( ) => {
1224
+ test ( '`beforeSendTransaction` records dropped events' , ( ) => {
1225
+ expect . assertions ( 1 ) ;
1226
+
1227
+ const client = new TestClient (
1228
+ getDefaultTestClientOptions ( {
1229
+ dsn : PUBLIC_DSN ,
1230
+ beforeSendTransaction ( ) {
1231
+ return null ;
1232
+ } ,
1233
+ } ) ,
1234
+ ) ;
1235
+
1236
+ const recordLostEventSpy = jest . spyOn ( client , 'recordDroppedEvent' ) ;
1237
+
1238
+ client . captureEvent ( { transaction : '/dogs/are/great' , type : 'transaction' } ) ;
1239
+
1240
+ expect ( recordLostEventSpy ) . toHaveBeenCalledWith ( 'before_send' , 'transaction' ) ;
1241
+ } ) ;
1242
+
1243
+ test ( 'event processor drops error event when it returns `null`' , ( ) => {
1065
1244
expect . assertions ( 3 ) ;
1066
1245
1067
1246
const client = new TestClient ( getDefaultTestClientOptions ( { dsn : PUBLIC_DSN } ) ) ;
@@ -1079,7 +1258,25 @@ describe('BaseClient', () => {
1079
1258
expect ( loggerLogSpy ) . toBeCalledWith ( 'An event processor returned `null`, will not send event.' ) ;
1080
1259
} ) ;
1081
1260
1082
- test ( 'event processor records dropped events' , ( ) => {
1261
+ test ( 'event processor drops transaction event when it returns `null`' , ( ) => {
1262
+ expect . assertions ( 2 ) ;
1263
+
1264
+ const client = new TestClient ( getDefaultTestClientOptions ( { dsn : PUBLIC_DSN } ) ) ;
1265
+ const captureExceptionSpy = jest . spyOn ( client , 'captureException' ) ;
1266
+ const loggerLogSpy = jest . spyOn ( logger , 'log' ) ;
1267
+ const scope = new Scope ( ) ;
1268
+ scope . addEventProcessor ( ( ) => null ) ;
1269
+
1270
+ client . captureEvent ( { transaction : '/dogs/are/great' , type : 'transaction' } , { } , scope ) ;
1271
+
1272
+ expect ( TestClient . instance ! . event ) . toBeUndefined ( ) ;
1273
+ // This proves that the reason the event didn't send/didn't get set on the test client is not because there was an
1274
+ // error, but because the event processor returned `null`
1275
+ expect ( captureExceptionSpy ) . not . toBeCalled ( ) ;
1276
+ expect ( loggerLogSpy ) . toBeCalledWith ( 'An event processor returned `null`, will not send event.' ) ;
1277
+ } ) ;
1278
+
1279
+ test ( 'event processor records dropped error events' , ( ) => {
1083
1280
expect . assertions ( 1 ) ;
1084
1281
1085
1282
const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN } ) ;
@@ -1095,6 +1292,22 @@ describe('BaseClient', () => {
1095
1292
expect ( recordLostEventSpy ) . toHaveBeenCalledWith ( 'event_processor' , 'error' ) ;
1096
1293
} ) ;
1097
1294
1295
+ test ( 'event processor records dropped transaction events' , ( ) => {
1296
+ expect . assertions ( 1 ) ;
1297
+
1298
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN } ) ;
1299
+ const client = new TestClient ( options ) ;
1300
+
1301
+ const recordLostEventSpy = jest . spyOn ( client , 'recordDroppedEvent' ) ;
1302
+
1303
+ const scope = new Scope ( ) ;
1304
+ scope . addEventProcessor ( ( ) => null ) ;
1305
+
1306
+ client . captureEvent ( { transaction : '/dogs/are/great' , type : 'transaction' } , { } , scope ) ;
1307
+
1308
+ expect ( recordLostEventSpy ) . toHaveBeenCalledWith ( 'event_processor' , 'transaction' ) ;
1309
+ } ) ;
1310
+
1098
1311
test ( 'mutating transaction name with event processors sets transaction-name-change metadata' , ( ) => {
1099
1312
const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , enableSend : true } ) ;
1100
1313
const client = new TestClient ( options ) ;
@@ -1130,6 +1343,38 @@ describe('BaseClient', () => {
1130
1343
} ) ;
1131
1344
} ) ;
1132
1345
1346
+ test ( 'mutating transaction name with `beforeSendTransaction` sets transaction-name-change metadata' , ( ) => {
1347
+ const beforeSendTransaction = jest . fn ( event => {
1348
+ event . transaction = '/adopt/dont/shop' ;
1349
+ return event ;
1350
+ } ) ;
1351
+ const options = getDefaultTestClientOptions ( { dsn : PUBLIC_DSN , beforeSendTransaction } ) ;
1352
+ const client = new TestClient ( options ) ;
1353
+
1354
+ client . captureEvent ( {
1355
+ transaction : '/dogs/are/great' ,
1356
+ type : 'transaction' ,
1357
+ transaction_info : {
1358
+ source : 'url' ,
1359
+ changes : [ ] ,
1360
+ propagations : 3 ,
1361
+ } ,
1362
+ } ) ;
1363
+
1364
+ expect ( TestClient . instance ! . event ! . transaction ) . toBe ( '/adopt/dont/shop' ) ;
1365
+ expect ( TestClient . instance ! . event ! . transaction_info ) . toEqual ( {
1366
+ source : 'custom' ,
1367
+ changes : [
1368
+ {
1369
+ propagations : 3 ,
1370
+ source : 'custom' ,
1371
+ timestamp : expect . any ( Number ) ,
1372
+ } ,
1373
+ ] ,
1374
+ propagations : 3 ,
1375
+ } ) ;
1376
+ } ) ;
1377
+
1133
1378
test ( 'event processor sends an event and logs when it crashes' , ( ) => {
1134
1379
expect . assertions ( 3 ) ;
1135
1380
@@ -1375,6 +1620,7 @@ describe('BaseClient', () => {
1375
1620
client . recordDroppedEvent ( 'network_error' , 'transaction' ) ;
1376
1621
client . recordDroppedEvent ( 'network_error' , 'transaction' ) ;
1377
1622
client . recordDroppedEvent ( 'before_send' , 'error' ) ;
1623
+ client . recordDroppedEvent ( 'before_send' , 'transaction' ) ;
1378
1624
client . recordDroppedEvent ( 'event_processor' , 'attachment' ) ;
1379
1625
client . recordDroppedEvent ( 'network_error' , 'transaction' ) ;
1380
1626
@@ -1397,6 +1643,11 @@ describe('BaseClient', () => {
1397
1643
category : 'error' ,
1398
1644
quantity : 1 ,
1399
1645
} ,
1646
+ {
1647
+ reason : 'before_send' ,
1648
+ category : 'transaction' ,
1649
+ quantity : 1 ,
1650
+ } ,
1400
1651
{
1401
1652
reason : 'event_processor' ,
1402
1653
category : 'attachment' ,
0 commit comments