@@ -56,6 +56,16 @@ class TestGatewayPlugin extends GatewayPlugin {
5656 }
5757}
5858
59+ type GatewaySessionState = {
60+ sessionId : string | null ;
61+ resumeGatewayUrl : string | null ;
62+ sequence : number | null ;
63+ } ;
64+
65+ function gatewaySessionState ( gateway : GatewayPlugin ) : GatewaySessionState {
66+ return gateway as unknown as GatewaySessionState ;
67+ }
68+
5969describe ( "GatewayPlugin" , ( ) => {
6070 afterEach ( ( ) => {
6171 vi . useRealTimers ( ) ;
@@ -263,20 +273,71 @@ describe("GatewayPlugin", () => {
263273 expect ( gateway . sockets ) . toHaveLength ( 2 ) ;
264274 } ) ;
265275
266- it ( "re-identifies after non-resumable gateway closes" , async ( ) => {
276+ it . each ( [ GatewayCloseCodes . InvalidSeq , GatewayCloseCodes . AlreadyAuthenticated ] ) (
277+ "re-identifies after non-resumable gateway close %s" ,
278+ async ( closeCode ) => {
279+ vi . useFakeTimers ( ) ;
280+ const gateway = new TestGatewayPlugin ( {
281+ autoInteractions : false ,
282+ url : "wss://gateway.example.test" ,
283+ } ) ;
284+
285+ gateway . connect ( false ) ;
286+ gateway . sockets [ 0 ] ?. emit ( "open" ) ;
287+ gateway . sockets [ 0 ] ?. emit ( "close" , closeCode ) ;
288+ await vi . advanceTimersByTimeAsync ( 2_000 ) ;
289+
290+ expect ( gateway . connectCalls ) . toEqual ( [ false , false ] ) ;
291+ expect ( gateway . sockets ) . toHaveLength ( 2 ) ;
292+ } ,
293+ ) ;
294+
295+ it ( "clears resume state after invalid session false" , async ( ) => {
267296 vi . useFakeTimers ( ) ;
268297 const gateway = new TestGatewayPlugin ( {
269298 autoInteractions : false ,
270299 url : "wss://gateway.example.test" ,
271300 } ) ;
301+ const sessionState = gatewaySessionState ( gateway ) ;
302+ sessionState . sessionId = "session1" ;
303+ sessionState . resumeGatewayUrl = "wss://resume.example.test" ;
304+ sessionState . sequence = 123 ;
272305
273306 gateway . connect ( false ) ;
274307 gateway . sockets [ 0 ] ?. emit ( "open" ) ;
275- gateway . sockets [ 0 ] ?. emit ( "close" , GatewayCloseCodes . InvalidSeq ) ;
308+ (
309+ gateway as unknown as {
310+ handlePayload ( payload : { op : number ; d : unknown } , resume : boolean ) : void ;
311+ }
312+ ) . handlePayload ( { op : GatewayOpcodes . InvalidSession , d : false } , true ) ;
276313 await vi . advanceTimersByTimeAsync ( 2_000 ) ;
277314
278315 expect ( gateway . connectCalls ) . toEqual ( [ false , false ] ) ;
279- expect ( gateway . sockets ) . toHaveLength ( 2 ) ;
316+ expect ( sessionState . sessionId ) . toBeNull ( ) ;
317+ expect ( sessionState . resumeGatewayUrl ) . toBeNull ( ) ;
318+ expect ( sessionState . sequence ) . toBeNull ( ) ;
319+ } ) ;
320+
321+ it ( "includes close code details when reconnect attempts are exhausted" , async ( ) => {
322+ vi . useFakeTimers ( ) ;
323+ const gateway = new TestGatewayPlugin ( {
324+ autoInteractions : false ,
325+ reconnect : { maxAttempts : 0 } ,
326+ url : "wss://gateway.example.test" ,
327+ } ) ;
328+ const errorSpy = vi . fn ( ) ;
329+ gateway . emitter . on ( "error" , errorSpy ) ;
330+
331+ gateway . connect ( false ) ;
332+ gateway . sockets [ 0 ] ?. emit ( "open" ) ;
333+ gateway . sockets [ 0 ] ?. emit ( "close" , 1006 ) ;
334+ await vi . advanceTimersByTimeAsync ( 30_000 ) ;
335+
336+ expect ( errorSpy ) . toHaveBeenCalledWith (
337+ new Error ( "Max reconnect attempts (0) reached after close code 1006" ) ,
338+ ) ;
339+ expect ( gateway . connectCalls ) . toEqual ( [ false ] ) ;
340+ expect ( gateway . sockets ) . toHaveLength ( 1 ) ;
280341 } ) ;
281342
282343 it ( "does not reconnect after fatal gateway closes" , async ( ) => {
0 commit comments