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 (