1
1
import { RPCType } from '@opentelemetry/core' ;
2
2
import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions' ;
3
3
import {
4
+ flushIfServerless ,
4
5
getActiveSpan ,
5
6
getRootSpan ,
6
7
getTraceMetaTags ,
@@ -15,13 +16,13 @@ vi.mock('@opentelemetry/core', () => ({
15
16
RPCType : { HTTP : 'http' } ,
16
17
getRPCMetadata : vi . fn ( ) ,
17
18
} ) ) ;
18
-
19
19
vi . mock ( '@sentry/core' , ( ) => ( {
20
20
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE : 'sentry.source' ,
21
21
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN : 'sentry.origin' ,
22
22
getActiveSpan : vi . fn ( ) ,
23
23
getRootSpan : vi . fn ( ) ,
24
24
getTraceMetaTags : vi . fn ( ) ,
25
+ flushIfServerless : vi . fn ( ) ,
25
26
} ) ) ;
26
27
27
28
describe ( 'wrapSentryHandleRequest' , ( ) => {
@@ -62,7 +63,8 @@ describe('wrapSentryHandleRequest', () => {
62
63
( getActiveSpan as unknown as ReturnType < typeof vi . fn > ) . mockReturnValue ( mockActiveSpan ) ;
63
64
( getRootSpan as unknown as ReturnType < typeof vi . fn > ) . mockReturnValue ( mockRootSpan ) ;
64
65
const getRPCMetadata = vi . fn ( ) . mockReturnValue ( mockRpcMetadata ) ;
65
- vi . mocked ( vi . importActual ( '@opentelemetry/core' ) ) . getRPCMetadata = getRPCMetadata ;
66
+ ( vi . importActual ( '@opentelemetry/core' ) as unknown as { getRPCMetadata : typeof getRPCMetadata } ) . getRPCMetadata =
67
+ getRPCMetadata ;
66
68
67
69
const routerContext = {
68
70
staticHandlerContext : {
@@ -110,7 +112,8 @@ describe('wrapSentryHandleRequest', () => {
110
112
( getActiveSpan as unknown as ReturnType < typeof vi . fn > ) . mockReturnValue ( null ) ;
111
113
112
114
const getRPCMetadata = vi . fn ( ) . mockReturnValue ( mockRpcMetadata ) ;
113
- vi . mocked ( vi . importActual ( '@opentelemetry/core' ) ) . getRPCMetadata = getRPCMetadata ;
115
+ ( vi . importActual ( '@opentelemetry/core' ) as unknown as { getRPCMetadata : typeof getRPCMetadata } ) . getRPCMetadata =
116
+ getRPCMetadata ;
114
117
115
118
const routerContext = {
116
119
staticHandlerContext : {
@@ -122,6 +125,76 @@ describe('wrapSentryHandleRequest', () => {
122
125
123
126
expect ( getRPCMetadata ) . not . toHaveBeenCalled ( ) ;
124
127
} ) ;
128
+
129
+ test ( 'should call flushIfServerless on successful execution' , async ( ) => {
130
+ const originalHandler = vi . fn ( ) . mockResolvedValue ( 'success response' ) ;
131
+ const wrappedHandler = wrapSentryHandleRequest ( originalHandler ) ;
132
+
133
+ const request = new Request ( 'https://example.com' ) ;
134
+ const responseStatusCode = 200 ;
135
+ const responseHeaders = new Headers ( ) ;
136
+ const routerContext = { staticHandlerContext : { matches : [ ] } } as any ;
137
+ const loadContext = { } as any ;
138
+
139
+ await wrappedHandler ( request , responseStatusCode , responseHeaders , routerContext , loadContext ) ;
140
+
141
+ expect ( flushIfServerless ) . toHaveBeenCalled ( ) ;
142
+ } ) ;
143
+
144
+ test ( 'should call flushIfServerless even when original handler throws an error' , async ( ) => {
145
+ const mockError = new Error ( 'Handler failed' ) ;
146
+ const originalHandler = vi . fn ( ) . mockRejectedValue ( mockError ) ;
147
+ const wrappedHandler = wrapSentryHandleRequest ( originalHandler ) ;
148
+
149
+ const request = new Request ( 'https://example.com' ) ;
150
+ const responseStatusCode = 200 ;
151
+ const responseHeaders = new Headers ( ) ;
152
+ const routerContext = { staticHandlerContext : { matches : [ ] } } as any ;
153
+ const loadContext = { } as any ;
154
+
155
+ await expect (
156
+ wrappedHandler ( request , responseStatusCode , responseHeaders , routerContext , loadContext ) ,
157
+ ) . rejects . toThrow ( 'Handler failed' ) ;
158
+
159
+ expect ( flushIfServerless ) . toHaveBeenCalled ( ) ;
160
+ } ) ;
161
+
162
+ test ( 'should propagate errors from original handler' , async ( ) => {
163
+ const mockError = new Error ( 'Test error' ) ;
164
+ const originalHandler = vi . fn ( ) . mockRejectedValue ( mockError ) ;
165
+ const wrappedHandler = wrapSentryHandleRequest ( originalHandler ) ;
166
+
167
+ const request = new Request ( 'https://example.com' ) ;
168
+ const responseStatusCode = 500 ;
169
+ const responseHeaders = new Headers ( ) ;
170
+ const routerContext = { staticHandlerContext : { matches : [ ] } } as any ;
171
+ const loadContext = { } as any ;
172
+
173
+ await expect ( wrappedHandler ( request , responseStatusCode , responseHeaders , routerContext , loadContext ) ) . rejects . toBe (
174
+ mockError ,
175
+ ) ;
176
+ } ) ;
177
+ } ) ;
178
+
179
+ test ( 'should not set span attributes when parameterized path does not exist' , async ( ) => {
180
+ const mockActiveSpan = { } ;
181
+ const mockRootSpan = { setAttributes : vi . fn ( ) } ;
182
+
183
+ ( getActiveSpan as unknown as ReturnType < typeof vi . fn > ) . mockReturnValue ( mockActiveSpan ) ;
184
+ ( getRootSpan as unknown as ReturnType < typeof vi . fn > ) . mockReturnValue ( mockRootSpan ) ;
185
+
186
+ const originalHandler = vi . fn ( ) . mockResolvedValue ( 'test' ) ;
187
+ const wrappedHandler = wrapSentryHandleRequest ( originalHandler ) ;
188
+
189
+ const routerContext = {
190
+ staticHandlerContext : {
191
+ matches : [ ] ,
192
+ } ,
193
+ } as any ;
194
+
195
+ await wrappedHandler ( new Request ( 'https://guapo.chulo' ) , 200 , new Headers ( ) , routerContext , { } as any ) ;
196
+
197
+ expect ( mockRootSpan . setAttributes ) . not . toHaveBeenCalled ( ) ;
125
198
} ) ;
126
199
127
200
describe ( 'getMetaTagTransformer' , ( ) => {
@@ -132,68 +205,64 @@ describe('getMetaTagTransformer', () => {
132
205
) ;
133
206
} ) ;
134
207
135
- test ( 'should inject meta tags before closing head tag' , done => {
136
- const outputStream = new PassThrough ( ) ;
137
- const bodyStream = new PassThrough ( ) ;
138
- const transformer = getMetaTagTransformer ( bodyStream ) ;
208
+ test ( 'should inject meta tags before closing head tag' , ( ) => {
209
+ return new Promise < void > ( resolve => {
210
+ const bodyStream = new PassThrough ( ) ;
211
+ const transformer = getMetaTagTransformer ( bodyStream ) ;
139
212
140
- let outputData = '' ;
141
- outputStream . on ( 'data' , chunk => {
142
- outputData += chunk . toString ( ) ;
143
- } ) ;
144
-
145
- outputStream . on ( 'end' , ( ) => {
146
- expect ( outputData ) . toContain ( '<meta name="sentry-trace" content="test-trace-id"></head>' ) ;
147
- expect ( outputData ) . not . toContain ( '</head></head>' ) ;
148
- done ( ) ;
149
- } ) ;
213
+ let outputData = '' ;
214
+ bodyStream . on ( 'data' , chunk => {
215
+ outputData += chunk . toString ( ) ;
216
+ } ) ;
150
217
151
- transformer . pipe ( outputStream ) ;
218
+ bodyStream . on ( 'end' , ( ) => {
219
+ expect ( outputData ) . toContain ( '<meta name="sentry-trace" content="test-trace-id"></head>' ) ;
220
+ expect ( outputData ) . not . toContain ( '</head></head>' ) ;
221
+ resolve ( ) ;
222
+ } ) ;
152
223
153
- bodyStream . write ( '<html><head></head><body>Test</body></html>' ) ;
154
- bodyStream . end ( ) ;
224
+ transformer . write ( '<html><head></head><body>Test</body></html>' ) ;
225
+ transformer . end ( ) ;
226
+ } ) ;
155
227
} ) ;
156
228
157
- test ( 'should not modify chunks without head closing tag' , done => {
158
- const outputStream = new PassThrough ( ) ;
159
- const bodyStream = new PassThrough ( ) ;
160
- const transformer = getMetaTagTransformer ( bodyStream ) ;
161
-
162
- let outputData = '' ;
163
- outputStream . on ( 'data' , chunk => {
164
- outputData += chunk . toString ( ) ;
165
- } ) ;
229
+ test ( 'should not modify chunks without head closing tag' , ( ) => {
230
+ return new Promise < void > ( resolve => {
231
+ const bodyStream = new PassThrough ( ) ;
232
+ const transformer = getMetaTagTransformer ( bodyStream ) ;
166
233
167
- outputStream . on ( 'end' , ( ) => {
168
- expect ( outputData ) . toBe ( '<html><body>Test</body></html>' ) ;
169
- expect ( getTraceMetaTags ) . toHaveBeenCalled ( ) ;
170
- done ( ) ;
171
- } ) ;
234
+ let outputData = '' ;
235
+ bodyStream . on ( 'data' , chunk => {
236
+ outputData += chunk . toString ( ) ;
237
+ } ) ;
172
238
173
- transformer . pipe ( outputStream ) ;
239
+ bodyStream . on ( 'end' , ( ) => {
240
+ expect ( outputData ) . toBe ( '<html><body>Test</body></html>' ) ;
241
+ resolve ( ) ;
242
+ } ) ;
174
243
175
- bodyStream . write ( '<html><body>Test</body></html>' ) ;
176
- bodyStream . end ( ) ;
244
+ transformer . write ( '<html><body>Test</body></html>' ) ;
245
+ transformer . end ( ) ;
246
+ } ) ;
177
247
} ) ;
178
248
179
- test ( 'should handle buffer input' , done => {
180
- const outputStream = new PassThrough ( ) ;
181
- const bodyStream = new PassThrough ( ) ;
182
- const transformer = getMetaTagTransformer ( bodyStream ) ;
183
-
184
- let outputData = '' ;
185
- outputStream . on ( 'data' , chunk => {
186
- outputData += chunk . toString ( ) ;
187
- } ) ;
249
+ test ( 'should handle buffer input' , ( ) => {
250
+ return new Promise < void > ( resolve => {
251
+ const bodyStream = new PassThrough ( ) ;
252
+ const transformer = getMetaTagTransformer ( bodyStream ) ;
188
253
189
- outputStream . on ( 'end' , ( ) => {
190
- expect ( outputData ) . toContain ( '<meta name="sentry-trace" content="test-trace-id"></head>' ) ;
191
- done ( ) ;
192
- } ) ;
254
+ let outputData = '' ;
255
+ bodyStream . on ( 'data' , chunk => {
256
+ outputData += chunk . toString ( ) ;
257
+ } ) ;
193
258
194
- transformer . pipe ( outputStream ) ;
259
+ bodyStream . on ( 'end' , ( ) => {
260
+ expect ( outputData ) . toContain ( '<meta name="sentry-trace" content="test-trace-id"></head>' ) ;
261
+ resolve ( ) ;
262
+ } ) ;
195
263
196
- bodyStream . write ( Buffer . from ( '<html><head></head><body>Test</body></html>' ) ) ;
197
- bodyStream . end ( ) ;
264
+ transformer . write ( Buffer . from ( '<html><head></head><body>Test</body></html>' ) ) ;
265
+ transformer . end ( ) ;
266
+ } ) ;
198
267
} ) ;
199
268
} ) ;
0 commit comments