@@ -6,6 +6,7 @@ import { Span, SpanStatus, Transaction } from '../../src';
66import { fetchCallback , FetchData , instrumentOutgoingRequests , xhrCallback , XHRData } from '../../src/browser/request' ;
77import { addExtensionMethods } from '../../src/hubextensions' ;
88import * as tracingUtils from '../../src/utils' ;
9+ import { objectFromEntries } from '../testutils' ;
910
1011// This is a normal base64 regex, modified to reflect that fact that we strip the trailing = or == off
1112const stripped_base64 = '([a-zA-Z0-9+/]{4})*([a-zA-Z0-9+/]{2,3})?' ;
@@ -17,9 +18,29 @@ const TRACESTATE_HEADER_REGEX = new RegExp(
1718
1819beforeAll ( ( ) => {
1920 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 ;
2344} ) ;
2445
2546const hasTracingEnabled = jest . spyOn ( tracingUtils , 'hasTracingEnabled' ) ;
@@ -57,7 +78,7 @@ describe('instrumentOutgoingRequests', () => {
5778 } ) ;
5879} ) ;
5980
60- describe ( 'callbacks' , ( ) => {
81+ describe ( 'fetch and xhr callbacks' , ( ) => {
6182 let hub : Hub ;
6283 let transaction : Transaction ;
6384 const alwaysCreateSpan = ( ) => true ;
@@ -193,15 +214,67 @@ describe('callbacks', () => {
193214 expect ( newSpan ! . status ) . toBe ( SpanStatus . fromHttpCode ( 404 ) ) ;
194215 } ) ;
195216
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' ) , { } ] } ;
199220
200- fetchCallback ( handlerData , alwaysCreateSpan , { } ) ;
221+ fetchCallback ( handlerData , alwaysCreateSpan , { } ) ;
201222
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+ } ) ;
205278 } ) ;
206279 } ) ;
207280
0 commit comments