Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions scripts/fiber/tests-passing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <span prop={this.state.error.message} />;
}
return this.props.children;
}
}

const InvalidType = undefined;
const brokenElement = <InvalidType />;
function BrokenRender(props) {
return brokenElement;
}

ReactNoop.render(
<ErrorBoundary>
<BrokenRender />
</ErrorBoundary>
);
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 <span prop={this.state.error.message} />;
}
return this.props.children;
}
}

const InvalidType = undefined;
const brokenElement = <InvalidType />;
function BrokenRender(props) {
return props.fail ? brokenElement : <span />;
}

ReactNoop.render(
<ErrorBoundary>
<BrokenRender fail={false} />
</ErrorBoundary>
);
ReactNoop.flush();

ReactNoop.render(
<ErrorBoundary>
<BrokenRender fail={true} />
</ErrorBoundary>
);
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(<InvalidType />);
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(<span prop="hi" />);
ReactNoop.flush();
expect(ReactNoop.getChildren()).toEqual([span('hi')]);
});
});