@@ -3,14 +3,8 @@ import { fireEvent, render, screen } from '@testing-library/react';
33import * as React from 'react' ;
44import { useState } from 'react' ;
55
6- import type {
7- ErrorBoundaryProps } from '../src/errorboundary' ;
8- import {
9- ErrorBoundary ,
10- isAtLeastReact17 ,
11- UNKNOWN_COMPONENT ,
12- withErrorBoundary ,
13- } from '../src/errorboundary' ;
6+ import type { ErrorBoundaryProps } from '../src/errorboundary' ;
7+ import { ErrorBoundary , isAtLeastReact17 , UNKNOWN_COMPONENT , withErrorBoundary } from '../src/errorboundary' ;
148
159const mockCaptureException = jest . fn ( ) ;
1610const mockShowReportDialog = jest . fn ( ) ;
@@ -39,7 +33,13 @@ function Bam(): JSX.Element {
3933 return < Boo title = { title } /> ;
4034}
4135
42- const TestApp : React . FC < ErrorBoundaryProps > = ( { children, ...props } ) => {
36+ interface TestAppProps extends ErrorBoundaryProps {
37+ errorComp ?: JSX . Element ;
38+ }
39+
40+ const TestApp : React . FC < TestAppProps > = ( { children, errorComp, ...props } ) => {
41+ // eslint-disable-next-line no-param-reassign
42+ const customErrorComp = errorComp || < Bam /> ;
4343 const [ isError , setError ] = React . useState ( false ) ;
4444 return (
4545 < ErrorBoundary
@@ -51,7 +51,7 @@ const TestApp: React.FC<ErrorBoundaryProps> = ({ children, ...props }) => {
5151 }
5252 } }
5353 >
54- { isError ? < Bam /> : children }
54+ { isError ? customErrorComp : children }
5555 < button
5656 data-testid = "errorBtn"
5757 onClick = { ( ) => {
@@ -299,6 +299,48 @@ describe('ErrorBoundary', () => {
299299 expect ( error . cause ) . not . toBeDefined ( ) ;
300300 } ) ;
301301
302+ it ( 'handles when `error.cause` is nested' , ( ) => {
303+ const mockOnError = jest . fn ( ) ;
304+
305+ function CustomBam ( ) : JSX . Element {
306+ const firstError = new Error ( 'bam' ) ;
307+ const secondError = new Error ( 'bam2' ) ;
308+ const thirdError = new Error ( 'bam3' ) ;
309+ // @ts -ignore Need to set cause on error
310+ secondError . cause = firstError ;
311+ // @ts -ignore Need to set cause on error
312+ thirdError . cause = secondError ;
313+ throw thirdError ;
314+ }
315+
316+ render (
317+ < TestApp fallback = { < p > You have hit an error</ p > } onError = { mockOnError } errorComp = { < CustomBam /> } >
318+ < h1 > children</ h1 >
319+ </ TestApp > ,
320+ ) ;
321+
322+ expect ( mockOnError ) . toHaveBeenCalledTimes ( 0 ) ;
323+ expect ( mockCaptureException ) . toHaveBeenCalledTimes ( 0 ) ;
324+
325+ const btn = screen . getByTestId ( 'errorBtn' ) ;
326+ fireEvent . click ( btn ) ;
327+
328+ expect ( mockCaptureException ) . toHaveBeenCalledTimes ( 1 ) ;
329+ expect ( mockCaptureException ) . toHaveBeenLastCalledWith ( expect . any ( Error ) , {
330+ contexts : { react : { componentStack : expect . any ( String ) } } ,
331+ } ) ;
332+
333+ expect ( mockOnError . mock . calls [ 0 ] [ 0 ] ) . toEqual ( mockCaptureException . mock . calls [ 0 ] [ 0 ] ) ;
334+
335+ const thirdError = mockCaptureException . mock . calls [ 0 ] [ 0 ] ;
336+ const secondError = thirdError . cause ;
337+ const firstError = secondError . cause ;
338+ const cause = firstError . cause ;
339+ expect ( cause . stack ) . toEqual ( mockCaptureException . mock . calls [ 0 ] [ 1 ] . contexts . react . componentStack ) ;
340+ expect ( cause . name ) . toContain ( 'React ErrorBoundary' ) ;
341+ expect ( cause . message ) . toEqual ( thirdError . message ) ;
342+ } ) ;
343+
302344 it ( 'calls `beforeCapture()` when an error occurs' , ( ) => {
303345 const mockBeforeCapture = jest . fn ( ) ;
304346
0 commit comments