forked from facebook/react
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enable getDerivedStateFromError (facebook#13746)
* Removed the enableGetDerivedStateFromCatch feature flag (aka permanently enabled the feature) * Forked/copied ReactErrorBoundaries to ReactLegacyErrorBoundaries for testing componentDidCatch * Updated error boundaries tests to apply to getDerivedStateFromCatch * Renamed getDerivedStateFromCatch -> getDerivedStateFromError * Warn if boundary with only componentDidCatch swallows error * Fixed a subtle reconciliation bug with render phase error boundary
- Loading branch information
Showing
25 changed files
with
2,639 additions
and
242 deletions.
There are no files selected for viewing
342 changes: 185 additions & 157 deletions
342
packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js
Large diffs are not rendered by default.
Oops, something went wrong.
2,130 changes: 2,130 additions & 0 deletions
2,130
packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
const jestDiff = require('jest-diff'); | ||
|
||
describe('ErrorBoundaryReconciliation', () => { | ||
let BrokenRender; | ||
let DidCatchErrorBoundary; | ||
let GetDerivedErrorBoundary; | ||
let React; | ||
let ReactFeatureFlags; | ||
let ReactTestRenderer; | ||
let span; | ||
|
||
beforeEach(() => { | ||
jest.resetModules(); | ||
|
||
ReactFeatureFlags = require('shared/ReactFeatureFlags'); | ||
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; | ||
ReactTestRenderer = require('react-test-renderer'); | ||
React = require('react'); | ||
|
||
DidCatchErrorBoundary = class extends React.Component { | ||
state = {error: null}; | ||
componentDidCatch(error) { | ||
this.setState({error}); | ||
} | ||
render() { | ||
return this.state.error | ||
? React.createElement(this.props.fallbackTagName, { | ||
prop: 'ErrorBoundary', | ||
}) | ||
: this.props.children; | ||
} | ||
}; | ||
|
||
GetDerivedErrorBoundary = class extends React.Component { | ||
state = {error: null}; | ||
static getDerivedStateFromError(error) { | ||
return {error}; | ||
} | ||
render() { | ||
return this.state.error | ||
? React.createElement(this.props.fallbackTagName, { | ||
prop: 'ErrorBoundary', | ||
}) | ||
: this.props.children; | ||
} | ||
}; | ||
|
||
const InvalidType = undefined; | ||
BrokenRender = ({fail}) => | ||
fail ? <InvalidType /> : <span prop="BrokenRender" />; | ||
|
||
function toHaveRenderedChildren(renderer, children) { | ||
let actual, expected; | ||
try { | ||
actual = renderer.toJSON(); | ||
expected = ReactTestRenderer.create(children).toJSON(); | ||
expect(actual).toEqual(expected); | ||
} catch (error) { | ||
return { | ||
message: () => jestDiff(expected, actual), | ||
pass: false, | ||
}; | ||
} | ||
return {pass: true}; | ||
} | ||
expect.extend({toHaveRenderedChildren}); | ||
}); | ||
|
||
[true, false].forEach(isConcurrent => { | ||
function sharedTest(ErrorBoundary, fallbackTagName) { | ||
const renderer = ReactTestRenderer.create( | ||
<ErrorBoundary fallbackTagName={fallbackTagName}> | ||
<BrokenRender fail={false} /> | ||
</ErrorBoundary>, | ||
{unstable_isConcurrent: isConcurrent}, | ||
); | ||
if (isConcurrent) { | ||
renderer.unstable_flushAll(); | ||
} | ||
expect(renderer).toHaveRenderedChildren(<span prop="BrokenRender" />); | ||
|
||
expect(() => { | ||
renderer.update( | ||
<ErrorBoundary fallbackTagName={fallbackTagName}> | ||
<BrokenRender fail={true} /> | ||
</ErrorBoundary>, | ||
); | ||
if (isConcurrent) { | ||
renderer.unstable_flushAll(); | ||
} | ||
}).toWarnDev(isConcurrent ? ['invalid', 'invalid'] : ['invalid']); | ||
expect(renderer).toHaveRenderedChildren( | ||
React.createElement(fallbackTagName, {prop: 'ErrorBoundary'}), | ||
); | ||
} | ||
|
||
describe(isConcurrent ? 'concurrent' : 'sync', () => { | ||
it('componentDidCatch can recover by rendering an element of the same type', () => | ||
sharedTest(DidCatchErrorBoundary, 'span')); | ||
|
||
it('componentDidCatch can recover by rendering an element of a different type', () => | ||
sharedTest(DidCatchErrorBoundary, 'div')); | ||
|
||
it('getDerivedStateFromError can recover by rendering an element of the same type', () => | ||
sharedTest(GetDerivedErrorBoundary, 'span')); | ||
|
||
it('getDerivedStateFromError can recover by rendering an element of a different type', () => | ||
sharedTest(GetDerivedErrorBoundary, 'div')); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.