-
Notifications
You must be signed in to change notification settings - Fork 47k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix context stack misalignment caused by error replay (#12508)
* Add regression tests for error boundary replay bugs * Ensure the context stack is aligned if renderer throws * Always throw when replaying a failed unit of work Replaying a failed unit of work should always throw, because the render phase is meant to be idempotent, If it doesn't throw, rethrow the original error, so React's internal stack is not misaligned. * Reset originalReplayError after replaying * Typo fix
- Loading branch information
Showing
3 changed files
with
94 additions
and
9 deletions.
There are no files selected for viewing
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
59 changes: 59 additions & 0 deletions
59
packages/react-reconciler/src/__tests__/ReactIncrementalErrorReplay-test.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,59 @@ | ||
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @emails react-core | ||
* @jest-environment node | ||
*/ | ||
|
||
'use strict'; | ||
|
||
let React; | ||
let ReactNoop; | ||
|
||
describe('ReactIncrementalErrorReplay', () => { | ||
beforeEach(() => { | ||
jest.resetModules(); | ||
React = require('react'); | ||
ReactNoop = require('react-noop-renderer'); | ||
}); | ||
|
||
function div(...children) { | ||
children = children.map(c => (typeof c === 'string' ? {text: c} : c)); | ||
return {type: 'div', children, prop: undefined}; | ||
} | ||
|
||
function span(prop) { | ||
return {type: 'span', children: [], prop}; | ||
} | ||
|
||
it('should fail gracefully on error in the host environment', () => { | ||
ReactNoop.simulateErrorInHostConfig(() => { | ||
ReactNoop.render(<span />); | ||
expect(() => ReactNoop.flush()).toThrow('Error in host config.'); | ||
}); | ||
}); | ||
|
||
it('should fail gracefully on error that does not reproduce on replay', () => { | ||
let didInit = false; | ||
|
||
function badLazyInit() { | ||
const needsInit = !didInit; | ||
didInit = true; | ||
if (needsInit) { | ||
throw new Error('Hi'); | ||
} | ||
} | ||
|
||
class App extends React.Component { | ||
render() { | ||
badLazyInit(); | ||
return <div />; | ||
} | ||
} | ||
ReactNoop.render(<App />); | ||
expect(() => ReactNoop.flush()).toThrow('Hi'); | ||
}); | ||
}); |