Skip to content

Commit

Permalink
[enzyme-adapter-utils] [fix] allow node, not just element
Browse files Browse the repository at this point in the history
Fixes #2030.
  • Loading branch information
ljharb committed Mar 5, 2019
1 parent f9ed0af commit a00ed0b
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 95 deletions.
Expand Up @@ -3,7 +3,7 @@ import { intersects } from 'semver';
import PropTypes from 'prop-types';

const propTypes = {
children: PropTypes.element.isRequired,
children: PropTypes.node.isRequired,
};

const Wrapper = (intersects('>= 0.14', React.version)
Expand Down
146 changes: 99 additions & 47 deletions packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
Expand Up @@ -5408,67 +5408,119 @@ describeWithDOM('mount', () => {
});
});

describe('.renderProp()', () => {
it('returns a wrapper around the node returned from the render prop', () => {
class Foo extends React.Component {
render() {
return <div className="in-foo" />;
wrap()
.withConsoleThrows()
.describe('.renderProp()', () => {
it('returns a wrapper around the node returned from the render prop', () => {
class Foo extends React.Component {
render() {
return <div className="in-foo" />;
}
}
}
class Bar extends React.Component {
render() {
const { render: r } = this.props;
return <div className="in-bar">{r()}</div>;
class Bar extends React.Component {
render() {
const { render: r } = this.props;
return <div className="in-bar">{r()}</div>;
}
}
}

const wrapperA = mount(<div><Bar render={() => <div><Foo /></div>} /></div>);
const renderPropWrapperA = wrapperA.find(Bar).renderProp('render')();
expect(renderPropWrapperA.find(Foo)).to.have.lengthOf(1);
const wrapperA = mount(<div><Bar render={() => <div><Foo /></div>} /></div>);
const renderPropWrapperA = wrapperA.find(Bar).renderProp('render')();
expect(renderPropWrapperA.find(Foo)).to.have.lengthOf(1);

const wrapperB = mount(<div><Bar render={() => <Foo />} /></div>);
const renderPropWrapperB = wrapperB.find(Bar).renderProp('render')();
expect(renderPropWrapperB.find(Foo)).to.have.lengthOf(1);
const wrapperB = mount(<div><Bar render={() => <Foo />} /></div>);
const renderPropWrapperB = wrapperB.find(Bar).renderProp('render')();
expect(renderPropWrapperB.find(Foo)).to.have.lengthOf(1);

const stub = sinon.stub().returns(<div />);
const wrapperC = mount(<div><Bar render={stub} /></div>);
stub.resetHistory();
wrapperC.find(Bar).renderProp('render')('one', 'two');
expect(stub.args).to.deep.equal([['one', 'two']]);
});
const stub = sinon.stub().returns(<div />);
const wrapperC = mount(<div><Bar render={stub} /></div>);
stub.resetHistory();
wrapperC.find(Bar).renderProp('render')('one', 'two');
expect(stub.args).to.deep.equal([['one', 'two']]);
});

it('throws on host elements', () => {
class Div extends React.Component {
render() {
const { children } = this.props;
return <div>{children}</div>;
it('throws on host elements', () => {
class Div extends React.Component {
render() {
const { children } = this.props;
return <div>{children}</div>;
}
}
}

const wrapper = mount(<Div />).childAt(0);
expect(wrapper.is('div')).to.equal(true);
expect(() => wrapper.renderProp('foo')).to.throw();
});
const wrapper = mount(<Div />).childAt(0);
expect(wrapper.is('div')).to.equal(true);
expect(() => wrapper.renderProp('foo')).to.throw();
});

wrap()
.withOverride(() => getAdapter(), 'wrap', () => undefined)
.it('throws with a react adapter that lacks a `.wrap`', () => {
class Foo extends React.Component {
render() {
return <div className="in-foo" />;
wrap()
.withOverride(() => getAdapter(), 'wrap', () => undefined)
.it('throws with a react adapter that lacks a `.wrap`', () => {
class Foo extends React.Component {
render() {
return <div className="in-foo" />;
}
}
}
class Bar extends React.Component {
render() {
const { render: r } = this.props;
return <div className="in-bar">{r()}</div>;
class Bar extends React.Component {
render() {
const { render: r } = this.props;
return <div className="in-bar">{r()}</div>;
}
}

const wrapper = mount(<div><Bar render={() => <div><Foo /></div>} /></div>);
expect(() => wrapper.find(Bar).renderProp('render')).to.throw(RangeError);
});

describeIf(is('>= 16'), 'allows non-nodes', () => {
function MyComponent({ val }) {
return <ComponentWithRenderProp val={val} r={x => x} />;
}

function ComponentWithRenderProp({ val, r }) {
return r(val);
}

const wrapper = mount(<div><Bar render={() => <div><Foo /></div>} /></div>);
expect(() => wrapper.find(Bar).renderProp('render')).to.throw(RangeError);
it('works with strings', () => {
const wrapper = mount(<MyComponent val="foo" />);

wrapper.find(ComponentWithRenderProp).renderProp('r')('foo');

wrapper.find(ComponentWithRenderProp).renderProp('r')('');
});

it('works with numbers', () => {
const wrapper = mount(<MyComponent val={42} />);

wrapper.find(ComponentWithRenderProp).renderProp('r')(42);

wrapper.find(ComponentWithRenderProp).renderProp('r')(0);

wrapper.find(ComponentWithRenderProp).renderProp('r')(NaN);
});

it('works with arrays', () => {
const wrapper = mount(<MyComponent val={[]} />);

wrapper.find(ComponentWithRenderProp).renderProp('r')([]);

wrapper.find(ComponentWithRenderProp).renderProp('r')(['a']);

wrapper.find(ComponentWithRenderProp).renderProp('r')([Infinity]);
});

it('works with false', () => {
const wrapper = mount(<MyComponent val={false} />);

wrapper.find(ComponentWithRenderProp).renderProp('r')(false);
});

it('throws with true', () => {
const wrapper = mount(<MyComponent val={false} />);

expect(() => wrapper.find(ComponentWithRenderProp).renderProp('r')(true)).to.throw();
});
});
});
});

describe('lifecycle methods', () => {
describeIf(is('>= 16.3'), 'getDerivedStateFromProps', () => {
Expand Down
146 changes: 99 additions & 47 deletions packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
Expand Up @@ -5489,67 +5489,119 @@ describe('shallow', () => {
});
});

describe('.renderProp()', () => {
it('returns a wrapper around the node returned from the render prop', () => {
class Foo extends React.Component {
render() {
return <div className="in-foo" />;
wrap()
.withConsoleThrows()
.describe('.renderProp()', () => {
it('returns a wrapper around the node returned from the render prop', () => {
class Foo extends React.Component {
render() {
return <div className="in-foo" />;
}
}
}
class Bar extends React.Component {
render() {
const { render: r } = this.props;
return <div className="in-bar">{r()}</div>;
class Bar extends React.Component {
render() {
const { render: r } = this.props;
return <div className="in-bar">{r()}</div>;
}
}
}

const wrapperA = shallow(<div><Bar render={() => <div><Foo /></div>} /></div>);
const renderPropWrapperA = wrapperA.find(Bar).renderProp('render')();
expect(renderPropWrapperA.find(Foo)).to.have.lengthOf(1);
const wrapperA = shallow(<div><Bar render={() => <div><Foo /></div>} /></div>);
const renderPropWrapperA = wrapperA.find(Bar).renderProp('render')();
expect(renderPropWrapperA.find(Foo)).to.have.lengthOf(1);

const wrapperB = shallow(<div><Bar render={() => <Foo />} /></div>);
const renderPropWrapperB = wrapperB.find(Bar).renderProp('render')();
expect(renderPropWrapperB.find(Foo)).to.have.lengthOf(1);
const wrapperB = shallow(<div><Bar render={() => <Foo />} /></div>);
const renderPropWrapperB = wrapperB.find(Bar).renderProp('render')();
expect(renderPropWrapperB.find(Foo)).to.have.lengthOf(1);

const stub = sinon.stub().returns(<div />);
const wrapperC = shallow(<div><Bar render={stub} /></div>);
stub.resetHistory();
wrapperC.find(Bar).renderProp('render')('one', 'two');
expect(stub.args).to.deep.equal([['one', 'two']]);
});
const stub = sinon.stub().returns(<div />);
const wrapperC = shallow(<div><Bar render={stub} /></div>);
stub.resetHistory();
wrapperC.find(Bar).renderProp('render')('one', 'two');
expect(stub.args).to.deep.equal([['one', 'two']]);
});

it('throws on host elements', () => {
class Div extends React.Component {
render() {
const { children } = this.props;
return <div>{children}</div>;
it('throws on host elements', () => {
class Div extends React.Component {
render() {
const { children } = this.props;
return <div>{children}</div>;
}
}
}

const wrapper = shallow(<Div />);
expect(wrapper.is('div')).to.equal(true);
expect(() => wrapper.renderProp('foo')).to.throw();
});
const wrapper = shallow(<Div />);
expect(wrapper.is('div')).to.equal(true);
expect(() => wrapper.renderProp('foo')).to.throw();
});

wrap()
.withOverride(() => getAdapter(), 'wrap', () => undefined)
.it('throws with a react adapter that lacks a `.wrap`', () => {
class Foo extends React.Component {
render() {
return <div className="in-foo" />;
wrap()
.withOverride(() => getAdapter(), 'wrap', () => undefined)
.it('throws with a react adapter that lacks a `.wrap`', () => {
class Foo extends React.Component {
render() {
return <div className="in-foo" />;
}
}
}
class Bar extends React.Component {
render() {
const { render: r } = this.props;
return <div className="in-bar">{r()}</div>;
class Bar extends React.Component {
render() {
const { render: r } = this.props;
return <div className="in-bar">{r()}</div>;
}
}

const wrapper = shallow(<div><Bar render={() => <div><Foo /></div>} /></div>);
expect(() => wrapper.find(Bar).renderProp('render')).to.throw(RangeError);
});

describeIf(is('>= 16'), 'allows non-nodes', () => {
function MyComponent({ val }) {
return <ComponentWithRenderProp val={val} r={x => x} />;
}

function ComponentWithRenderProp({ val, r }) {
return r(val);
}

const wrapper = shallow(<div><Bar render={() => <div><Foo /></div>} /></div>);
expect(() => wrapper.find(Bar).renderProp('render')).to.throw(RangeError);
it('works with strings', () => {
const wrapper = shallow(<MyComponent val="foo" />);

wrapper.find(ComponentWithRenderProp).renderProp('r')('foo');

wrapper.find(ComponentWithRenderProp).renderProp('r')('');
});

it('works with numbers', () => {
const wrapper = shallow(<MyComponent val={42} />);

wrapper.find(ComponentWithRenderProp).renderProp('r')(42);

wrapper.find(ComponentWithRenderProp).renderProp('r')(0);

wrapper.find(ComponentWithRenderProp).renderProp('r')(NaN);
});

it('works with arrays', () => {
const wrapper = shallow(<MyComponent val={[]} />);

wrapper.find(ComponentWithRenderProp).renderProp('r')([]);

wrapper.find(ComponentWithRenderProp).renderProp('r')(['a']);

wrapper.find(ComponentWithRenderProp).renderProp('r')([Infinity]);
});

it('works with false', () => {
const wrapper = shallow(<MyComponent val={false} />);

wrapper.find(ComponentWithRenderProp).renderProp('r')(false);
});

it('throws with true', () => {
const wrapper = shallow(<MyComponent val={false} />);

expect(() => wrapper.find(ComponentWithRenderProp).renderProp('r')(true).shallow()).to.throw();
});
});
});
});

describe('lifecycle methods', () => {
describe('disableLifecycleMethods option', () => {
Expand Down

0 comments on commit a00ed0b

Please sign in to comment.