@@ -62,9 +62,15 @@ test('Faulty middlewares', async ({ request }) => {
6262test ( 'Should trace outgoing fetch requests inside middleware and create breadcrumbs for it' , async ( { request } ) => {
6363 test . skip ( isDevMode , 'The fetch requests ends up in a separate tx in dev atm' ) ;
6464 const middlewareTransactionPromise = waitForTransaction ( 'nextjs-16' , async transactionEvent => {
65+ return transactionEvent ?. transaction === 'middleware GET' ;
66+ } ) ;
67+
68+ // In some builds (especially webpack), fetch spans may end up in a separate transaction instead of as child spans
69+ // This test validates that the fetch is traced either way
70+ const fetchTransactionPromise = waitForTransaction ( 'nextjs-16' , async transactionEvent => {
6571 return (
66- transactionEvent ?. transaction === 'middleware GET' &&
67- ! ! transactionEvent . spans ?. find ( span => span . op === 'http.client' )
72+ transactionEvent ?. transaction === 'GET http://localhost:3030/' ||
73+ transactionEvent ?. contexts ?. trace ?. description === 'GET http://localhost:3030/'
6874 ) ;
6975 } ) ;
7076
@@ -74,40 +80,7 @@ test('Should trace outgoing fetch requests inside middleware and create breadcru
7480
7581 const middlewareTransaction = await middlewareTransactionPromise ;
7682
77- expect ( middlewareTransaction . spans ) . toEqual (
78- expect . arrayContaining ( [
79- {
80- data : {
81- 'http.request.method' : 'GET' ,
82- 'http.request.method_original' : 'GET' ,
83- 'http.response.status_code' : 200 ,
84- 'network.peer.address' : '::1' ,
85- 'network.peer.port' : 3030 ,
86- 'otel.kind' : 'CLIENT' ,
87- 'sentry.op' : 'http.client' ,
88- 'sentry.origin' : 'auto.http.otel.node_fetch' ,
89- 'server.address' : 'localhost' ,
90- 'server.port' : 3030 ,
91- url : 'http://localhost:3030/' ,
92- 'url.full' : 'http://localhost:3030/' ,
93- 'url.path' : '/' ,
94- 'url.query' : '' ,
95- 'url.scheme' : 'http' ,
96- 'user_agent.original' : 'node' ,
97- } ,
98- description : 'GET http://localhost:3030/' ,
99- op : 'http.client' ,
100- origin : 'auto.http.otel.node_fetch' ,
101- parent_span_id : expect . stringMatching ( / [ a - f 0 - 9 ] { 16 } / ) ,
102- span_id : expect . stringMatching ( / [ a - f 0 - 9 ] { 16 } / ) ,
103- start_timestamp : expect . any ( Number ) ,
104- status : 'ok' ,
105- timestamp : expect . any ( Number ) ,
106- trace_id : expect . stringMatching ( / [ a - f 0 - 9 ] { 32 } / ) ,
107- } ,
108- ] ) ,
109- ) ;
110-
83+ // Breadcrumbs should always be created for the fetch request
11184 expect ( middlewareTransaction . breadcrumbs ) . toEqual (
11285 expect . arrayContaining ( [
11386 {
@@ -118,4 +91,52 @@ test('Should trace outgoing fetch requests inside middleware and create breadcru
11891 } ,
11992 ] ) ,
12093 ) ;
94+
95+ // Check if http.client span exists as a child of the middleware transaction
96+ const hasHttpClientSpan = ! ! middlewareTransaction . spans ?. find ( span => span . op === 'http.client' ) ;
97+
98+ if ( hasHttpClientSpan ) {
99+ // Check if fetch is traced as a child span of the middleware transaction
100+ expect ( middlewareTransaction . spans ) . toEqual (
101+ expect . arrayContaining ( [
102+ {
103+ data : {
104+ 'http.request.method' : 'GET' ,
105+ 'http.request.method_original' : 'GET' ,
106+ 'http.response.status_code' : 200 ,
107+ 'network.peer.address' : '::1' ,
108+ 'network.peer.port' : 3030 ,
109+ 'otel.kind' : 'CLIENT' ,
110+ 'sentry.op' : 'http.client' ,
111+ 'sentry.origin' : 'auto.http.otel.node_fetch' ,
112+ 'server.address' : 'localhost' ,
113+ 'server.port' : 3030 ,
114+ url : 'http://localhost:3030/' ,
115+ 'url.full' : 'http://localhost:3030/' ,
116+ 'url.path' : '/' ,
117+ 'url.query' : '' ,
118+ 'url.scheme' : 'http' ,
119+ 'user_agent.original' : 'node' ,
120+ } ,
121+ description : 'GET http://localhost:3030/' ,
122+ op : 'http.client' ,
123+ origin : 'auto.http.otel.node_fetch' ,
124+ parent_span_id : expect . stringMatching ( / [ a - f 0 - 9 ] { 16 } / ) ,
125+ span_id : expect . stringMatching ( / [ a - f 0 - 9 ] { 16 } / ) ,
126+ start_timestamp : expect . any ( Number ) ,
127+ status : 'ok' ,
128+ timestamp : expect . any ( Number ) ,
129+ trace_id : expect . stringMatching ( / [ a - f 0 - 9 ] { 32 } / ) ,
130+ } ,
131+ ] ) ,
132+ ) ;
133+ } else {
134+ // Alternatively, fetch is traced as a separate transaction, similar to Dev builds
135+ const fetchTransaction = await fetchTransactionPromise ;
136+
137+ expect ( fetchTransaction . contexts ?. trace ?. op ) . toBe ( 'http.client' ) ;
138+ expect ( fetchTransaction . contexts ?. trace ?. status ) . toBe ( 'ok' ) ;
139+ expect ( fetchTransaction . contexts ?. trace ?. data ?. [ 'http.request.method' ] ) . toBe ( 'GET' ) ;
140+ expect ( fetchTransaction . contexts ?. trace ?. data ?. [ 'url.full' ] ) . toBe ( 'http://localhost:3030/' ) ;
141+ }
121142} ) ;
0 commit comments