diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt
index 7562b2881b..a780be9589 100644
--- a/scripts/fiber/tests-passing.txt
+++ b/scripts/fiber/tests-passing.txt
@@ -1087,6 +1087,9 @@ src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js
* can schedule updates after uncaught error during umounting
* continues work on other roots despite caught errors
* continues work on other roots despite uncaught errors
+* catches reconciler errors in a boundary during mounting
+* catches reconciler errors in a boundary during update
+* recovers from uncaught reconciler errors
src/renderers/shared/fiber/__tests__/ReactIncrementalReflection-test.js
* handles isMounted even when the initial render is deferred
diff --git a/src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js b/src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js
index 0f55886650..aef659cc35 100644
--- a/src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js
+++ b/src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js
@@ -275,4 +275,97 @@ describe('ReactIncrementalErrorHandling', () => {
expect(ReactNoop.getChildren('e')).toEqual(null);
expect(ReactNoop.getChildren('f')).toEqual(null);
});
+
+ it('catches reconciler errors in a boundary during mounting', () => {
+ spyOn(console, 'error');
+
+ class ErrorBoundary extends React.Component {
+ state = {error: null};
+ unstable_handleError(error) {
+ this.setState({error});
+ }
+ render() {
+ if (this.state.error) {
+ return ;
+ }
+ return this.props.children;
+ }
+ }
+
+ const InvalidType = undefined;
+ const brokenElement = ;
+ function BrokenRender(props) {
+ return brokenElement;
+ }
+
+ ReactNoop.render(
+
+
+
+ );
+ ReactNoop.flush();
+ expect(ReactNoop.getChildren()).toEqual([span(
+ 'Element type is invalid: expected a string (for built-in components) or ' +
+ 'a class/function (for composite components) but got: undefined.'
+ )]);
+ expect(console.error.calls.count()).toBe(1);
+ });
+
+ it('catches reconciler errors in a boundary during update', () => {
+ spyOn(console, 'error');
+
+ class ErrorBoundary extends React.Component {
+ state = {error: null};
+ unstable_handleError(error) {
+ this.setState({error});
+ }
+ render() {
+ if (this.state.error) {
+ return ;
+ }
+ return this.props.children;
+ }
+ }
+
+ const InvalidType = undefined;
+ const brokenElement = ;
+ function BrokenRender(props) {
+ return props.fail ? brokenElement : ;
+ }
+
+ ReactNoop.render(
+
+
+
+ );
+ ReactNoop.flush();
+
+ ReactNoop.render(
+
+
+
+ );
+ ReactNoop.flush();
+ expect(ReactNoop.getChildren()).toEqual([span(
+ 'Element type is invalid: expected a string (for built-in components) or ' +
+ 'a class/function (for composite components) but got: undefined.'
+ )]);
+ expect(console.error.calls.count()).toBe(1);
+ });
+
+ it('recovers from uncaught reconciler errors', () => {
+ spyOn(console, 'error');
+ const InvalidType = undefined;
+ ReactNoop.render();
+ expect(() => {
+ ReactNoop.flush();
+ }).toThrowError(
+ 'Element type is invalid: expected a string (for built-in components) or ' +
+ 'a class/function (for composite components) but got: undefined.'
+ );
+
+ ReactNoop.render();
+ ReactNoop.flush();
+ expect(ReactNoop.getChildren()).toEqual([span('hi')]);
+ });
});