@@ -268,5 +268,150 @@ describe('TelemetryService', () => {
268268 // Should not throw and only process once.
269269 expect ( TelemetryService . getCurrentInstance ( ) ) . toBeNull ( )
270270 } )
271+
272+ it ( 'does not flush when service is destroyed' , async ( ) => {
273+ const client = await TelemetryService . getTelemetryClient ( 'test-org' )
274+ await client . destroy ( )
275+
276+ // Now try to flush on a destroyed instance.
277+ await client . flush ( )
278+
279+ // Should not send anything because service is destroyed.
280+ expect ( mockPostOrgTelemetry ) . toHaveBeenCalledTimes ( 0 )
281+ } )
282+
283+ it ( 'handles SDK setup failure during flush gracefully' , async ( ) => {
284+ const client = await TelemetryService . getTelemetryClient ( 'test-org' )
285+
286+ client . track ( {
287+ event_sender_created_at : new Date ( ) . toISOString ( ) ,
288+ event_type : 'test_event' ,
289+ context : { } ,
290+ } )
291+
292+ // Make SDK setup fail during flush.
293+ mockSetupSdk . mockResolvedValue ( {
294+ ok : false ,
295+ message : 'SDK setup failed' ,
296+ } )
297+
298+ // Should not throw.
299+ await expect ( client . flush ( ) ) . resolves . not . toThrow ( )
300+ } )
301+
302+ it ( 'handles exceptions during initialization gracefully' , async ( ) => {
303+ mockSetupSdk . mockRejectedValue ( new Error ( 'Unexpected error' ) )
304+
305+ // Should not throw and return a client with default config.
306+ const client = await TelemetryService . getTelemetryClient ( 'error-org' )
307+ expect ( client ) . toBeDefined ( )
308+ } )
309+ } )
310+
311+ describe ( 'concurrent initialization' , ( ) => {
312+ it ( 'handles concurrent calls to getTelemetryClient' , async ( ) => {
313+ // Simulate concurrent calls.
314+ const [ client1 , client2 , client3 ] = await Promise . all ( [
315+ TelemetryService . getTelemetryClient ( 'test-org' ) ,
316+ TelemetryService . getTelemetryClient ( 'test-org' ) ,
317+ TelemetryService . getTelemetryClient ( 'test-org' ) ,
318+ ] )
319+
320+ // All should return the same instance.
321+ expect ( client1 ) . toBe ( client2 )
322+ expect ( client2 ) . toBe ( client3 )
323+
324+ // SDK setup should only be called once.
325+ expect ( mockSetupSdk ) . toHaveBeenCalledTimes ( 1 )
326+ } )
327+ } )
328+
329+ describe ( 'sendEvents error handling' , ( ) => {
330+ it ( 'tracks success and failure counts correctly' , async ( ) => {
331+ // Make some events succeed and some fail.
332+ let callCount = 0
333+ mockPostOrgTelemetry . mockImplementation ( async ( ) => {
334+ callCount ++
335+ if ( callCount % 2 === 0 ) {
336+ return { success : false , error : 'Failed' }
337+ }
338+ return { success : true }
339+ } )
340+
341+ const client = await TelemetryService . getTelemetryClient ( 'test-org' )
342+
343+ client . track ( {
344+ event_sender_created_at : new Date ( ) . toISOString ( ) ,
345+ event_type : 'event_1' ,
346+ context : { } ,
347+ } )
348+ client . track ( {
349+ event_sender_created_at : new Date ( ) . toISOString ( ) ,
350+ event_type : 'event_2' ,
351+ context : { } ,
352+ } )
353+ client . track ( {
354+ event_sender_created_at : new Date ( ) . toISOString ( ) ,
355+ event_type : 'event_3' ,
356+ context : { } ,
357+ } )
358+
359+ await client . flush ( )
360+
361+ expect ( mockPostOrgTelemetry ) . toHaveBeenCalledTimes ( 3 )
362+ } )
363+
364+ it ( 'handles rejected promises during send' , async ( ) => {
365+ let callCount = 0
366+ mockPostOrgTelemetry . mockImplementation ( async ( ) => {
367+ callCount ++
368+ if ( callCount === 2 ) {
369+ throw new Error ( 'Network error' )
370+ }
371+ return { success : true }
372+ } )
373+
374+ const client = await TelemetryService . getTelemetryClient ( 'test-org' )
375+
376+ client . track ( {
377+ event_sender_created_at : new Date ( ) . toISOString ( ) ,
378+ event_type : 'event_1' ,
379+ context : { } ,
380+ } )
381+ client . track ( {
382+ event_sender_created_at : new Date ( ) . toISOString ( ) ,
383+ event_type : 'event_2' ,
384+ context : { } ,
385+ } )
386+ client . track ( {
387+ event_sender_created_at : new Date ( ) . toISOString ( ) ,
388+ event_type : 'event_3' ,
389+ context : { } ,
390+ } )
391+
392+ // Should not throw despite one event failing.
393+ await expect ( client . flush ( ) ) . resolves . not . toThrow ( )
394+ } )
395+ } )
396+
397+ describe ( 'auto-flush on batch size' , ( ) => {
398+ it ( 'automatically flushes when batch size is reached' , async ( ) => {
399+ const client = await TelemetryService . getTelemetryClient ( 'test-org' )
400+
401+ // Add 10 events (default batch size).
402+ for ( let i = 0 ; i < 10 ; i ++ ) {
403+ client . track ( {
404+ event_sender_created_at : new Date ( ) . toISOString ( ) ,
405+ event_type : `event_${ i } ` ,
406+ context : { } ,
407+ } )
408+ }
409+
410+ // Give time for auto-flush to complete.
411+ await new Promise ( resolve => setTimeout ( resolve , 100 ) )
412+
413+ // Events should have been sent.
414+ expect ( mockPostOrgTelemetry ) . toHaveBeenCalled ( )
415+ } )
271416 } )
272417} )
0 commit comments