@@ -98,6 +98,47 @@ describe('startAbortPoller heartbeat', () => {
9898 }
9999 } )
100100
101+ it ( 'aborts the controller before clearing the marker so the marker is never observable as cleared while the signal is still unaborted' , async ( ) => {
102+ const controller = new AbortController ( )
103+ const streamId = 'stream-order-1'
104+
105+ let signalAbortedWhenMarkerCleared : boolean | null = null
106+ mockClearAbortMarker . mockImplementationOnce ( async ( ) => {
107+ signalAbortedWhenMarkerCleared = controller . signal . aborted
108+ } )
109+ mockHasAbortMarker . mockResolvedValueOnce ( true )
110+
111+ const interval = startAbortPoller ( streamId , controller , { } )
112+
113+ try {
114+ await vi . advanceTimersByTimeAsync ( 300 )
115+
116+ expect ( mockClearAbortMarker ) . toHaveBeenCalledWith ( streamId )
117+ expect ( signalAbortedWhenMarkerCleared ) . toBe ( true )
118+ expect ( controller . signal . aborted ) . toBe ( true )
119+ } finally {
120+ clearInterval ( interval )
121+ }
122+ } )
123+
124+ it ( 'does not clear the marker when the signal is already aborted (no double abort)' , async ( ) => {
125+ const controller = new AbortController ( )
126+ controller . abort ( 'preexisting' )
127+ const streamId = 'stream-order-2'
128+
129+ mockHasAbortMarker . mockResolvedValueOnce ( true )
130+
131+ const interval = startAbortPoller ( streamId , controller , { } )
132+
133+ try {
134+ await vi . advanceTimersByTimeAsync ( 300 )
135+
136+ expect ( mockClearAbortMarker ) . not . toHaveBeenCalled ( )
137+ } finally {
138+ clearInterval ( interval )
139+ }
140+ } )
141+
101142 it ( 'stops heartbeating after ownership is lost' , async ( ) => {
102143 const controller = new AbortController ( )
103144 const streamId = 'stream-lost'
0 commit comments