11import { RPCType } from '@opentelemetry/core' ;
22import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions' ;
33import {
4+ flushIfServerless ,
45 getActiveSpan ,
56 getRootSpan ,
67 getTraceMetaTags ,
@@ -15,13 +16,13 @@ vi.mock('@opentelemetry/core', () => ({
1516 RPCType : { HTTP : 'http' } ,
1617 getRPCMetadata : vi . fn ( ) ,
1718} ) ) ;
18-
1919vi . mock ( '@sentry/core' , ( ) => ( {
2020 SEMANTIC_ATTRIBUTE_SENTRY_SOURCE : 'sentry.source' ,
2121 SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN : 'sentry.origin' ,
2222 getActiveSpan : vi . fn ( ) ,
2323 getRootSpan : vi . fn ( ) ,
2424 getTraceMetaTags : vi . fn ( ) ,
25+ flushIfServerless : vi . fn ( ) ,
2526} ) ) ;
2627
2728describe ( 'wrapSentryHandleRequest' , ( ) => {
@@ -62,7 +63,8 @@ describe('wrapSentryHandleRequest', () => {
6263 ( getActiveSpan as unknown as ReturnType < typeof vi . fn > ) . mockReturnValue ( mockActiveSpan ) ;
6364 ( getRootSpan as unknown as ReturnType < typeof vi . fn > ) . mockReturnValue ( mockRootSpan ) ;
6465 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 ;
6668
6769 const routerContext = {
6870 staticHandlerContext : {
@@ -110,7 +112,8 @@ describe('wrapSentryHandleRequest', () => {
110112 ( getActiveSpan as unknown as ReturnType < typeof vi . fn > ) . mockReturnValue ( null ) ;
111113
112114 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 ;
114117
115118 const routerContext = {
116119 staticHandlerContext : {
@@ -122,6 +125,76 @@ describe('wrapSentryHandleRequest', () => {
122125
123126 expect ( getRPCMetadata ) . not . toHaveBeenCalled ( ) ;
124127 } ) ;
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 ( ) ;
125198} ) ;
126199
127200describe ( 'getMetaTagTransformer' , ( ) => {
@@ -132,68 +205,64 @@ describe('getMetaTagTransformer', () => {
132205 ) ;
133206 } ) ;
134207
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 ) ;
139212
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+ } ) ;
150217
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+ } ) ;
152223
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+ } ) ;
155227 } ) ;
156228
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 ) ;
166233
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+ } ) ;
172238
173- transformer . pipe ( outputStream ) ;
239+ bodyStream . on ( 'end' , ( ) => {
240+ expect ( outputData ) . toBe ( '<html><body>Test</body></html>' ) ;
241+ resolve ( ) ;
242+ } ) ;
174243
175- bodyStream . write ( '<html><body>Test</body></html>' ) ;
176- bodyStream . end ( ) ;
244+ transformer . write ( '<html><body>Test</body></html>' ) ;
245+ transformer . end ( ) ;
246+ } ) ;
177247 } ) ;
178248
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 ) ;
188253
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+ } ) ;
193258
194- transformer . pipe ( outputStream ) ;
259+ bodyStream . on ( 'end' , ( ) => {
260+ expect ( outputData ) . toContain ( '<meta name="sentry-trace" content="test-trace-id"></head>' ) ;
261+ resolve ( ) ;
262+ } ) ;
195263
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+ } ) ;
198267 } ) ;
199268} ) ;
0 commit comments