@@ -517,6 +517,47 @@ describe('ExpressInstrumentation', () => {
517
517
}
518
518
) ;
519
519
} ) ;
520
+
521
+ it ( 'should keep the handle properties even if router is patched before instrumentation does it' , async ( ) => {
522
+ const rootSpan = tracer . startSpan ( 'rootSpan' ) ;
523
+ let routerLayer : { name : string ; handle : { stack : any [ ] } } ;
524
+
525
+ const expressApp = express ( ) ;
526
+ const router = express . Router ( ) ;
527
+ const CustomRouter : ( ...p : Parameters < typeof router > ) => void = (
528
+ req ,
529
+ res ,
530
+ next
531
+ ) => router ( req , res , next ) ;
532
+ router . use ( '/:slug' , ( req , res , next ) => {
533
+ const stack = req . app . _router . stack as any [ ] ;
534
+ routerLayer = stack . find ( router => router . name === 'CustomRouter' ) ;
535
+ return res . status ( 200 ) . end ( 'bar' ) ;
536
+ } ) ;
537
+ // The patched router now has express router's own properties in its prototype so
538
+ // they are not accessible through `Object.keys(...)`
539
+ // https://github.com/TryGhost/Ghost/blob/fefb9ec395df8695d06442b6ecd3130dae374d94/ghost/core/core/frontend/web/site.js#L192
540
+ Object . setPrototypeOf ( CustomRouter , router ) ;
541
+ expressApp . use ( CustomRouter ) ;
542
+
543
+ const httpServer = await createServer ( expressApp ) ;
544
+ server = httpServer . server ;
545
+ port = httpServer . port ;
546
+ await context . with (
547
+ trace . setSpan ( context . active ( ) , rootSpan ) ,
548
+ async ( ) => {
549
+ const response = await httpRequest . get (
550
+ `http://localhost:${ port } /foo`
551
+ ) ;
552
+ assert . strictEqual ( response , 'bar' ) ;
553
+ rootSpan . end ( ) ;
554
+ assert . ok (
555
+ routerLayer . handle . stack . length === 1 ,
556
+ 'router layer stack is accessible'
557
+ ) ;
558
+ }
559
+ ) ;
560
+ } ) ;
520
561
} ) ;
521
562
522
563
describe ( 'Disabling plugin' , ( ) => {
0 commit comments