@@ -12,6 +12,7 @@ import {
12
12
} from '../../src/browser/request' ;
13
13
import { addExtensionMethods } from '../../src/hubextensions' ;
14
14
import * as tracingUtils from '../../src/utils' ;
15
+ import { objectFromEntries } from '../testutils' ;
15
16
16
17
// This is a normal base64 regex, modified to reflect that fact that we strip the trailing = or == off
17
18
const stripped_base64 = '([a-zA-Z0-9+/]{4})*([a-zA-Z0-9+/]{2,3})?' ;
@@ -23,9 +24,29 @@ const TRACESTATE_HEADER_REGEX = new RegExp(
23
24
24
25
beforeAll ( ( ) => {
25
26
addExtensionMethods ( ) ;
26
- // @ts -ignore need to override global Request because it's not in the jest environment (even with an
27
- // `@jest-environment jsdom` directive, for some reason)
28
- global . Request = { } ;
27
+
28
+ // Add Request to the global scope (necessary because for some reason Request isn't in the jest environment, even with
29
+ // an `@jest-environment jsdom` directive)
30
+
31
+ type MockHeaders = {
32
+ [ key : string ] : any ;
33
+ append : ( key : string , value : string ) => void ;
34
+ } ;
35
+
36
+ class Request {
37
+ public headers : MockHeaders ;
38
+ constructor ( ) {
39
+ // We need our headers to act like an object for key-lookup purposes, but also have an append method that adds
40
+ // items as its siblings. This hack precludes a key named `append`, of course, but for our purposes it's enough.
41
+ const headers = { } as MockHeaders ;
42
+ headers . append = ( key : string , value : any ) : void => {
43
+ headers [ key ] = value ;
44
+ } ;
45
+ this . headers = headers ;
46
+ }
47
+ }
48
+
49
+ ( global as any ) . Request = Request ;
29
50
} ) ;
30
51
31
52
const hasTracingEnabled = jest . spyOn ( tracingUtils , 'hasTracingEnabled' ) ;
@@ -63,7 +84,7 @@ describe('registerRequestInstrumentation', () => {
63
84
} ) ;
64
85
} ) ;
65
86
66
- describe ( 'callbacks' , ( ) => {
87
+ describe ( 'fetch and xhr callbacks' , ( ) => {
67
88
let hub : Hub ;
68
89
let transaction : Transaction ;
69
90
const alwaysCreateSpan = ( ) => true ;
@@ -199,15 +220,67 @@ describe('callbacks', () => {
199
220
expect ( newSpan ! . status ) . toBe ( SpanStatus . fromHttpCode ( 404 ) ) ;
200
221
} ) ;
201
222
202
- it ( 'adds tracing headers to fetch requests', ( ) => {
203
- // make a local copy so the global one doesn't get mutated
204
- const handlerData = { ...fetchHandlerData } ;
223
+ describe ( 'adding tracing headers to fetch requests', ( ) => {
224
+ it ( 'can handle headers added with an `append` method' , ( ) => {
225
+ const handlerData : FetchData = { ...fetchHandlerData , args : [ new Request ( 'http://dogs.are.great' ) , { } ] } ;
205
226
206
- fetchCallback ( handlerData , alwaysCreateSpan , { } ) ;
227
+ fetchCallback ( handlerData , alwaysCreateSpan , { } ) ;
207
228
208
- const headers = ( handlerData . args [ 1 ] . headers as Record < string , string > ) || { } ;
209
- expect ( headers [ 'sentry-trace' ] ) . toBeDefined ( ) ;
210
- expect ( headers [ 'tracestate' ] ) . toBeDefined ( ) ;
229
+ const headers = handlerData . args [ 1 ] . headers ;
230
+ expect ( headers [ 'sentry-trace' ] ) . toBeDefined ( ) ;
231
+ expect ( headers [ 'tracestate' ] ) . toBeDefined ( ) ;
232
+ } ) ;
233
+
234
+ it ( 'can handle existing headers in array form' , ( ) => {
235
+ const handlerData = {
236
+ ...fetchHandlerData ,
237
+ args : [
238
+ 'http://dogs.are.great/' ,
239
+ {
240
+ headers : [
241
+ [ 'GREETING_PROTOCOL' , 'mutual butt sniffing' ] ,
242
+ [ 'TAIL_ACTION' , 'wagging' ] ,
243
+ ] ,
244
+ } ,
245
+ ] ,
246
+ } ;
247
+
248
+ fetchCallback ( handlerData , alwaysCreateSpan , { } ) ;
249
+
250
+ const headers = objectFromEntries ( ( handlerData . args [ 1 ] as any ) . headers ) ;
251
+ expect ( headers [ 'sentry-trace' ] ) . toBeDefined ( ) ;
252
+ expect ( headers [ 'tracestate' ] ) . toBeDefined ( ) ;
253
+ } ) ;
254
+
255
+ it ( 'can handle existing headers in object form' , ( ) => {
256
+ const handlerData = {
257
+ ...fetchHandlerData ,
258
+ args : [
259
+ 'http://dogs.are.great/' ,
260
+ {
261
+ headers : { GREETING_PROTOCOL : 'mutual butt sniffing' , TAIL_ACTION : 'wagging' } ,
262
+ } ,
263
+ ] ,
264
+ } ;
265
+
266
+ fetchCallback ( handlerData , alwaysCreateSpan , { } ) ;
267
+
268
+ const headers = ( handlerData . args [ 1 ] as any ) . headers ;
269
+ expect ( headers [ 'sentry-trace' ] ) . toBeDefined ( ) ;
270
+ expect ( headers [ 'tracestate' ] ) . toBeDefined ( ) ;
271
+ } ) ;
272
+
273
+ it ( 'can handle there being no existing headers' , ( ) => {
274
+ // override the value of `args`, even though we're overriding it with the same data, as a means of deep copying
275
+ // the one part which gets mutated
276
+ const handlerData = { ...fetchHandlerData , args : [ 'http://dogs.are.great/' , { } ] } ;
277
+
278
+ fetchCallback ( handlerData , alwaysCreateSpan , { } ) ;
279
+
280
+ const headers = ( handlerData . args [ 1 ] as any ) . headers ;
281
+ expect ( headers [ 'sentry-trace' ] ) . toBeDefined ( ) ;
282
+ expect ( headers [ 'tracestate' ] ) . toBeDefined ( ) ;
283
+ } ) ;
211
284
} ) ;
212
285
} ) ;
213
286
0 commit comments