Skip to content

Commit

Permalink
Added ErrorBoundary tests for useEffect and useLayoutEffect (#14401)
Browse files Browse the repository at this point in the history
  • Loading branch information
bvaughn authored Dec 6, 2018
1 parent 98eb5ae commit 5bb4ad7
Showing 1 changed file with 87 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,20 @@ describe('ReactErrorBoundaries', () => {
let BrokenComponentWillMountErrorBoundary;
let BrokenComponentDidMountErrorBoundary;
let BrokenRender;
let BrokenUseEffect;
let BrokenUseLayoutEffect;
let ErrorBoundary;
let ErrorMessage;
let NoopErrorBoundary;
let RetryErrorBoundary;
let Normal;

beforeEach(() => {
jest.useFakeTimers();
jest.resetModules();
PropTypes = require('prop-types');
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableHooks = true;
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
ReactDOM = require('react-dom');
React = require('react');
Expand Down Expand Up @@ -386,6 +390,28 @@ describe('ReactErrorBoundaries', () => {
}
};

BrokenUseEffect = props => {
log.push('BrokenUseEffect render');

React.useEffect(() => {
log.push('BrokenUseEffect useEffect [!]');
throw new Error('Hello');
});

return props.children;
};

BrokenUseLayoutEffect = props => {
log.push('BrokenUseLayoutEffect render');

React.useLayoutEffect(() => {
log.push('BrokenUseLayoutEffect useLayoutEffect [!]');
throw new Error('Hello');
});

return props.children;
};

NoopErrorBoundary = class extends React.Component {
constructor(props) {
super(props);
Expand Down Expand Up @@ -1795,6 +1821,67 @@ describe('ReactErrorBoundaries', () => {
expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
});

it('catches errors in useEffect', () => {
const container = document.createElement('div');
ReactDOM.render(
<ErrorBoundary>
<BrokenUseEffect>Initial value</BrokenUseEffect>
</ErrorBoundary>,
container,
);
expect(log).toEqual([
'ErrorBoundary constructor',
'ErrorBoundary componentWillMount',
'ErrorBoundary render success',
'BrokenUseEffect render',
'ErrorBoundary componentDidMount',
]);

expect(container.firstChild.textContent).toBe('Initial value');
log.length = 0;

jest.runAllTimers();

// Flush passive effects and handle the error
expect(log).toEqual([
'BrokenUseEffect useEffect [!]',
// Handle the error
'ErrorBoundary static getDerivedStateFromError',
'ErrorBoundary componentWillUpdate',
'ErrorBoundary render error',
'ErrorBoundary componentDidUpdate',
]);

expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
});

it('catches errors in useLayoutEffect', () => {
const container = document.createElement('div');
ReactDOM.render(
<ErrorBoundary>
<BrokenUseLayoutEffect>Initial value</BrokenUseLayoutEffect>
</ErrorBoundary>,
container,
);
expect(log).toEqual([
'ErrorBoundary constructor',
'ErrorBoundary componentWillMount',
'ErrorBoundary render success',
'BrokenUseLayoutEffect render',
'BrokenUseLayoutEffect useLayoutEffect [!]',
// Fiber proceeds with the hooks
'ErrorBoundary componentDidMount',
// The error propagates to the higher boundary
'ErrorBoundary static getDerivedStateFromError',
// Fiber retries from the root
'ErrorBoundary componentWillUpdate',
'ErrorBoundary render error',
'ErrorBoundary componentDidUpdate',
]);

expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
});

it('propagates errors inside boundary during componentDidMount', () => {
const container = document.createElement('div');
ReactDOM.render(
Expand Down

0 comments on commit 5bb4ad7

Please sign in to comment.