Added ErrorBoundary tests for useEffect and useLayoutEffect (#14401)
Brian Vaughn committed
Dec 6, 2018 at 13:55 UTC
5bb4ad7376b315b61865ea5424e9f76ba6a5c5a3
1 file changed
+87
packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js
+87
@@ -28,6 +28,8 @@ describe('ReactErrorBoundaries', () => {
28
let BrokenComponentWillMountErrorBoundary;
29
let BrokenComponentDidMountErrorBoundary;
30
let BrokenRender;
31
+ let BrokenUseEffect;
32
+ let BrokenUseLayoutEffect;
33
let ErrorBoundary;
34
let ErrorMessage;
35
let NoopErrorBoundary;
@@ -35,9 +37,11 @@ describe('ReactErrorBoundaries', () => {
37
let Normal;
38
39
beforeEach(() => {
40
+ jest.useFakeTimers();
41
jest.resetModules();
42
PropTypes = require('prop-types');
43
ReactFeatureFlags = require('shared/ReactFeatureFlags');
44
+ ReactFeatureFlags.enableHooks = true;
45
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
46
ReactDOM = require('react-dom');
47
React = require('react');
@@ -386,6 +390,28 @@ describe('ReactErrorBoundaries', () => {
390
}
391
};
392
393
+ BrokenUseEffect = props => {
394
+ log.push('BrokenUseEffect render');
395
+
396
+ React.useEffect(() => {
397
+ log.push('BrokenUseEffect useEffect [!]');
398
+ throw new Error('Hello');
399
+ });
400
+
401
+ return props.children;
402
+ };
403
+
404
+ BrokenUseLayoutEffect = props => {
405
+ log.push('BrokenUseLayoutEffect render');
406
+
407
+ React.useLayoutEffect(() => {
408
+ log.push('BrokenUseLayoutEffect useLayoutEffect [!]');
409
+ throw new Error('Hello');
410
+ });
411
+
412
+ return props.children;
413
+ };
414
+
415
NoopErrorBoundary = class extends React.Component {
416
constructor(props) {
417
super(props);
@@ -1795,6 +1821,67 @@ describe('ReactErrorBoundaries', () => {
1821
expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
1822
});
1823
1824
+ it('catches errors in useEffect', () => {
1825
+ const container = document.createElement('div');
1826
+ ReactDOM.render(
1827
+ <ErrorBoundary>
1828
+ <BrokenUseEffect>Initial value</BrokenUseEffect>
1829
+ </ErrorBoundary>,
1830
+ container,
1831
+ );
1832
+ expect(log).toEqual([
1833
+ 'ErrorBoundary constructor',
1834
+ 'ErrorBoundary componentWillMount',
1835
+ 'ErrorBoundary render success',
1836
+ 'BrokenUseEffect render',
1837
+ 'ErrorBoundary componentDidMount',
1838
+ ]);
1839
+
1840
+ expect(container.firstChild.textContent).toBe('Initial value');
1841
+ log.length = 0;
1842
+
1843
+ jest.runAllTimers();
1844
+
1845
+ // Flush passive effects and handle the error
1846
+ expect(log).toEqual([
1847
+ 'BrokenUseEffect useEffect [!]',
1848
+ // Handle the error
1849
+ 'ErrorBoundary static getDerivedStateFromError',
1850
+ 'ErrorBoundary componentWillUpdate',
1851
+ 'ErrorBoundary render error',
1852
+ 'ErrorBoundary componentDidUpdate',
1853
+ ]);
1854
+
1855
+ expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
1856
+ });
1857
+
1858
+ it('catches errors in useLayoutEffect', () => {
1859
+ const container = document.createElement('div');
1860
+ ReactDOM.render(
1861
+ <ErrorBoundary>
1862
+ <BrokenUseLayoutEffect>Initial value</BrokenUseLayoutEffect>
1863
+ </ErrorBoundary>,
1864
+ container,
1865
+ );
1866
+ expect(log).toEqual([
1867
+ 'ErrorBoundary constructor',
1868
+ 'ErrorBoundary componentWillMount',
1869
+ 'ErrorBoundary render success',
1870
+ 'BrokenUseLayoutEffect render',
1871
+ 'BrokenUseLayoutEffect useLayoutEffect [!]',
1872
+ // Fiber proceeds with the hooks
1873
+ 'ErrorBoundary componentDidMount',
1874
+ // The error propagates to the higher boundary
1875
+ 'ErrorBoundary static getDerivedStateFromError',
1876
+ // Fiber retries from the root
1877
+ 'ErrorBoundary componentWillUpdate',
1878
+ 'ErrorBoundary render error',
1879
+ 'ErrorBoundary componentDidUpdate',
1880
+ ]);
1881
+
1882
+ expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
1883
+ });
1884
+
1885
it('propagates errors inside boundary during componentDidMount', () => {
1886
const container = document.createElement('div');
1887
ReactDOM.render(