@@ -19,16 +19,23 @@ test.describe('Server Middleware Instrumentation', () => {
1919 // Verify that we have spans for each middleware
2020 const middlewareSpans = serverTxnEvent . spans ?. filter ( span => span . op === 'middleware.nuxt' ) || [ ] ;
2121
22- expect ( middlewareSpans ) . toHaveLength ( 3 ) ;
22+ // 3 simple + 3 hooks (onRequest+handler+onBeforeResponse) + 5 array hooks (2 onRequest + 1 handler + 2 onBeforeResponse)
23+ expect ( middlewareSpans ) . toHaveLength ( 11 ) ;
2324
2425 // Check for specific middleware spans
25- const firstMiddlewareSpan = middlewareSpans . find ( span => span . data ?. [ 'nuxt.middleware.name' ] === '01.first.ts' ) ;
26- const secondMiddlewareSpan = middlewareSpans . find ( span => span . data ?. [ 'nuxt.middleware.name' ] === '02.second.ts' ) ;
27- const authMiddlewareSpan = middlewareSpans . find ( span => span . data ?. [ 'nuxt.middleware.name' ] === '03.auth.ts' ) ;
26+ const firstMiddlewareSpan = middlewareSpans . find ( span => span . data ?. [ 'nuxt.middleware.name' ] === '01.first' ) ;
27+ const secondMiddlewareSpan = middlewareSpans . find ( span => span . data ?. [ 'nuxt.middleware.name' ] === '02.second' ) ;
28+ const authMiddlewareSpan = middlewareSpans . find ( span => span . data ?. [ 'nuxt.middleware.name' ] === '03.auth' ) ;
29+ const hooksOnRequestSpan = middlewareSpans . find ( span => span . data ?. [ 'nuxt.middleware.name' ] === '04.hooks' ) ;
30+ const arrayHooksHandlerSpan = middlewareSpans . find (
31+ span => span . data ?. [ 'nuxt.middleware.name' ] === '05.array-hooks' ,
32+ ) ;
2833
2934 expect ( firstMiddlewareSpan ) . toBeDefined ( ) ;
3035 expect ( secondMiddlewareSpan ) . toBeDefined ( ) ;
3136 expect ( authMiddlewareSpan ) . toBeDefined ( ) ;
37+ expect ( hooksOnRequestSpan ) . toBeDefined ( ) ;
38+ expect ( arrayHooksHandlerSpan ) . toBeDefined ( ) ;
3239
3340 // Verify each span has the correct attributes
3441 [ firstMiddlewareSpan , secondMiddlewareSpan , authMiddlewareSpan ] . forEach ( span => {
@@ -37,7 +44,7 @@ test.describe('Server Middleware Instrumentation', () => {
3744 op : 'middleware.nuxt' ,
3845 data : expect . objectContaining ( {
3946 'sentry.op' : 'middleware.nuxt' ,
40- 'sentry.origin' : 'auto.http .nuxt' ,
47+ 'sentry.origin' : 'auto.middleware .nuxt' ,
4148 'sentry.source' : 'custom' ,
4249 'http.request.method' : 'GET' ,
4350 'http.route' : '/api/middleware-test' ,
@@ -52,7 +59,8 @@ test.describe('Server Middleware Instrumentation', () => {
5259 // Verify spans have different span IDs (each middleware gets its own span)
5360 const spanIds = middlewareSpans . map ( span => span . span_id ) ;
5461 const uniqueSpanIds = new Set ( spanIds ) ;
55- expect ( uniqueSpanIds . size ) . toBe ( 3 ) ;
62+ // 3 simple + 3 hooks (onRequest+handler+onBeforeResponse) + 5 array hooks (2 onRequest + 1 handler + 2 onBeforeResponse)
63+ expect ( uniqueSpanIds . size ) . toBe ( 11 ) ;
5664
5765 // Verify spans share the same trace ID
5866 const traceIds = middlewareSpans . map ( span => span . trace_id ) ;
@@ -95,7 +103,7 @@ test.describe('Server Middleware Instrumentation', () => {
95103
96104 // Find the auth middleware span
97105 const authMiddlewareSpan = serverTxnEvent . spans ?. find (
98- span => span . op === 'middleware.nuxt' && span . data ?. [ 'nuxt.middleware.name' ] === '03.auth.ts ' ,
106+ span => span . op === 'middleware.nuxt' && span . data ?. [ 'nuxt.middleware.name' ] === '03.auth' ,
99107 ) ;
100108
101109 expect ( authMiddlewareSpan ) . toBeDefined ( ) ;
@@ -113,9 +121,212 @@ test.describe('Server Middleware Instrumentation', () => {
113121 type : 'Error' ,
114122 mechanism : expect . objectContaining ( {
115123 handled : false ,
116- type : 'auto.http .nuxt' ,
124+ type : 'auto.middleware .nuxt' ,
117125 } ) ,
118126 } ) ,
119127 ) ;
120128 } ) ;
129+
130+ test ( 'should create spans for onRequest and onBeforeResponse hooks' , async ( { request } ) => {
131+ const serverTxnEventPromise = waitForTransaction ( 'nuxt-3' , txnEvent => {
132+ return txnEvent . transaction ?. includes ( 'GET /api/middleware-test' ) ?? false ;
133+ } ) ;
134+
135+ // Make request to trigger middleware with hooks
136+ const response = await request . get ( '/api/middleware-test' ) ;
137+ expect ( response . status ( ) ) . toBe ( 200 ) ;
138+
139+ const serverTxnEvent = await serverTxnEventPromise ;
140+ const middlewareSpans = serverTxnEvent . spans ?. filter ( span => span . op === 'middleware.nuxt' ) || [ ] ;
141+
142+ // Find spans for the hooks middleware
143+ const hooksSpans = middlewareSpans . filter ( span => span . data ?. [ 'nuxt.middleware.name' ] === '04.hooks' ) ;
144+
145+ // Should have spans for onRequest, handler, and onBeforeResponse
146+ expect ( hooksSpans ) . toHaveLength ( 3 ) ;
147+
148+ // Find specific hook spans
149+ const onRequestSpan = hooksSpans . find ( span => span . data ?. [ 'nuxt.middleware.hook.name' ] === 'onRequest' ) ;
150+ const handlerSpan = hooksSpans . find ( span => span . data ?. [ 'nuxt.middleware.hook.name' ] === 'handler' ) ;
151+ const onBeforeResponseSpan = hooksSpans . find (
152+ span => span . data ?. [ 'nuxt.middleware.hook.name' ] === 'onBeforeResponse' ,
153+ ) ;
154+
155+ expect ( onRequestSpan ) . toBeDefined ( ) ;
156+ expect ( handlerSpan ) . toBeDefined ( ) ;
157+ expect ( onBeforeResponseSpan ) . toBeDefined ( ) ;
158+
159+ // Verify span names include hook types
160+ expect ( onRequestSpan ?. description ) . toBe ( '04.hooks.onRequest' ) ;
161+ expect ( handlerSpan ?. description ) . toBe ( '04.hooks' ) ;
162+ expect ( onBeforeResponseSpan ?. description ) . toBe ( '04.hooks.onBeforeResponse' ) ;
163+
164+ // Verify all spans have correct middleware name (without hook suffix)
165+ [ onRequestSpan , handlerSpan , onBeforeResponseSpan ] . forEach ( span => {
166+ expect ( span ?. data ?. [ 'nuxt.middleware.name' ] ) . toBe ( '04.hooks' ) ;
167+ } ) ;
168+
169+ // Verify hook-specific attributes
170+ expect ( onRequestSpan ?. data ?. [ 'nuxt.middleware.hook.name' ] ) . toBe ( 'onRequest' ) ;
171+ expect ( handlerSpan ?. data ?. [ 'nuxt.middleware.hook.name' ] ) . toBe ( 'handler' ) ;
172+ expect ( onBeforeResponseSpan ?. data ?. [ 'nuxt.middleware.hook.name' ] ) . toBe ( 'onBeforeResponse' ) ;
173+
174+ // Verify no index attributes for single hooks
175+ expect ( onRequestSpan ?. data ) . not . toHaveProperty ( 'nuxt.middleware.hook.index' ) ;
176+ expect ( handlerSpan ?. data ) . not . toHaveProperty ( 'nuxt.middleware.hook.index' ) ;
177+ expect ( onBeforeResponseSpan ?. data ) . not . toHaveProperty ( 'nuxt.middleware.hook.index' ) ;
178+ } ) ;
179+
180+ test ( 'should create spans with index attributes for array hooks' , async ( { request } ) => {
181+ const serverTxnEventPromise = waitForTransaction ( 'nuxt-3' , txnEvent => {
182+ return txnEvent . transaction ?. includes ( 'GET /api/middleware-test' ) ?? false ;
183+ } ) ;
184+
185+ // Make request to trigger middleware with array hooks
186+ const response = await request . get ( '/api/middleware-test' ) ;
187+ expect ( response . status ( ) ) . toBe ( 200 ) ;
188+
189+ const serverTxnEvent = await serverTxnEventPromise ;
190+ const middlewareSpans = serverTxnEvent . spans ?. filter ( span => span . op === 'middleware.nuxt' ) || [ ] ;
191+
192+ // Find spans for the array hooks middleware
193+ const arrayHooksSpans = middlewareSpans . filter ( span => span . data ?. [ 'nuxt.middleware.name' ] === '05.array-hooks' ) ;
194+
195+ // Should have spans for 2 onRequest + 1 handler + 2 onBeforeResponse = 5 spans
196+ expect ( arrayHooksSpans ) . toHaveLength ( 5 ) ;
197+
198+ // Find onRequest array spans
199+ const onRequestSpans = arrayHooksSpans . filter ( span => span . data ?. [ 'nuxt.middleware.hook.name' ] === 'onRequest' ) ;
200+ expect ( onRequestSpans ) . toHaveLength ( 2 ) ;
201+
202+ // Find onBeforeResponse array spans
203+ const onBeforeResponseSpans = arrayHooksSpans . filter (
204+ span => span . data ?. [ 'nuxt.middleware.hook.name' ] === 'onBeforeResponse' ,
205+ ) ;
206+ expect ( onBeforeResponseSpans ) . toHaveLength ( 2 ) ;
207+
208+ // Find handler span
209+ const handlerSpan = arrayHooksSpans . find ( span => span . data ?. [ 'nuxt.middleware.hook.name' ] === 'handler' ) ;
210+ expect ( handlerSpan ) . toBeDefined ( ) ;
211+
212+ // Verify index attributes for onRequest array
213+ const onRequest0Span = onRequestSpans . find ( span => span . data ?. [ 'nuxt.middleware.hook.index' ] === 0 ) ;
214+ const onRequest1Span = onRequestSpans . find ( span => span . data ?. [ 'nuxt.middleware.hook.index' ] === 1 ) ;
215+
216+ expect ( onRequest0Span ) . toBeDefined ( ) ;
217+ expect ( onRequest1Span ) . toBeDefined ( ) ;
218+
219+ // Verify index attributes for onBeforeResponse array
220+ const onBeforeResponse0Span = onBeforeResponseSpans . find ( span => span . data ?. [ 'nuxt.middleware.hook.index' ] === 0 ) ;
221+ const onBeforeResponse1Span = onBeforeResponseSpans . find ( span => span . data ?. [ 'nuxt.middleware.hook.index' ] === 1 ) ;
222+
223+ expect ( onBeforeResponse0Span ) . toBeDefined ( ) ;
224+ expect ( onBeforeResponse1Span ) . toBeDefined ( ) ;
225+
226+ // Verify span names for array handlers
227+ expect ( onRequest0Span ?. description ) . toBe ( '05.array-hooks.onRequest' ) ;
228+ expect ( onRequest1Span ?. description ) . toBe ( '05.array-hooks.onRequest' ) ;
229+ expect ( onBeforeResponse0Span ?. description ) . toBe ( '05.array-hooks.onBeforeResponse' ) ;
230+ expect ( onBeforeResponse1Span ?. description ) . toBe ( '05.array-hooks.onBeforeResponse' ) ;
231+
232+ // Verify handler has no index
233+ expect ( handlerSpan ?. data ) . not . toHaveProperty ( 'nuxt.middleware.hook.index' ) ;
234+ } ) ;
235+
236+ test ( 'should handle errors in onRequest hooks' , async ( { request } ) => {
237+ const serverTxnEventPromise = waitForTransaction ( 'nuxt-3' , txnEvent => {
238+ return txnEvent . transaction ?. includes ( 'GET /api/middleware-test' ) ?? false ;
239+ } ) ;
240+
241+ const errorEventPromise = waitForError ( 'nuxt-3' , errorEvent => {
242+ return errorEvent ?. exception ?. values ?. [ 0 ] ?. value === 'OnRequest hook error' ;
243+ } ) ;
244+
245+ // Make request with query param to trigger error in onRequest
246+ const response = await request . get ( '/api/middleware-test?throwOnRequestError=true' ) ;
247+ expect ( response . status ( ) ) . toBe ( 500 ) ;
248+
249+ const [ serverTxnEvent , errorEvent ] = await Promise . all ( [ serverTxnEventPromise , errorEventPromise ] ) ;
250+
251+ // Find the onRequest span that should have error status
252+ const onRequestSpan = serverTxnEvent . spans ?. find (
253+ span =>
254+ span . op === 'middleware.nuxt' &&
255+ span . data ?. [ 'nuxt.middleware.name' ] === '04.hooks' &&
256+ span . data ?. [ 'nuxt.middleware.hook.name' ] === 'onRequest' ,
257+ ) ;
258+
259+ expect ( onRequestSpan ) . toBeDefined ( ) ;
260+ expect ( onRequestSpan ?. status ) . toBe ( 'internal_error' ) ;
261+ expect ( errorEvent . exception ?. values ?. [ 0 ] ?. value ) . toBe ( 'OnRequest hook error' ) ;
262+ } ) ;
263+
264+ test ( 'should handle errors in onBeforeResponse hooks' , async ( { request } ) => {
265+ const serverTxnEventPromise = waitForTransaction ( 'nuxt-3' , txnEvent => {
266+ return txnEvent . transaction ?. includes ( 'GET /api/middleware-test' ) ?? false ;
267+ } ) ;
268+
269+ const errorEventPromise = waitForError ( 'nuxt-3' , errorEvent => {
270+ return errorEvent ?. exception ?. values ?. [ 0 ] ?. value === 'OnBeforeResponse hook error' ;
271+ } ) ;
272+
273+ // Make request with query param to trigger error in onBeforeResponse
274+ const response = await request . get ( '/api/middleware-test?throwOnBeforeResponseError=true' ) ;
275+ expect ( response . status ( ) ) . toBe ( 500 ) ;
276+
277+ const [ serverTxnEvent , errorEvent ] = await Promise . all ( [ serverTxnEventPromise , errorEventPromise ] ) ;
278+
279+ // Find the onBeforeResponse span that should have error status
280+ const onBeforeResponseSpan = serverTxnEvent . spans ?. find (
281+ span =>
282+ span . op === 'middleware.nuxt' &&
283+ span . data ?. [ 'nuxt.middleware.name' ] === '04.hooks' &&
284+ span . data ?. [ 'nuxt.middleware.hook.name' ] === 'onBeforeResponse' ,
285+ ) ;
286+
287+ expect ( onBeforeResponseSpan ) . toBeDefined ( ) ;
288+ expect ( onBeforeResponseSpan ?. status ) . toBe ( 'internal_error' ) ;
289+ expect ( errorEvent . exception ?. values ?. [ 0 ] ?. value ) . toBe ( 'OnBeforeResponse hook error' ) ;
290+ } ) ;
291+
292+ test ( 'should handle errors in array hooks with proper index attribution' , async ( { request } ) => {
293+ const serverTxnEventPromise = waitForTransaction ( 'nuxt-3' , txnEvent => {
294+ return txnEvent . transaction ?. includes ( 'GET /api/middleware-test' ) ?? false ;
295+ } ) ;
296+
297+ const errorEventPromise = waitForError ( 'nuxt-3' , errorEvent => {
298+ return errorEvent ?. exception ?. values ?. [ 0 ] ?. value === 'OnRequest[1] hook error' ;
299+ } ) ;
300+
301+ // Make request with query param to trigger error in second onRequest handler
302+ const response = await request . get ( '/api/middleware-test?throwOnRequest1Error=true' ) ;
303+ expect ( response . status ( ) ) . toBe ( 500 ) ;
304+
305+ const [ serverTxnEvent , errorEvent ] = await Promise . all ( [ serverTxnEventPromise , errorEventPromise ] ) ;
306+
307+ // Find the second onRequest span that should have error status
308+ const onRequest1Span = serverTxnEvent . spans ?. find (
309+ span =>
310+ span . op === 'middleware.nuxt' &&
311+ span . data ?. [ 'nuxt.middleware.name' ] === '05.array-hooks' &&
312+ span . data ?. [ 'nuxt.middleware.hook.name' ] === 'onRequest' &&
313+ span . data ?. [ 'nuxt.middleware.hook.index' ] === 1 ,
314+ ) ;
315+
316+ expect ( onRequest1Span ) . toBeDefined ( ) ;
317+ expect ( onRequest1Span ?. status ) . toBe ( 'internal_error' ) ;
318+ expect ( errorEvent . exception ?. values ?. [ 0 ] ?. value ) . toBe ( 'OnRequest[1] hook error' ) ;
319+
320+ // Verify the first onRequest handler still executed successfully
321+ const onRequest0Span = serverTxnEvent . spans ?. find (
322+ span =>
323+ span . op === 'middleware.nuxt' &&
324+ span . data ?. [ 'nuxt.middleware.name' ] === '05.array-hooks' &&
325+ span . data ?. [ 'nuxt.middleware.hook.name' ] === 'onRequest' &&
326+ span . data ?. [ 'nuxt.middleware.hook.index' ] === 0 ,
327+ ) ;
328+
329+ expect ( onRequest0Span ) . toBeDefined ( ) ;
330+ expect ( onRequest0Span ?. status ) . not . toBe ( 'internal_error' ) ;
331+ } ) ;
121332} ) ;
0 commit comments