Skip to content

Commit

Permalink
[Fix] shallow: Mock sCU if gDSFP defined in shallow renderer rerender
Browse files Browse the repository at this point in the history
  • Loading branch information
chenesan authored and ljharb committed Feb 28, 2019
1 parent 9fedf8f commit b66ac28
Showing 1 changed file with 35 additions and 0 deletions.
35 changes: 35 additions & 0 deletions packages/enzyme/src/ShallowWrapper.js
Expand Up @@ -131,6 +131,10 @@ function getAdapterLifecycles({ options }) {
}),
}
: null;
const { getDerivedStateFromProps: originalGDSFP } = lifecycles;
const getDerivedStateFromProps = originalGDSFP ? {
hasShouldComponentUpdateBug: !!originalGDSFP.hasShouldComponentUpdateBug,
} : false;

return {
...lifecycles,
Expand All @@ -142,6 +146,7 @@ function getAdapterLifecycles({ options }) {
...lifecycles.getChildContext,
},
...(componentDidUpdate && { componentDidUpdate }),
getDerivedStateFromProps,
};
}

Expand Down Expand Up @@ -243,6 +248,28 @@ function privateSetChildContext(adapter, wrapper, instance, renderedNode, getChi
}
}

function mockSCUIfgDSFPReturnNonNull(node, state) {
const { getDerivedStateFromProps } = node.type;

if (typeof getDerivedStateFromProps === 'function') {
// 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 { instance } = node;
const { restore } = spyMethod(instance, 'shouldComponentUpdate', (originalSCU) => {
return function shouldComponentUpdate(...args) {
instance.state = state;
const sCUResult = originalSCU.apply(instance, args);
const [, nextState] = args;
instance.state = nextState;
restore();
return sCUResult;
};
});
}
}

/**
* @class ShallowWrapper
Expand Down Expand Up @@ -452,6 +479,10 @@ class ShallowWrapper {
&& instance
) {
if (typeof instance.shouldComponentUpdate === 'function') {
const { getDerivedStateFromProps: gDSFP } = lifecycles;
if (gDSFP && gDSFP.hasShouldComponentUpdateBug) {
mockSCUIfgDSFPReturnNonNull(node, state);
}
shouldComponentUpdateSpy = spyMethod(instance, 'shouldComponentUpdate');
}
if (
Expand Down Expand Up @@ -601,6 +632,10 @@ class ShallowWrapper {
&& lifecycles.componentDidUpdate.onSetState
&& typeof instance.shouldComponentUpdate === 'function'
) {
const { getDerivedStateFromProps: gDSFP } = lifecycles;
if (gDSFP && gDSFP.hasShouldComponentUpdateBug) {
mockSCUIfgDSFPReturnNonNull(node, state);
}
shouldComponentUpdateSpy = spyMethod(instance, 'shouldComponentUpdate');
}
if (
Expand Down

0 comments on commit b66ac28

Please sign in to comment.