@@ -49,7 +49,6 @@ describe('TelemetryCollector.recordLog', () => {
4949 expect ( log . iid ) . toBeUndefined ( ) ;
5050 expect ( log . ts ) . toBe ( new Date ( ts ) . toISOString ( ) ) ;
5151 expect ( log . pk ) . toBe ( TEST_PK ) ;
52- // Function and undefined stripped out
5352 expect ( log . payload ) . toEqual ( { a : 1 } ) ;
5453 } ) ;
5554
@@ -62,7 +61,6 @@ describe('TelemetryCollector.recordLog', () => {
6261 timestamp : Date . now ( ) ,
6362 } ;
6463
65- // undefined context
6664 fetchSpy . mockClear ( ) ;
6765 collector . recordLog ( { ...base , context : undefined } as any ) ;
6866 jest . runAllTimers ( ) ;
@@ -71,7 +69,6 @@ describe('TelemetryCollector.recordLog', () => {
7169 let body = JSON . parse ( initOptions1 . body as string ) ;
7270 expect ( body . logs [ 0 ] . payload ) . toBeNull ( ) ;
7371
74- // array context
7572 fetchSpy . mockClear ( ) ;
7673 collector . recordLog ( { ...base , context : [ 1 , 2 , 3 ] } as any ) ;
7774 jest . runAllTimers ( ) ;
@@ -80,7 +77,6 @@ describe('TelemetryCollector.recordLog', () => {
8077 body = JSON . parse ( initOptions2 . body as string ) ;
8178 expect ( body . logs [ 0 ] . payload ) . toBeNull ( ) ;
8279
83- // circular context
8480 fetchSpy . mockClear ( ) ;
8581 const circular : any = { foo : 'bar' } ;
8682 circular . self = circular ;
@@ -95,7 +91,6 @@ describe('TelemetryCollector.recordLog', () => {
9591 test ( 'drops invalid entries: missing id, invalid level, empty message, invalid timestamp' , ( ) => {
9692 const collector = new TelemetryCollector ( { publishableKey : TEST_PK } ) ;
9793
98- // invalid level
9994 fetchSpy . mockClear ( ) ;
10095 collector . recordLog ( {
10196 level : 'fatal' as unknown as any ,
@@ -105,7 +100,6 @@ describe('TelemetryCollector.recordLog', () => {
105100 jest . runAllTimers ( ) ;
106101 expect ( fetchSpy ) . not . toHaveBeenCalled ( ) ;
107102
108- // empty message
109103 fetchSpy . mockClear ( ) ;
110104 collector . recordLog ( {
111105 level : 'debug' ,
@@ -115,7 +109,6 @@ describe('TelemetryCollector.recordLog', () => {
115109 jest . runAllTimers ( ) ;
116110 expect ( fetchSpy ) . not . toHaveBeenCalled ( ) ;
117111
118- // invalid timestamp (NaN)
119112 fetchSpy . mockClear ( ) ;
120113 collector . recordLog ( {
121114 level : 'warn' ,
@@ -144,4 +137,86 @@ describe('TelemetryCollector.recordLog', () => {
144137 const body = JSON . parse ( initOptions4 . body as string ) ;
145138 expect ( body . logs [ 0 ] . ts ) . toBe ( new Date ( tsString ) . toISOString ( ) ) ;
146139 } ) ;
140+
141+ describe ( 'error handling' , ( ) => {
142+ test ( 'recordLog() method handles circular references in context gracefully' , ( ) => {
143+ const collector = new TelemetryCollector ( { publishableKey : TEST_PK } ) ;
144+
145+ const circularContext = ( ( ) => {
146+ const obj : any = { test : 'value' } ;
147+ obj . self = obj ;
148+ return obj ;
149+ } ) ( ) ;
150+
151+ expect ( ( ) => {
152+ collector . recordLog ( {
153+ level : 'info' ,
154+ message : 'test message' ,
155+ timestamp : Date . now ( ) ,
156+ context : circularContext ,
157+ } ) ;
158+ } ) . not . toThrow ( ) ;
159+
160+ jest . runAllTimers ( ) ;
161+ expect ( fetchSpy ) . toHaveBeenCalled ( ) ;
162+
163+ const [ url , init ] = fetchSpy . mock . calls [ 0 ] ;
164+ expect ( String ( url ) ) . toMatch ( '/v1/logs' ) ;
165+
166+ const initOptions = init as RequestInit ;
167+ const body = JSON . parse ( initOptions . body as string ) ;
168+ expect ( body . logs [ 0 ] . payload ) . toBeNull ( ) ;
169+ } ) ;
170+
171+ test ( 'recordLog() method handles non-serializable context gracefully' , ( ) => {
172+ const collector = new TelemetryCollector ( { publishableKey : TEST_PK } ) ;
173+
174+ const nonSerializableContext = {
175+ function : ( ) => 'test' ,
176+ undefined : undefined ,
177+ symbol : Symbol ( 'test' ) ,
178+ circular : ( ( ) => {
179+ const obj : any = { test : 'value' } ;
180+ obj . self = obj ;
181+ return obj ;
182+ } ) ( ) ,
183+ } ;
184+
185+ expect ( ( ) => {
186+ collector . recordLog ( {
187+ level : 'info' ,
188+ message : 'test message' ,
189+ timestamp : Date . now ( ) ,
190+ context : nonSerializableContext ,
191+ } ) ;
192+ } ) . not . toThrow ( ) ;
193+
194+ jest . runAllTimers ( ) ;
195+ expect ( fetchSpy ) . toHaveBeenCalled ( ) ;
196+
197+ const [ url , init ] = fetchSpy . mock . calls [ 0 ] ;
198+ expect ( String ( url ) ) . toMatch ( '/v1/logs' ) ;
199+
200+ const initOptions = init as RequestInit ;
201+ const body = JSON . parse ( initOptions . body as string ) ;
202+ expect ( body . logs [ 0 ] . payload ) . toBeNull ( ) ;
203+ } ) ;
204+
205+ test ( 'recordLog() method handles invalid timestamp gracefully' , ( ) => {
206+ const collector = new TelemetryCollector ( { publishableKey : TEST_PK } ) ;
207+
208+ const invalidTimestamp = new Date ( 'invalid date' ) ;
209+
210+ expect ( ( ) => {
211+ collector . recordLog ( {
212+ level : 'info' ,
213+ message : 'test message' ,
214+ timestamp : invalidTimestamp . getTime ( ) ,
215+ } ) ;
216+ } ) . not . toThrow ( ) ;
217+
218+ jest . runAllTimers ( ) ;
219+ expect ( fetchSpy ) . not . toHaveBeenCalled ( ) ;
220+ } ) ;
221+ } ) ;
147222} ) ;
0 commit comments