@@ -19,16 +19,23 @@ test.describe('Server Middleware Instrumentation', () => {
19
19
// Verify that we have spans for each middleware
20
20
const middlewareSpans = serverTxnEvent . spans ?. filter ( span => span . op === 'middleware.nuxt' ) || [ ] ;
21
21
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 ) ;
23
24
24
25
// 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
+ ) ;
28
33
29
34
expect ( firstMiddlewareSpan ) . toBeDefined ( ) ;
30
35
expect ( secondMiddlewareSpan ) . toBeDefined ( ) ;
31
36
expect ( authMiddlewareSpan ) . toBeDefined ( ) ;
37
+ expect ( hooksOnRequestSpan ) . toBeDefined ( ) ;
38
+ expect ( arrayHooksHandlerSpan ) . toBeDefined ( ) ;
32
39
33
40
// Verify each span has the correct attributes
34
41
[ firstMiddlewareSpan , secondMiddlewareSpan , authMiddlewareSpan ] . forEach ( span => {
@@ -37,7 +44,7 @@ test.describe('Server Middleware Instrumentation', () => {
37
44
op : 'middleware.nuxt' ,
38
45
data : expect . objectContaining ( {
39
46
'sentry.op' : 'middleware.nuxt' ,
40
- 'sentry.origin' : 'auto.http .nuxt' ,
47
+ 'sentry.origin' : 'auto.middleware .nuxt' ,
41
48
'sentry.source' : 'custom' ,
42
49
'http.request.method' : 'GET' ,
43
50
'http.route' : '/api/middleware-test' ,
@@ -52,7 +59,8 @@ test.describe('Server Middleware Instrumentation', () => {
52
59
// Verify spans have different span IDs (each middleware gets its own span)
53
60
const spanIds = middlewareSpans . map ( span => span . span_id ) ;
54
61
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 ) ;
56
64
57
65
// Verify spans share the same trace ID
58
66
const traceIds = middlewareSpans . map ( span => span . trace_id ) ;
@@ -95,7 +103,7 @@ test.describe('Server Middleware Instrumentation', () => {
95
103
96
104
// Find the auth middleware span
97
105
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' ,
99
107
) ;
100
108
101
109
expect ( authMiddlewareSpan ) . toBeDefined ( ) ;
@@ -113,9 +121,212 @@ test.describe('Server Middleware Instrumentation', () => {
113
121
type : 'Error' ,
114
122
mechanism : expect . objectContaining ( {
115
123
handled : false ,
116
- type : 'auto.http .nuxt' ,
124
+ type : 'auto.middleware .nuxt' ,
117
125
} ) ,
118
126
} ) ,
119
127
) ;
120
128
} ) ;
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
+ } ) ;
121
332
} ) ;
0 commit comments