| 1 | describe('ErrorBoundaryReconciliation', () => { |
| 2 | let BrokenRender; |
| 3 | let DidCatchErrorBoundary; |
| 4 | let GetDerivedErrorBoundary; |
| 5 | let React; |
| 6 | let ReactTestRenderer; |
| 7 | let span; |
| 8 | let act; |
| 9 | |
| 10 | beforeEach(() => { |
| 11 | jest.resetModules(); |
| 12 | |
| 13 | ReactTestRenderer = require('react-test-renderer'); |
| 14 | React = require('react'); |
| 15 | act = require('internal-test-utils').act; |
| 16 | DidCatchErrorBoundary = class extends React.Component { |
| 17 | state = {error: null}; |
| 18 | componentDidCatch(error) { |
| 19 | this.setState({error}); |
| 20 | } |
| 21 | render() { |
| 22 | return this.state.error |
| 23 | ? React.createElement(this.props.fallbackTagName, { |
| 24 | prop: 'ErrorBoundary', |
| 25 | }) |
| 26 | : this.props.children; |
| 27 | } |
| 28 | }; |
| 29 | |
| 30 | GetDerivedErrorBoundary = class extends React.Component { |
| 31 | state = {error: null}; |
| 32 | static getDerivedStateFromError(error) { |
| 33 | return {error}; |
| 34 | } |
| 35 | render() { |
| 36 | return this.state.error |
| 37 | ? React.createElement(this.props.fallbackTagName, { |
| 38 | prop: 'ErrorBoundary', |
| 39 | }) |
| 40 | : this.props.children; |
| 41 | } |
| 42 | }; |
| 43 | |
| 44 | const InvalidType = undefined; |
| 45 | BrokenRender = ({fail}) => |
| 46 | fail ? <InvalidType /> : <span prop="BrokenRender" />; |
| 47 | }); |
| 48 | |
| 49 | async function sharedTest(ErrorBoundary, fallbackTagName) { |
| 50 | let renderer; |
| 51 | |
| 52 | await act(() => { |
| 53 | renderer = ReactTestRenderer.create( |
| 54 | <ErrorBoundary fallbackTagName={fallbackTagName}> |
| 55 | <BrokenRender fail={false} /> |
| 56 | </ErrorBoundary>, |
| 57 | {unstable_isConcurrent: true}, |
| 58 | ); |
| 59 | }); |
| 60 | expect(renderer).toMatchRenderedOutput(<span prop="BrokenRender" />); |
| 61 | await act(() => { |
| 62 | renderer.update( |
| 63 | <ErrorBoundary fallbackTagName={fallbackTagName}> |
| 64 | <BrokenRender fail={true} /> |
| 65 | </ErrorBoundary>, |
| 66 | ); |
| 67 | }); |
| 68 | |
| 69 | const Fallback = fallbackTagName; |
| 70 | expect(renderer).toMatchRenderedOutput(<Fallback prop="ErrorBoundary" />); |
| 71 | } |
| 72 | |
| 73 | it('componentDidCatch can recover by rendering an element of the same type', () => |
| 74 | sharedTest(DidCatchErrorBoundary, 'span')); |
| 75 | |
| 76 | it('componentDidCatch can recover by rendering an element of a different type', () => |
| 77 | sharedTest(DidCatchErrorBoundary, 'div')); |
| 78 | |
| 79 | it('getDerivedStateFromError can recover by rendering an element of the same type', () => |
| 80 | sharedTest(GetDerivedErrorBoundary, 'span')); |
| 81 | |
| 82 | it('getDerivedStateFromError can recover by rendering an element of a different type', () => |
| 83 | sharedTest(GetDerivedErrorBoundary, 'div')); |
| 84 | }); |