From cffd5b00a431768b6e551ab3bd3da3653c0301b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E4=B9=99=E5=B1=B1?= Date: Thu, 28 Feb 2019 17:28:11 +0800 Subject: [PATCH] Mock SCU if gDSFP defined in shallow renderer rerender --- packages/enzyme/src/ShallowWrapper.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/enzyme/src/ShallowWrapper.js b/packages/enzyme/src/ShallowWrapper.js index b0165110e..acf8080d7 100644 --- a/packages/enzyme/src/ShallowWrapper.js +++ b/packages/enzyme/src/ShallowWrapper.js @@ -243,6 +243,29 @@ function privateSetChildContext(adapter, wrapper, instance, renderedNode, getChi } } +function mockSCUIfgDSFPReturnNonNull(node, props, state) { + const { getDerivedStateFromProps } = node.type; + const { instance } = node; + if (typeof getDerivedStateFromProps === 'function') { + const gDSFPResult = getDerivedStateFromProps(props, state); + if (gDSFPResult != null) { + // we try to fix a React shallow renderer bug here. + // (facebook/react#14607, which has been fixed in react 16.8): + // when gDSFP return derived state, it will set instance state in shallow renderer before SCU, + // this will cause `this.state` in sCU be the updated state, which is wrong behavior. + // so we have to wrap sCU to pass the old state to original sCU. + const originalSCU = instance.shouldComponentUpdate; + instance.shouldComponentUpdate = (...args) => { + instance.state = state; + const sCUResult = originalSCU.apply(instance, args); + const nextState = args[1]; + instance.state = nextState; + instance.shouldComponentUpdate = originalSCU; + return sCUResult; + }; + } + } +} /** * @class ShallowWrapper @@ -452,6 +475,8 @@ class ShallowWrapper { && instance ) { if (typeof instance.shouldComponentUpdate === 'function') { + const nextProps = { ...prevProps, ...props }; + mockSCUIfgDSFPReturnNonNull(node, nextProps, state, instance); shouldComponentUpdateSpy = spyMethod(instance, 'shouldComponentUpdate'); } if ( @@ -601,6 +626,8 @@ class ShallowWrapper { && lifecycles.componentDidUpdate.onSetState && typeof instance.shouldComponentUpdate === 'function' ) { + const props = prevProps; + mockSCUIfgDSFPReturnNonNull(node, props, state, instance); shouldComponentUpdateSpy = spyMethod(instance, 'shouldComponentUpdate'); } if (