diff --git a/src/renderers/testing/ReactTestReconcileTransaction.js b/src/renderers/testing/ReactTestReconcileTransaction.js index e0b959784eaf1..0929103fa12ca 100644 --- a/src/renderers/testing/ReactTestReconcileTransaction.js +++ b/src/renderers/testing/ReactTestReconcileTransaction.js @@ -89,6 +89,19 @@ var Mixin = { return ReactUpdateQueue; }, + /** + * Save current transaction state -- if the return value from this method is + * passed to `rollback`, the transaction will be reset to that state. + */ + checkpoint: function() { + // reactMountReady is the our only stateful wrapper + return this.reactMountReady.checkpoint(); + }, + + rollback: function(checkpoint) { + this.reactMountReady.rollback(checkpoint); + }, + /** * `PooledClass` looks for this, and will invoke this before allowing this * instance to be reused. diff --git a/src/renderers/testing/__tests__/ReactTestRenderer-test.js b/src/renderers/testing/__tests__/ReactTestRenderer-test.js index 24fff957ddc46..9e938242d9424 100644 --- a/src/renderers/testing/__tests__/ReactTestRenderer-test.js +++ b/src/renderers/testing/__tests__/ReactTestRenderer-test.js @@ -206,4 +206,42 @@ describe('ReactTestRenderer', function() { expect(log).toEqual([null]); }); + it('supports error boundaries', function() { + class Angry extends React.Component { + render() { + throw new Error('Please, do not render me.'); + } + } + + class Boundary extends React.Component { + constructor(props) { + super(props); + this.state = {error: false}; + } + render() { + if (!this.state.error) { + return (
); + } else { + return (
Happy Birthday!
); + } + } + onClick() { + /* do nothing */ + } + unstable_handleError() { + this.setState({error: true}); + } + } + + var EventPluginHub = require('EventPluginHub'); + EventPluginHub.putListener = jest.fn(); + var renderer = ReactTestRenderer.create(); + expect(renderer.toJSON()).toEqual({ + type: 'div', + props: {}, + children: ['Happy Birthday!'], + }); + expect(EventPluginHub.putListener).not.toBeCalled(); + }); + });