Skip to content

Commit faea638

Browse files
chenesanljharb
authored andcommitted
Mock SCU if gDSFP defined in shallow renderer rerender
1 parent deefeb9 commit faea638

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed

packages/enzyme/src/ShallowWrapper.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ function getAdapterLifecycles({ options }) {
131131
}),
132132
}
133133
: null;
134+
const { getDerivedStateFromProps: originalGDSFP } = lifecycles;
135+
const getDerivedStateFromProps = originalGDSFP ? {
136+
hasShouldComponentUpdateBug: !!originalGDSFP.hasShouldComponentUpdateBug,
137+
} : false;
134138

135139
return {
136140
...lifecycles,
@@ -142,6 +146,7 @@ function getAdapterLifecycles({ options }) {
142146
...lifecycles.getChildContext,
143147
},
144148
...(componentDidUpdate && { componentDidUpdate }),
149+
getDerivedStateFromProps,
145150
};
146151
}
147152

@@ -243,6 +248,28 @@ function privateSetChildContext(adapter, wrapper, instance, renderedNode, getChi
243248
}
244249
}
245250

251+
function mockSCUIfgDSFPReturnNonNull(node, state) {
252+
const { getDerivedStateFromProps } = node.type;
253+
254+
if (typeof getDerivedStateFromProps === 'function') {
255+
// we try to fix a React shallow renderer bug here.
256+
// (facebook/react#14607, which has been fixed in react 16.8):
257+
// when gDSFP return derived state, it will set instance state in shallow renderer before SCU,
258+
// this will cause `this.state` in sCU be the updated state, which is wrong behavior.
259+
// so we have to wrap sCU to pass the old state to original sCU.
260+
const { instance } = node;
261+
const { restore } = spyMethod(instance, 'shouldComponentUpdate', (originalSCU) => {
262+
return function shouldComponentUpdate(...args) {
263+
instance.state = state;
264+
const sCUResult = originalSCU.apply(instance, args);
265+
const [, nextState] = args;
266+
instance.state = nextState;
267+
restore();
268+
return sCUResult;
269+
};
270+
});
271+
}
272+
}
246273

247274
/**
248275
* @class ShallowWrapper
@@ -452,6 +479,10 @@ class ShallowWrapper {
452479
&& instance
453480
) {
454481
if (typeof instance.shouldComponentUpdate === 'function') {
482+
const { getDerivedStateFromProps: gDSFP } = lifecycles;
483+
if (gDSFP && gDSFP.hasShouldComponentUpdateBug) {
484+
mockSCUIfgDSFPReturnNonNull(node, state);
485+
}
455486
shouldComponentUpdateSpy = spyMethod(instance, 'shouldComponentUpdate');
456487
}
457488
if (
@@ -601,6 +632,10 @@ class ShallowWrapper {
601632
&& lifecycles.componentDidUpdate.onSetState
602633
&& typeof instance.shouldComponentUpdate === 'function'
603634
) {
635+
const { getDerivedStateFromProps: gDSFP } = lifecycles;
636+
if (gDSFP && gDSFP.hasShouldComponentUpdateBug) {
637+
mockSCUIfgDSFPReturnNonNull(node, state);
638+
}
604639
shouldComponentUpdateSpy = spyMethod(instance, 'shouldComponentUpdate');
605640
}
606641
if (

0 commit comments

Comments
 (0)