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