Skip to content

Commit

Permalink
[enzyme-adapter-react-16] [new] Added support for React.memo
Browse files Browse the repository at this point in the history
  • Loading branch information
jintoppy authored and ljharb committed Nov 22, 2018
1 parent 0a89b1f commit bcbb1e8
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 1 deletion.
14 changes: 13 additions & 1 deletion packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
ForwardRef,
Profiler,
Portal,
isMemo,
Memo,
} from 'react-is';
import { EnzymeAdapter } from 'enzyme';
import { typeOfNode } from 'enzyme/build/Utils';
Expand Down Expand Up @@ -94,7 +96,6 @@ function elementToTree(el) {

const { children, containerInfo } = el;
const props = { children, containerInfo };

return {
nodeType: 'portal',
type: Portal,
Expand Down Expand Up @@ -143,6 +144,7 @@ function toTree(vnode) {
instance: node.stateNode,
rendered: childrenToTree(node.child),
};
case FiberTags.Memo:
case FiberTags.FunctionalComponent:
return {
nodeType: 'function',
Expand Down Expand Up @@ -357,6 +359,15 @@ class ReactSixteenAdapter extends EnzymeAdapter {
|| Array.isArray(Component.__reactAutoBindPairs) // fallback for createClass components
);

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));
}

if (!isStateful && typeof Component === 'function') {
const wrappedEl = Object.assign(
(...args) => Component(...args), // eslint-disable-line new-cap
Expand Down Expand Up @@ -513,6 +524,7 @@ class ReactSixteenAdapter extends EnzymeAdapter {
switch ($$typeofType) {
case ContextConsumer || NaN: return 'ContextConsumer';
case ContextProvider || NaN: return 'ContextProvider';
case Memo || NaN: return 'Memo';
case ForwardRef || NaN: {
if (type.displayName) {
return type.displayName;
Expand Down
4 changes: 4 additions & 0 deletions packages/enzyme-adapter-react-16/src/detectFiberTags.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module.exports = function detectFiberTags() {
const supportsMode = typeof React.StrictMode !== 'undefined';
const supportsContext = typeof React.createContext !== 'undefined';
const supportsForwardRef = typeof React.forwardRef !== 'undefined';
const supportsMemo = typeof React.memo !== 'undefined';

function Fn() {
return null;
Expand All @@ -44,6 +45,9 @@ module.exports = function detectFiberTags() {
ClassComponent: getFiber(React.createElement(Cls)).tag,
Fragment: getFiber([['nested']]).tag,
FunctionalComponent: getFiber(React.createElement(Fn)).tag,
Memo: supportsMemo
? getFiber(React.createElement(React.memo(Fn))).tag
: -1,
HostPortal: getFiber(ReactDOM.createPortal(null, global.document.createElement('div'))).tag,
HostComponent: getFiber(React.createElement('span')).tag,
HostText: getFiber('text').tag,
Expand Down
35 changes: 35 additions & 0 deletions packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
createRef,
Fragment,
forwardRef,
memo,
PureComponent,
} from './_helpers/react-compat';
import {
Expand Down Expand Up @@ -461,6 +462,40 @@ describeWithDOM('mount', () => {
expect(wrapper.find(TestItem)).to.have.lengthOf(3);
expect(wrapper.find(TestItem).first().props().test).to.equal('123');
});

itIf(is('>= 16.6'), 'works with memo', () => {
const InnerComp = () => <div><span>Hello</span></div>;
const Foo = memo(({ foo }) => (
<div>
<InnerComp />
<div className="bar">bar</div>
<div className="qoo">{foo}</div>
</div>
));

const wrapper = mount(<Foo foo="qux" />);
expect(wrapper.debug()).to.equal(`<Component foo="qux">
<div>
<InnerComp>
<div>
<span>
Hello
</span>
</div>
</InnerComp>
<div className="bar">
bar
</div>
<div className="qoo">
qux
</div>
</div>
</Component>`);
expect(wrapper.find('InnerComp')).to.have.lengthOf(1);
expect(wrapper.find('.bar')).to.have.lengthOf(1);
expect(wrapper.find('.qoo').text()).to.equal('qux');
});

});

describeIf(is('>= 16'), 'portals', () => {
Expand Down
42 changes: 42 additions & 0 deletions packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
createRef,
Fragment,
forwardRef,
memo,
PureComponent,
} from './_helpers/react-compat';
import {
Expand Down Expand Up @@ -1273,6 +1274,47 @@ describe('shallow', () => {
expect(wrapper.find(Component.displayName)).to.have.lengthOf(2);
});
});

describeIf(is('>= 16.6'), 'memo', () => {
it('renders memoized component', () => {
const Component = () => <div>Memoized component</div>;
const ComponentWithMemo = memo(Component);

const wrapper = shallow(<ComponentWithMemo />);
expect(wrapper.find('div')).to.have.lengthOf(1);
expect(wrapper.debug()).to.equal(`<div>
Memoized component
</div>`);
});

it('renders memoized component and passes the props', () => {
const Component = ({ title }) => <div><span>{title}</span></div>;
const ComponentWithMemo = memo(Component);

const wrapper = shallow(<ComponentWithMemo title="memo test" />);
expect(wrapper.find('span').text()).to.equal('memo test');
});

it('finds memo', () => {
const Component = memo(() => <div />);
Component.displayName = 'CustomMemo';
class Foo extends React.Component {
render() {
return (
<div>
<Component />
<Component />
</div>
);
}
}

const wrapper = shallow(<Foo />);
expect(wrapper.find(Component)).to.have.lengthOf(2);
expect(wrapper.find('Memo')).to.have.lengthOf(2);
});
});

});

describe('.findWhere(predicate)', () => {
Expand Down

0 comments on commit bcbb1e8

Please sign in to comment.