@@ -3,14 +3,8 @@ import { fireEvent, render, screen } from '@testing-library/react';
3
3
import * as React from 'react' ;
4
4
import { useState } from 'react' ;
5
5
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' ;
14
8
15
9
const mockCaptureException = jest . fn ( ) ;
16
10
const mockShowReportDialog = jest . fn ( ) ;
@@ -39,7 +33,13 @@ function Bam(): JSX.Element {
39
33
return < Boo title = { title } /> ;
40
34
}
41
35
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 /> ;
43
43
const [ isError , setError ] = React . useState ( false ) ;
44
44
return (
45
45
< ErrorBoundary
@@ -51,7 +51,7 @@ const TestApp: React.FC<ErrorBoundaryProps> = ({ children, ...props }) => {
51
51
}
52
52
} }
53
53
>
54
- { isError ? < Bam /> : children }
54
+ { isError ? customErrorComp : children }
55
55
< button
56
56
data-testid = "errorBtn"
57
57
onClick = { ( ) => {
@@ -299,6 +299,48 @@ describe('ErrorBoundary', () => {
299
299
expect ( error . cause ) . not . toBeDefined ( ) ;
300
300
} ) ;
301
301
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
+
302
344
it ( 'calls `beforeCapture()` when an error occurs' , ( ) => {
303
345
const mockBeforeCapture = jest . fn ( ) ;
304
346
0 commit comments