Skip to content

Commit

Permalink
Add support for forwardRef
Browse files Browse the repository at this point in the history
  • Loading branch information
jquense authored and ljharb committed Mar 23, 2018
1 parent e6287cc commit f818a17
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 3 deletions.
2 changes: 2 additions & 0 deletions packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const HostText = 6;
const Mode = 11;
const ContextConsumerType = 12;
const ContextProviderType = 13;
const ForwardRefType = 14;

function nodeAndSiblingsArray(nodeWithSibling) {
const array = [];
Expand Down Expand Up @@ -130,6 +131,7 @@ function toTree(vnode) {
case Mode: // 11
case ContextProviderType: // 13
case ContextConsumerType: // 12
case ForwardRefType: // 14
return childrenToTree(node.child);
default:
throw new Error(`Enzyme Internal Error: unknown node with tag ${node.tag}`);
Expand Down
7 changes: 6 additions & 1 deletion packages/enzyme-adapter-utils/src/createMountWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import PropTypes from 'prop-types';

/* eslint react/forbid-prop-types: 0 */

// TODO: use react-is?
const specialType = PropTypes.shape({
$$typeof: PropTypes.any.isRequired,
}).isRequired;

/**
* This is a utility component to wrap around the nodes we are
* passing in to `mount()`. Theoretically, you could do everything
Expand Down Expand Up @@ -62,7 +67,7 @@ export default function createMountWrapper(node, options = {}) {
}
}
WrapperComponent.propTypes = {
Component: PropTypes.oneOfType([PropTypes.func, PropTypes.string]).isRequired,
Component: PropTypes.oneOfType([PropTypes.func, PropTypes.string, specialType]).isRequired,
props: PropTypes.object.isRequired,
context: PropTypes.object,
};
Expand Down
37 changes: 36 additions & 1 deletion packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import {
} from 'enzyme/build/Utils';

import './_helpers/setupAdapters';
import { createClass, createContext, createPortal } from './_helpers/react-compat';
import {
createClass,
createContext,
createPortal,
forwardRef,
} from './_helpers/react-compat';
import {
describeWithDOM,
describeIf,
Expand Down Expand Up @@ -203,6 +208,36 @@ describeWithDOM('mount', () => {
expect(wrapper.find('span').text()).to.equal('foo');
});

describeIf(is('>= 16.3'), 'forwarded ref Components', () => {
it('should mount without complaint', () => {
const warningStub = sinon.stub(console, 'error');

const SomeComponent = forwardRef((props, ref) => (
<div {...props} ref={ref} />
));

mount(<SomeComponent />);

expect(warningStub).to.have.property('callCount', 0);

warningStub.restore();
});

it('should find elements through forwardedRef elements', () => {
const testRef = () => {};
const SomeComponent = forwardRef((props, ref) => (
<div ref={ref}>
<span className="child1" />
<span className="child2" />
</div>
));

const wrapper = mount(<div><SomeComponent ref={testRef} /></div>);

expect(wrapper.find('.child2')).to.have.lengthOf(1);
});
});

describeIf(is('> 0.13'), 'stateless components', () => {
it('can pass in context', () => {
const SimpleComponent = (props, context) => (
Expand Down
49 changes: 48 additions & 1 deletion packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ import {
} from 'enzyme/build/Utils';

import './_helpers/setupAdapters';
import { createClass, createContext } from './_helpers/react-compat';
import {
createClass,
createContext,
forwardRef,
createPortal,
} from './_helpers/react-compat';
import {
describeIf,
itIf,
Expand Down Expand Up @@ -139,7 +144,19 @@ describe('shallow', () => {

expect(shallow(<Consumes />).find('span')).to.have.lengthOf(1);
expect(shallow(<Provides />).find(Consumes)).to.have.lengthOf(1);
});

itIf(is('>= 16.3'), 'should find elements through forwarded refs elements', () => {
const SomeComponent = forwardRef((props, ref) => (
<div ref={ref}>
<span className="child1" />
<span className="child2" />
</div>
));

const wrapper = shallow(<SomeComponent />);

expect(wrapper.find('.child2')).to.have.length(1);
});

describeIf(is('> 0.13'), 'stateless function components', () => {
Expand Down Expand Up @@ -3344,6 +3361,36 @@ describe('shallow', () => {
it('should pass through to the debugNodes function', () => {
expect(shallow(<div />).debug()).to.equal('<div />');
});

itIf(is('>= 16.3'), 'should handle internal types gracefully', () => {
const { Provider, Consumer } = createContext(null);
// eslint-disable-next-line prefer-arrow-callback
const Forwarded = forwardRef(function MyComponent(props) {
return (
<Provider value={5}>
<Forwarded />
<div {...props}>
<React.Fragment>
<Consumer>{function Named() { return <div />; }}</Consumer>
{createPortal(<span />, { nodeType: 1 })}
</React.Fragment>
</div>
</Provider>
);
});

expect(shallow(<Forwarded />).debug()).to.equal(`<ContextProvider value={5}>
<ForwardRef(MyComponent) />
<div>
<Fragment>
<ContextConsumer>
[function Named]
</ContextConsumer>
<Portal />
</Fragment>
</div>
</ContextProvider>`);
});
});

describe('.html()', () => {
Expand Down

0 comments on commit f818a17

Please sign in to comment.