@@ -341,6 +341,45 @@ describe('ErrorBoundary', () => {
341341 expect ( cause . message ) . toEqual ( thirdError . message ) ;
342342 } ) ;
343343
344+ it ( 'handles when `error.cause` is recursive' , ( ) => {
345+ const mockOnError = jest . fn ( ) ;
346+
347+ function CustomBam ( ) : JSX . Element {
348+ const firstError = new Error ( 'bam' ) ;
349+ const secondError = new Error ( 'bam2' ) ;
350+ // @ts -ignore Need to set cause on error
351+ firstError . cause = secondError ;
352+ // @ts -ignore Need to set cause on error
353+ secondError . cause = firstError ;
354+ throw firstError ;
355+ }
356+
357+ render (
358+ < TestApp fallback = { < p > You have hit an error</ p > } onError = { mockOnError } errorComp = { < CustomBam /> } >
359+ < h1 > children</ h1 >
360+ </ TestApp > ,
361+ ) ;
362+
363+ expect ( mockOnError ) . toHaveBeenCalledTimes ( 0 ) ;
364+ expect ( mockCaptureException ) . toHaveBeenCalledTimes ( 0 ) ;
365+
366+ const btn = screen . getByTestId ( 'errorBtn' ) ;
367+ fireEvent . click ( btn ) ;
368+
369+ expect ( mockCaptureException ) . toHaveBeenCalledTimes ( 1 ) ;
370+ expect ( mockCaptureException ) . toHaveBeenLastCalledWith ( expect . any ( Error ) , {
371+ contexts : { react : { componentStack : expect . any ( String ) } } ,
372+ } ) ;
373+
374+ expect ( mockOnError . mock . calls [ 0 ] [ 0 ] ) . toEqual ( mockCaptureException . mock . calls [ 0 ] [ 0 ] ) ;
375+
376+ const error = mockCaptureException . mock . calls [ 0 ] [ 0 ] ;
377+ const cause = error . cause ;
378+ // We need to make sure that recursive error.cause does not cause infinite loop
379+ expect ( cause . stack ) . not . toEqual ( mockCaptureException . mock . calls [ 0 ] [ 1 ] . contexts . react . componentStack ) ;
380+ expect ( cause . name ) . not . toContain ( 'React ErrorBoundary' ) ;
381+ } ) ;
382+
344383 it ( 'calls `beforeCapture()` when an error occurs' , ( ) => {
345384 const mockBeforeCapture = jest . fn ( ) ;
346385
0 commit comments