@@ -2084,4 +2084,70 @@ describe('ReactErrorBoundaries', () => {
2084
2084
// Error should be the first thrown
2085
2085
expect ( caughtError . message ) . toBe ( 'child sad' ) ;
2086
2086
} ) ;
2087
+
2088
+ it ( 'should warn if an error boundary with only componentDidCatch does not update state' , ( ) => {
2089
+ class InvalidErrorBoundary extends React . Component {
2090
+ componentDidCatch ( error , info ) {
2091
+ // This component does not define getDerivedStateFromError().
2092
+ // It also doesn't call setState().
2093
+ // So it would swallow errors (which is probably unintentional).
2094
+ }
2095
+ render ( ) {
2096
+ return this . props . children ;
2097
+ }
2098
+ }
2099
+
2100
+ const Throws = ( ) => {
2101
+ throw new Error ( 'expected' ) ;
2102
+ } ;
2103
+
2104
+ const container = document . createElement ( 'div' ) ;
2105
+ expect ( ( ) => {
2106
+ ReactDOM . render (
2107
+ < InvalidErrorBoundary >
2108
+ < Throws />
2109
+ </ InvalidErrorBoundary > ,
2110
+ container ,
2111
+ ) ;
2112
+ } ) . toWarnDev (
2113
+ 'InvalidErrorBoundary: Error boundaries should implement getDerivedStateFromError(). ' +
2114
+ 'In that method, return a state update to display an error message or fallback UI, ' +
2115
+ 'or rethrow the error to let parent components handle it' ,
2116
+ { withoutStack : true } ,
2117
+ ) ;
2118
+ expect ( container . textContent ) . toBe ( '' ) ;
2119
+ } ) ;
2120
+
2121
+ it ( 'should call both componentDidCatch and getDerivedStateFromError if both exist on a component' , ( ) => {
2122
+ let componentDidCatchError , getDerivedStateFromErrorError ;
2123
+ class ErrorBoundaryWithBothMethods extends React . Component {
2124
+ state = { error : null } ;
2125
+ static getDerivedStateFromError ( error ) {
2126
+ getDerivedStateFromErrorError = error ;
2127
+ return { error} ;
2128
+ }
2129
+ componentDidCatch ( error , info ) {
2130
+ componentDidCatchError = error ;
2131
+ }
2132
+ render ( ) {
2133
+ return this . state . error ? 'ErrorBoundary' : this . props . children ;
2134
+ }
2135
+ }
2136
+
2137
+ const thrownError = new Error ( 'expected' ) ;
2138
+ const Throws = ( ) => {
2139
+ throw thrownError ;
2140
+ } ;
2141
+
2142
+ const container = document . createElement ( 'div' ) ;
2143
+ ReactDOM . render (
2144
+ < ErrorBoundaryWithBothMethods >
2145
+ < Throws />
2146
+ </ ErrorBoundaryWithBothMethods > ,
2147
+ container ,
2148
+ ) ;
2149
+ expect ( container . textContent ) . toBe ( 'ErrorBoundary' ) ;
2150
+ expect ( componentDidCatchError ) . toBe ( thrownError ) ;
2151
+ expect ( getDerivedStateFromErrorError ) . toBe ( thrownError ) ;
2152
+ } ) ;
2087
2153
} ) ;
0 commit comments