diff --git a/.travis.yml b/.travis.yml index bd95283e3..e5c88bfae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,8 @@ matrix: env: REACT=16 - node_js: "6" env: REACT=16 + - node_js: "lts/*" + env: REACT=16.8.5 RENDERER=16.8.5 - node_js: "lts/*" env: REACT=16.8.3 - node_js: "lts/*" diff --git a/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js b/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js index 76ad49ac0..f3b21ea99 100644 --- a/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js +++ b/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js @@ -405,6 +405,27 @@ class ReactSixteenAdapter extends EnzymeAdapter { const renderer = new ShallowRenderer(); let isDOM = false; let cachedNode = null; + + let lastComponent = null; + let wrappedComponent = null; + + // Wrap functional components on versions prior to 16.5, + // to avoid inadvertently pass a `this` instance to it. + const wrapFunctionalComponent = (Component) => { + if (is165) { + return Component; + } + + if (lastComponent !== Component) { + wrappedComponent = Object.assign( + (...args) => Component(...args), // eslint-disable-line new-cap + Component, + ); + lastComponent = Component; + } + return wrappedComponent; + }; + return { render(el, unmaskedContext) { cachedNode = el; @@ -424,20 +445,19 @@ class ReactSixteenAdapter extends EnzymeAdapter { if (!isStateful && isMemo(el.type)) { const InnerComp = el.type.type; - const wrappedEl = Object.assign( - (...args) => InnerComp(...args), // eslint-disable-line new-cap - InnerComp, - ); - return withSetStateAllowed(() => renderer.render({ ...el, type: wrappedEl }, context)); + return withSetStateAllowed(() => renderer.render( + { ...el, type: wrapFunctionalComponent(InnerComp) }, + context, + )); } if (!isStateful && typeof Component === 'function') { - const wrappedEl = Object.assign( - (...args) => Component(...args), // eslint-disable-line new-cap - Component, - ); - return withSetStateAllowed(() => renderer.render({ ...el, type: wrappedEl }, context)); + return withSetStateAllowed(() => renderer.render( + { ...el, type: wrapFunctionalComponent(Component) }, + context, + )); } + if (isStateful) { // fix react bug; see implementation of `getEmptyStateValue` const emptyStateValue = getEmptyStateValue(); diff --git a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx index 7cdfb73a3..b9d067b92 100644 --- a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx +++ b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx @@ -643,7 +643,7 @@ describe('shallow', () => { }); }); - describeIf(is('>= 16.8'), 'hooks', () => { + describeIf(is('>= 16.8.5'), 'hooks', () => { // TODO: enable when the shallow renderer fixes its bug it.skip('works with `useEffect`', (done) => { function ComponentUsingEffectHook() { diff --git a/packages/enzyme-test-suite/test/shared/methods/find.jsx b/packages/enzyme-test-suite/test/shared/methods/find.jsx index c511f2973..be3d252b5 100644 --- a/packages/enzyme-test-suite/test/shared/methods/find.jsx +++ b/packages/enzyme-test-suite/test/shared/methods/find.jsx @@ -17,6 +17,7 @@ import { Fragment, forwardRef, memo, + useState, } from '../../_helpers/react-compat'; export default function describeFind({ @@ -767,6 +768,49 @@ export default function describeFind({ }); }); + describeIf(is('>= 16.8'), 'hooks', () => { + it('handles useState', () => { + const ComponentUsingStateHook = () => { + const [count] = useState(0); + return