@@ -88,6 +88,51 @@ describe("BulkQueue", () => {
8888 expect ( sendBulk ) . toHaveBeenNthCalledWith ( 2 , [ trackEvent ] ) ;
8989 } ) ;
9090
91+ it ( "requeues and downgrades page teardown aborts for bulk sends" , async ( ) => {
92+ const logger = {
93+ debug : vi . fn ( ) ,
94+ info : vi . fn ( ) ,
95+ warn : vi . fn ( ) ,
96+ error : vi . fn ( ) ,
97+ } ;
98+ const sendBulk = vi
99+ . fn < ( events : BulkEvent [ ] ) => Promise < Response > > ( )
100+ . mockRejectedValueOnce ( new TypeError ( "Failed to fetch" ) )
101+ . mockResolvedValue ( new Response ( "" , { status : 200 } ) ) ;
102+ const queue = new BulkQueue ( sendBulk , {
103+ flushDelayMs : 10 ,
104+ retryBaseDelayMs : 20 ,
105+ retryMaxDelayMs : 20 ,
106+ logger,
107+ } ) ;
108+
109+ window . dispatchEvent ( new Event ( "pagehide" ) ) ;
110+ await queue . enqueue ( trackEvent ) ;
111+
112+ await vi . advanceTimersByTimeAsync ( 10 ) ;
113+ expect ( sendBulk ) . toHaveBeenCalledTimes ( 1 ) ;
114+ expect ( await queue . size ( ) ) . toBe ( 1 ) ;
115+ expect ( logger . debug ) . toHaveBeenCalledWith (
116+ "bulk retry scheduled (aborted during page teardown)" ,
117+ expect . objectContaining ( {
118+ retryInMs : 20 ,
119+ queueSize : 2 ,
120+ consecutiveFailures : 1 ,
121+ error : expect . any ( TypeError ) ,
122+ } ) ,
123+ ) ;
124+ expect ( logger . info ) . not . toHaveBeenCalledWith (
125+ "bulk retry scheduled" ,
126+ expect . anything ( ) ,
127+ ) ;
128+ expect ( logger . warn ) . not . toHaveBeenCalled ( ) ;
129+
130+ window . dispatchEvent ( new Event ( "pageshow" ) ) ;
131+ await vi . advanceTimersByTimeAsync ( 20 ) ;
132+ expect ( sendBulk ) . toHaveBeenCalledTimes ( 2 ) ;
133+ expect ( sendBulk ) . toHaveBeenNthCalledWith ( 2 , [ trackEvent ] ) ;
134+ } ) ;
135+
91136 it ( "drops 4xx responses, logs error, and does not retry" , async ( ) => {
92137 const sendBulk = vi
93138 . fn < ( events : BulkEvent [ ] ) => Promise < Response > > ( )
0 commit comments