@@ -514,6 +514,41 @@ describe('nestjsChannelIntegration: @Injectable (middleware/guard/pipe/intercept
514514 expect ( teardowns ) . toHaveLength ( 0 ) ;
515515 } ) ;
516516
517+ it ( 'sync interceptor that short-circuits without next.handle(): ends the before-span' , ( ) => {
518+ installTestAsyncContextStrategy ( ) ;
519+ initTestClient ( ) ;
520+ nestjsChannelIntegration ( ) . setupOnce ! ( ) ;
521+
522+ const teardowns : Array < ( ) => void > = [ ] ;
523+ const observable = {
524+ subscribe ( ) : { add : ( fn : ( ) => void ) => void } {
525+ return { add : ( fn : ( ) => void ) => void teardowns . push ( fn ) } ;
526+ } ,
527+ } ;
528+
529+ let beforeSpan : ReturnType < typeof getActiveSpan > ;
530+ class CachingInterceptor {
531+ // Synchronously returns an Observable without calling `next.handle()`
532+ // (a cache/validation short-circuit).
533+ public intercept ( _context : unknown , _next : { handle : ( ) => unknown } ) : unknown {
534+ beforeSpan = getActiveSpan ( ) ;
535+ return observable ;
536+ }
537+ }
538+ applyInjectable ( CachingInterceptor ) ;
539+
540+ const next = { handle : vi . fn ( ) } ;
541+ const returned = new CachingInterceptor ( ) . intercept ( { } , next ) as typeof observable ;
542+
543+ expect ( returned ) . toBe ( observable ) ;
544+ expect ( next . handle ) . not . toHaveBeenCalled ( ) ;
545+ // before-span is closed even though `next.handle()` (which normally ends it) never ran
546+ expect ( spanToJSON ( beforeSpan ! ) . timestamp ) . toBeDefined ( ) ;
547+ // no after-span, so the observable is left un-instrumented
548+ returned . subscribe ( ) ;
549+ expect ( teardowns ) . toHaveLength ( 0 ) ;
550+ } ) ;
551+
517552 it ( 'skips targets flagged __SENTRY_INTERNAL__' , ( ) => {
518553 installTestAsyncContextStrategy ( ) ;
519554 initTestClient ( ) ;
0 commit comments