From 64b1361b7ab411e912f789ef712ffeb5eaee9b0a Mon Sep 17 00:00:00 2001 From: John Haitas Date: Fri, 2 Nov 2018 13:45:58 -0500 Subject: [PATCH] Adds support for `static getDerivedStateFromError(error)`. Should resolve https://github.com/developit/preact-render-to-string/issues/65. Includes 3 tests. --- src/index.js | 3 +- test/render.js | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index c2583626..3bb8e8f8 100644 --- a/src/index.js +++ b/src/index.js @@ -79,7 +79,8 @@ function renderToString(vnode, context, opts, inner, isSvgMode) { rendered = c.render(c.props, c.state, c.context); } catch (error) { - if (c.componentDidCatch) c.componentDidCatch(error); + if (nodeName.getDerivedStateFromError) c.state = assign(assign({}, c.state), nodeName.getDerivedStateFromError(error)); + else if (c.componentDidCatch) c.componentDidCatch(error); else throw error; } diff --git a/test/render.js b/test/render.js index 2db8c965..9e428749 100644 --- a/test/render.js +++ b/test/render.js @@ -672,5 +672,81 @@ describe('render', () => { expect(Test.prototype.render) .to.throw(); }); + + it('should invoke getDerivedStateFromError from an error thrown in getDerivedStateFromProps', () => { + class Test extends Component { + static getDerivedStateFromProps() { + throw new Error(); + } + static getDerivedStateFromError(error) {} + componentDidCatch(error) {} + } + spy(Test.prototype.constructor, 'getDerivedStateFromProps'); + spy(Test.prototype.constructor, 'getDerivedStateFromError'); + spy(Test.prototype, 'componentDidCatch'); + + render(); + + expect(Test.prototype.constructor.getDerivedStateFromProps) + .to.have.been.calledOnce + .and.to.have.been.calledBefore(Test.prototype.constructor.getDerivedStateFromError); + + expect(Test.prototype.componentDidCatch) + .to.not.have.been.called; + + expect(Test.prototype.constructor.getDerivedStateFromProps) + .to.throw(); + }); + + it('should invoke getDerivedStateFromError from an error thrown in componentWillMount', () => { + class Test extends Component { + static getDerivedStateFromError(error) {} + componentWillMount() { + throw new Error(); + } + componentDidCatch(error) {} + } + spy(Test.prototype.constructor, 'getDerivedStateFromError'); + spy(Test.prototype, 'componentWillMount'); + spy(Test.prototype, 'componentDidCatch'); + + render(); + + expect(Test.prototype.componentWillMount) + .to.have.been.calledOnce + .and.to.have.been.calledBefore(Test.prototype.constructor.getDerivedStateFromError); + + expect(Test.prototype.componentDidCatch) + .to.not.have.been.called; + + expect(Test.prototype.componentWillMount) + .to.throw(); + }); + + it('should invoke getDerivedStateFromError from an error thrown in render', () => { + class Test extends Component { + static getDerivedStateFromError(error) {} + componentDidCatch(error) {} + render(props) { + throw new Error('Error in render() method'); + return
; // eslint-disable-line + } + } + spy(Test.prototype.constructor, 'getDerivedStateFromError'); + spy(Test.prototype, 'componentDidCatch'); + spy(Test.prototype, 'render'); + + render(); + + expect(Test.prototype.render) + .to.have.been.calledOnce + .and.to.have.been.calledBefore(Test.prototype.constructor.getDerivedStateFromError); + + expect(Test.prototype.componentDidCatch) + .to.not.have.been.called; + + expect(Test.prototype.render) + .to.throw(); + }); }); });