d2-ui
Version:
1,682 lines (1,445 loc) • 83.6 kB
JavaScript
import React from 'react';
import { expect } from 'chai';
import { shallow, render, ShallowWrapper } from '../src/';
import sinon from 'sinon';
import { describeIf } from './_helpers';
import { REACT013 } from '../src/version';
describe('shallow', () => {
describe('context', () => {
it('can pass in context', () => {
const SimpleComponent = React.createClass({
contextTypes: {
name: React.PropTypes.string,
},
render() {
return <div>{this.context.name}</div>;
},
});
const context = { name: 'foo' };
const wrapper = shallow(<SimpleComponent />, { context });
expect(wrapper.text()).to.equal('foo');
});
it('should not throw if context is passed in but contextTypes is missing', () => {
const SimpleComponent = React.createClass({
render() {
return <div>{this.context.name}</div>;
},
});
const context = { name: 'foo' };
expect(() => shallow(<SimpleComponent />, { context })).to.not.throw(Error);
});
it('is instrospectable through context API', () => {
const SimpleComponent = React.createClass({
contextTypes: {
name: React.PropTypes.string,
},
render() {
return <div>{this.context.name}</div>;
},
});
const context = { name: 'foo' };
const wrapper = shallow(<SimpleComponent />, { context });
expect(wrapper.context().name).to.equal(context.name);
expect(wrapper.context('name')).to.equal(context.name);
});
describeIf(!REACT013, 'stateless function components', () => {
it('can pass in context', () => {
const SimpleComponent = (props, context) => (
<div>{context.name}</div>
);
SimpleComponent.contextTypes = { name: React.PropTypes.string };
const context = { name: 'foo' };
const wrapper = shallow(<SimpleComponent />, { context });
expect(wrapper.text()).to.equal('foo');
});
it('should not throw if context is passed in but contextTypes is missing', () => {
const SimpleComponent = (props, context) => (
<div>{context.name}</div>
);
const context = { name: 'foo' };
expect(() => shallow(<SimpleComponent />, { context })).not.to.throw(Error);
});
it('is instrospectable through context API', () => {
const SimpleComponent = (props, context) => (
<div>{context.name}</div>
);
SimpleComponent.contextTypes = { name: React.PropTypes.string };
const wrapper = shallow(<SimpleComponent />, { context });
expect(wrapper.context().name).to.equal(context.name);
expect(wrapper.context('name')).to.equal(context.name);
});
});
});
describeIf(!REACT013, 'stateless function components', () => {
it('works with stateless components', () => {
const Foo = ({ foo }) => (
<div>
<div className="bar">bar</div>
<div className="qoo">{foo}</div>
</div>
);
const wrapper = shallow(<Foo foo="qux" />);
expect(wrapper.type()).to.equal('div');
expect(wrapper.find('.bar')).to.have.length(1);
expect(wrapper.find('.qoo').text()).to.equal('qux');
});
});
describe('.instance()', () => {
it('should return the component instance', () => {
class Foo extends React.Component {
render() { return <div />; }
}
const wrapper = shallow(<Foo />);
expect(wrapper.instance()).to.be.instanceof(Foo);
expect(wrapper.instance().render).to.equal(Foo.prototype.render);
});
it('should throw if called on something other than the root node', () => {
class Foo extends React.Component {
render() { return <div><a /></div>; }
}
const wrapper = shallow(<Foo />);
const div = wrapper.find('div');
expect(() => div.instance()).to.throw();
});
});
describe('.contains(node)', () => {
it('should allow matches on the root node', () => {
const a = <div className="foo" />;
const b = <div className="foo" />;
const c = <div className="bar" />;
expect(shallow(a).contains(b)).to.equal(true);
expect(shallow(a).contains(c)).to.equal(false);
});
it('should allow matches on a nested node', () => {
const wrapper = shallow(
<div>
<div className="foo" />
</div>
);
const b = <div className="foo" />;
expect(wrapper.contains(b)).to.equal(true);
});
it('should match composite components', () => {
class Foo extends React.Component {
render() { return <div />; }
}
const wrapper = shallow(
<div>
<Foo />
</div>
);
const b = <Foo />;
expect(wrapper.contains(b)).to.equal(true);
});
it('should work with strings', () => {
const wrapper = shallow(<div>foo</div>);
expect(wrapper.contains('foo')).to.equal(true);
expect(wrapper.contains('bar')).to.equal(false);
});
it('should work with numbers', () => {
const wrapper = shallow(<div>{1}</div>);
expect(wrapper.contains(1)).to.equal(true);
expect(wrapper.contains(2)).to.equal(false);
expect(wrapper.contains('1')).to.equal(false);
});
it('should work with nested strings & numbers', () => {
const wrapper = shallow(
<div>
<div>
<div>{5}</div>
</div>
<div>foo</div>
</div>
);
expect(wrapper.contains('foo')).to.equal(true);
expect(wrapper.contains(<div>foo</div>)).to.equal(true);
expect(wrapper.contains(5)).to.equal(true);
expect(wrapper.contains(<div>{5}</div>)).to.equal(true);
});
it('should do something with arrays of nodes', () => {
const wrapper = shallow(
<div>
<span>Hello</span>
<div>Goodbye</div>
<span>More</span>
</div>
);
const fails = [
<span>wrong</span>,
<div>Goodbye</div>,
];
const passes1 = [
<span>Hello</span>,
<div>Goodbye</div>,
];
const passes2 = [
<div>Goodbye</div>,
<span>More</span>,
];
expect(wrapper.contains(fails)).to.equal(false);
expect(wrapper.contains(passes1)).to.equal(true);
expect(wrapper.contains(passes2)).to.equal(true);
});
it('should throw on invalid argument', () => {
const wrapper = shallow(<div></div>);
expect(() => wrapper.contains({})).to.throw();
expect(() => wrapper.contains(() => ({}))).to.throw();
});
describeIf(!REACT013, 'stateless function components', () => {
it('should match composite components', () => {
const Foo = () => (
<div />
);
const wrapper = shallow(
<div>
<Foo />
</div>
);
const b = <Foo />;
expect(wrapper.contains(b)).to.equal(true);
});
});
});
describe('.equals(node)', () => {
it('should allow matches on the root node', () => {
const a = <div className="foo" />;
const b = <div className="foo" />;
const c = <div className="bar" />;
expect(shallow(a).equals(b)).to.equal(true);
expect(shallow(a).equals(c)).to.equal(false);
});
it('should NOT allow matches on a nested node', () => {
const wrapper = shallow(
<div>
<div className="foo" />
</div>
);
const b = <div className="foo" />;
expect(wrapper.equals(b)).to.equal(false);
});
it('should match composite components', () => {
class Foo extends React.Component {
render() { return <div />; }
}
const wrapper = shallow(
<div>
<Foo />
</div>
);
const b = <div><Foo /></div>;
expect(wrapper.equals(b)).to.equal(true);
});
it('should not expand `node` content', () => {
class Bar extends React.Component {
render() { return <div />; }
}
class Foo extends React.Component {
render() { return <Bar />; }
}
expect(shallow(<Foo />).equals(<Bar />)).to.equal(true);
expect(shallow(<Foo />).equals(<Foo />)).to.equal(false);
});
describeIf(!REACT013, 'stateless components', () => {
it('should match composite stateless components', () => {
const Foo = () => (
<div />
);
const wrapper = shallow(
<div>
<Foo />
</div>
);
const b = <div><Foo /></div>;
expect(wrapper.equals(b)).to.equal(true);
});
it('should not expand `node` content', () => {
const Bar = () => (
<div />
);
const Foo = () => (
<Bar />
);
expect(shallow(<Foo />).equals(<Bar />)).to.equal(true);
expect(shallow(<Foo />).equals(<Foo />)).to.equal(false);
});
});
});
describe('.find(selector)', () => {
it('should be able to match the root DOM element', () => {
const wrapper = shallow(<div id="ttt" className="ttt">hello</div>);
expect(wrapper.find('#ttt')).to.have.length(1);
expect(wrapper.find('.ttt')).to.have.length(1);
});
it('should find an element based on a class name', () => {
const wrapper = shallow(
<div>
<input className="foo" />
</div>
);
expect(wrapper.find('.foo').type()).to.equal('input');
});
it('should find an element based on a tag name', () => {
const wrapper = shallow(
<div>
<input className="foo" />
<button className="bar">Button</button>
<textarea className="magic"></textarea>
<select className="reality"></select>
</div>
);
expect(wrapper.find('input').props().className).to.equal('foo');
expect(wrapper.find('button').props().className).to.equal('bar');
expect(wrapper.find('textarea').props().className).to.equal('magic');
expect(wrapper.find('select').props().className).to.equal('reality');
});
it('should find a component based on a constructor', () => {
class Foo extends React.Component {
render() { return <div />; }
}
const wrapper = shallow(
<div>
<Foo className="foo" />
</div>
);
expect(wrapper.find(Foo).type()).to.equal(Foo);
});
it('should find a component based on a display name', () => {
class Foo extends React.Component {
render() { return <div />; }
}
const wrapper = shallow(
<div>
<Foo className="foo" />
</div>
);
expect(wrapper.find('Foo').type()).to.equal(Foo);
});
it('should find multiple elements based on a class name', () => {
const wrapper = shallow(
<div>
<input className="foo" />
<button className="foo" />
</div>
);
expect(wrapper.find('.foo').length).to.equal(2);
});
it('should find multiple elements based on a tag name', () => {
const wrapper = shallow(
<div>
<input className="foo" />
<input />
<button />
</div>
);
expect(wrapper.find('input').length).to.equal(2);
expect(wrapper.find('button').length).to.equal(1);
});
it('should find component based on a react prop', () => {
const wrapper = shallow(
<div>
<span title="foo" />
</div>
);
expect(wrapper.find('[title="foo"]')).to.have.length(1);
expect(wrapper.find('[title]')).to.have.length(1);
});
it('should error sensibly if prop selector without quotes', () => {
const wrapper = shallow(
<div>
<input type="text" />
<input type="hidden" />
</div>
);
expect(() => wrapper.find('[type=text]')).to.throw();
});
it('should compound tag and prop selector', () => {
const wrapper = shallow(
<div>
<span preserveAspectRatio="xMaxYMax" />
</div>
);
expect(wrapper.find('span[preserveAspectRatio="xMaxYMax"]')).to.have.length(1);
expect(wrapper.find('span[preserveAspectRatio]')).to.have.length(1);
});
it('should support data prop selectors', () => {
const wrapper = shallow(
<div>
<span data-foo="bar" />
</div>
);
expect(wrapper.find('[data-foo="bar"]')).to.have.length(1);
expect(wrapper.find('[data-foo]')).to.have.length(1);
});
it('should find components with multiple matching react props', () => {
function noop() {}
const wrapper = shallow(
<div>
<span htmlFor="foo" onChange={noop} preserveAspectRatio="xMaxYMax" />
</div>
);
expect(wrapper.find('span[htmlFor="foo"][onChange]')).to.have.length(1);
expect(wrapper.find('span[htmlFor="foo"][preserveAspectRatio="xMaxYMax"]')).to.have.length(1);
expect(wrapper.find('[htmlFor][preserveAspectRatio]')).to.have.length(1);
});
it('should support boolean and numeric values for matching props', () => {
const wrapper = shallow(
<div>
<span value={1} />
<a value={false} />
</div>
);
expect(wrapper.find('span[value=1]')).to.have.length(1);
expect(wrapper.find('span[value=2]')).to.have.length(0);
expect(wrapper.find('a[value=false]')).to.have.length(1);
expect(wrapper.find('a[value=true]')).to.have.length(0);
});
it('should not find key or ref via property selector', () => {
const arrayOfComponents = [<div key="1" />, <div key="2" />];
const wrapper = shallow(
<div>
<div ref="foo" />
{arrayOfComponents}
</div>
);
expect(wrapper.find('div[ref="foo"]')).to.have.length(0);
expect(wrapper.find('div[key="1"]')).to.have.length(0);
expect(wrapper.find('[ref]')).to.have.length(0);
expect(wrapper.find('[key]')).to.have.length(0);
});
it('should find multiple elements based on a constructor', () => {
const wrapper = shallow(
<div>
<input className="foo" />
<input />
<button />
</div>
);
expect(wrapper.find('input').length).to.equal(2);
expect(wrapper.find('button').length).to.equal(1);
});
it('should support object property selectors', () => {
const wrapper = shallow(
<div>
<input data-test="ref" className="foo" type="text" />
<input data-test="ref" type="text" />
<button data-test="ref" prop={undefined} />
<span data-test="ref" prop={null} />
<div data-test="ref" prop={123} />
<input data-test="ref" prop={false} />
<a data-test="ref" prop />
</div>
);
expect(wrapper.find({ a: 1 })).to.have.length(0);
expect(wrapper.find({ 'data-test': 'ref' })).to.have.length(7);
expect(wrapper.find({ className: 'foo' })).to.have.length(1);
expect(wrapper.find({ prop: undefined })).to.have.length(1);
expect(wrapper.find({ prop: null })).to.have.length(1);
expect(wrapper.find({ prop: 123 })).to.have.length(1);
expect(wrapper.find({ prop: false })).to.have.length(1);
expect(wrapper.find({ prop: true })).to.have.length(1);
});
it('should support complex and nested object property selectors', () => {
const testFunction = () => ({});
const wrapper = shallow(
<div>
<span more={[{ id: 1 }]} data-test="ref" prop onChange={testFunction} />
<a more={[{ id: 1 }]} data-test="ref" />
<div more={{ item: { id: 1 } }} data-test="ref" />
<input style={{ height: 20 }} data-test="ref" />
</div>
);
expect(wrapper.find({ 'data-test': 'ref' })).to.have.length(4);
expect(wrapper.find({ more: { a: 1 } })).to.have.length(0);
expect(wrapper.find({ more: [{ id: 1 }] })).to.have.length(2);
expect(wrapper.find({ more: { item: { id: 1 } } })).to.have.length(1);
expect(wrapper.find({ style: { height: 20 } })).to.have.length(1);
expect(wrapper
.find({ more: [{ id: 1 }], 'data-test': 'ref', prop: true, onChange: testFunction })
).to.have.length(1);
});
it('should throw when given empty object, null, or an array', () => {
const wrapper = shallow(
<div>
<input className="foo" type="text" />
</div>
);
expect(() => wrapper.find({})).to.throw(Error);
expect(() => wrapper.find([])).to.throw(Error);
expect(() => wrapper.find(null)).to.throw(Error);
});
describeIf(!REACT013, 'stateless function components', () => {
it('should find a component based on a constructor', () => {
const Foo = () => (
<div />
);
const wrapper = shallow(
<div>
<Foo className="foo" />
</div>
);
expect(wrapper.find(Foo).type()).to.equal(Foo);
});
it('should find a component based on a display name', () => {
const Foo = () => (
<div />
);
const wrapper = shallow(
<div>
<Foo className="foo" />
</div>
);
expect(wrapper.find('Foo').type()).to.equal(Foo);
});
});
});
describe('.findWhere(predicate)', () => {
it('should return all elements for a truthy test', () => {
const wrapper = shallow(
<div>
<input className="foo" />
<input />
</div>
);
expect(wrapper.findWhere(() => true).length).to.equal(3);
});
it('should return no elements for a falsy test', () => {
const wrapper = shallow(
<div>
<input className="foo" />
<input />
</div>
);
expect(wrapper.findWhere(() => false).length).to.equal(0);
});
it('should call the predicate with the wrapped node as the first argument', () => {
const wrapper = shallow(
<div>
<div className="foo bar" />
<div className="foo baz" />
<div className="foo bux" />
</div>
);
const stub = sinon.stub();
stub.returns(true);
const spy = sinon.spy(stub);
wrapper.findWhere(spy);
expect(spy.callCount).to.equal(4);
expect(spy.args[0][0]).to.be.instanceOf(ShallowWrapper);
expect(spy.args[1][0]).to.be.instanceOf(ShallowWrapper);
expect(spy.args[2][0]).to.be.instanceOf(ShallowWrapper);
expect(spy.args[3][0]).to.be.instanceOf(ShallowWrapper);
expect(spy.args[1][0].hasClass('bar')).to.equal(true);
expect(spy.args[2][0].hasClass('baz')).to.equal(true);
expect(spy.args[3][0].hasClass('bux')).to.equal(true);
});
describeIf(!REACT013, 'stateless function components', () => {
it('finds nodes', () => {
const SFC = function SFC({ selector }) {
return (
<div>
<span data-foo={selector} />
<i data-foo={selector} />
</div>
);
};
const selector = 'blah';
const wrapper = shallow(<SFC selector={selector} />);
const foundSpan = wrapper.findWhere(n => (
n.type() === 'span' && n.props()['data-foo'] === selector
));
expect(foundSpan.type()).to.equal('span');
const foundNotSpan = wrapper.findWhere(n => (
n.type() !== 'span' && n.props()['data-foo'] === selector
));
expect(foundNotSpan.type()).to.equal('i');
});
it('finds nodes when conditionally rendered', () => {
const SFC = function SFC({ selector }) {
return (
<div>
<span data-foo={selector} />
{selector === 'baz' ? <i data-foo={selector} /> : null}
</div>
);
};
const selector = 'blah';
const wrapper = shallow(<SFC selector={selector} />);
const foundSpan = wrapper.findWhere(n => (
n.type() === 'span' && n.props()['data-foo'] === selector
));
expect(foundSpan.type()).to.equal('span');
const foundNotSpan = wrapper.findWhere(n => (
n.type() !== 'span' && n.props()['data-foo'] === selector
));
expect(foundNotSpan).to.have.length(0);
});
});
it('should not pass in null or false nodes', () => {
const wrapper = shallow(
<div>
<div className="foo bar" />
{null}
{false}
</div>
);
const stub = sinon.stub();
stub.returns(true);
const spy = sinon.spy(stub);
wrapper.findWhere(spy);
expect(spy.callCount).to.equal(2);
});
});
describe('.setProps(newProps)', () => {
it('should set props for a component multiple times', () => {
class Foo extends React.Component {
render() {
return (
<div className={this.props.id}>
{this.props.id}
</div>
);
}
}
const wrapper = shallow(<Foo id="foo" />);
expect(wrapper.find('.foo').length).to.equal(1);
wrapper.setProps({ id: 'bar', foo: 'bla' });
expect(wrapper.find('.bar').length).to.equal(1);
});
it('should call componentWillReceiveProps for new renders', () => {
const spy = sinon.spy();
class Foo extends React.Component {
constructor(props) {
super(props);
this.componentWillReceiveProps = spy;
}
render() {
return (
<div className={this.props.id}>
{this.props.id}
</div>
);
}
}
const nextProps = { id: 'bar', foo: 'bla' };
const wrapper = shallow(<Foo id="foo" />);
expect(spy.calledOnce).to.equal(false);
wrapper.setProps(nextProps);
expect(spy.calledOnce).to.equal(true);
expect(spy.calledWith(nextProps)).to.equal(true);
});
it('should merge newProps with oldProps', () => {
class Foo extends React.Component {
render() {
return (
<div {...this.props} />
);
}
}
const wrapper = shallow(<Foo a="a" b="b" />);
expect(wrapper.props().a).to.equal('a');
expect(wrapper.props().b).to.equal('b');
wrapper.setProps({ b: 'c', d: 'e' });
expect(wrapper.props().a).to.equal('a');
expect(wrapper.props().b).to.equal('c');
expect(wrapper.props().d).to.equal('e');
});
it('should pass in old context', () => {
class Foo extends React.Component {
render() {
return (
<div>{this.context.x}</div>
);
}
}
Foo.contextTypes = { x: React.PropTypes.string };
const context = { x: 'yolo' };
const wrapper = shallow(<Foo x={5} />, { context });
expect(wrapper.first('div').text()).to.equal('yolo');
wrapper.setProps({ x: 5 }); // Just force a re-render
expect(wrapper.first('div').text()).to.equal('yolo');
});
describeIf(!REACT013, 'stateless function components', () => {
it('should set props for a component multiple times', () => {
const Foo = (props) => (
<div className={props.id}>
{props.id}
</div>
);
const wrapper = shallow(<Foo id="foo" />);
expect(wrapper.find('.foo').length).to.equal(1);
wrapper.setProps({ id: 'bar', foo: 'bla' });
expect(wrapper.find('.bar').length).to.equal(1);
});
it('should merge newProps with oldProps', () => {
const Foo = (props) => (
<div {...props} />
);
const wrapper = shallow(<Foo a="a" b="b" />);
expect(wrapper.props().a).to.equal('a');
expect(wrapper.props().b).to.equal('b');
wrapper.setProps({ b: 'c', d: 'e' });
expect(wrapper.props().a).to.equal('a');
expect(wrapper.props().b).to.equal('c');
expect(wrapper.props().d).to.equal('e');
});
it('should pass in old context', () => {
const Foo = (props, context) => (
<div>{context.x}</div>
);
Foo.contextTypes = { x: React.PropTypes.string };
const context = { x: 'yolo' };
const wrapper = shallow(<Foo x={5} />, { context });
expect(wrapper.first('div').text()).to.equal('yolo');
wrapper.setProps({ x: 5 }); // Just force a re-render
expect(wrapper.first('div').text()).to.equal('yolo');
});
});
});
describe('.setContext(newContext)', () => {
const SimpleComponent = React.createClass({
contextTypes: {
name: React.PropTypes.string,
},
render() {
return <div>{this.context.name}</div>;
},
});
it('should set context for a component multiple times', () => {
const context = { name: 'foo' };
const wrapper = shallow(<SimpleComponent />, { context });
expect(wrapper.text()).to.equal('foo');
wrapper.setContext({ name: 'bar' });
expect(wrapper.text()).to.equal('bar');
wrapper.setContext({ name: 'baz' });
expect(wrapper.text()).to.equal('baz');
});
it('should throw if it is called when shallow didnt include context', () => {
const wrapper = shallow(<SimpleComponent />);
expect(() => wrapper.setContext({ name: 'bar' })).to.throw(Error);
});
describeIf(!REACT013, 'stateless function components', () => {
const SFC = (props, context) => (
<div>{context.name}</div>
);
SFC.contextTypes = { name: React.PropTypes.string };
it('should set context for a component multiple times', () => {
const context = { name: 'foo' };
const wrapper = shallow(<SFC />, { context });
expect(wrapper.text()).to.equal('foo');
wrapper.setContext({ name: 'bar' });
expect(wrapper.text()).to.equal('bar');
wrapper.setContext({ name: 'baz' });
expect(wrapper.text()).to.equal('baz');
});
it('should throw if it is called when shallow didnt include context', () => {
const wrapper = shallow(<SFC />);
expect(() => wrapper.setContext({ name: 'bar' })).to.throw(Error);
});
});
});
describe('.simulate(eventName, data)', () => {
it('should simulate events', () => {
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
this.incrementCount = this.incrementCount.bind(this);
}
incrementCount() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<a
className={`clicks-${this.state.count}`}
onClick={this.incrementCount}
>foo</a>
);
}
}
const wrapper = shallow(<Foo />);
expect(wrapper.find('.clicks-0').length).to.equal(1);
wrapper.simulate('click');
expect(wrapper.find('.clicks-1').length).to.equal(1);
});
it('should pass in event data', () => {
const spy = sinon.spy();
class Foo extends React.Component {
render() {
return (
<a onClick={spy}>foo</a>
);
}
}
const wrapper = shallow(<Foo />);
const a = {};
const b = {};
wrapper.simulate('click', a, b);
expect(spy.args[0][0]).to.equal(a);
expect(spy.args[0][1]).to.equal(b);
});
describeIf(!REACT013, 'stateless function components', () => {
it('should simulate events', () => {
const spy = sinon.spy();
const Foo = (props) => (
<a onClick={props.onClick}>foo</a>
);
const wrapper = shallow(<Foo onClick={spy} />);
expect(spy.calledOnce).to.equal(false);
wrapper.find('a').simulate('click');
expect(spy.calledOnce).to.equal(true);
});
it('should pass in event data', () => {
const spy = sinon.spy();
const Foo = () => (
<a onClick={spy}>foo</a>
);
const wrapper = shallow(<Foo />);
const a = {};
const b = {};
wrapper.simulate('click', a, b);
expect(spy.args[0][0]).to.equal(a);
expect(spy.args[0][1]).to.equal(b);
});
});
describe('Normalizing JS event names', () => {
it('should convert lowercase events to React camelcase', () => {
const spy = sinon.spy();
const clickSpy = sinon.spy();
class Foo extends React.Component {
render() {
return (
<a onClick={clickSpy} onDoubleClick={spy}>foo</a>
);
}
}
const wrapper = shallow(<Foo />);
wrapper.simulate('dblclick');
expect(spy.calledOnce).to.equal(true);
wrapper.simulate('click');
expect(clickSpy.calledOnce).to.equal(true);
});
describeIf(!REACT013, 'normalizing mouseenter', () => {
it('should convert lowercase events to React camelcase', () => {
const spy = sinon.spy();
class Foo extends React.Component {
render() {
return (
<a onMouseEnter={spy}>foo</a>
);
}
}
const wrapper = shallow(<Foo />);
wrapper.simulate('mouseenter');
expect(spy.calledOnce).to.equal(true);
});
it('should convert lowercase events to React camelcase in stateless components', () => {
const spy = sinon.spy();
const Foo = () => (
<a onMouseEnter={spy}>foo</a>
);
const wrapper = shallow(<Foo />);
wrapper.simulate('mouseenter');
expect(spy.calledOnce).to.equal(true);
});
});
});
});
describe('.setState(newState)', () => {
it('should set the state of the root node', () => {
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = { id: 'foo' };
}
render() {
return (
<div className={this.state.id} />
);
}
}
const wrapper = shallow(<Foo />);
expect(wrapper.find('.foo').length).to.equal(1);
wrapper.setState({ id: 'bar' });
expect(wrapper.find('.bar').length).to.equal(1);
});
describeIf(!REACT013, 'stateless function components', () => {
it('should throw when trying to access state', () => {
const Foo = () => (
<div>abc</div>
);
const wrapper = shallow(<Foo />);
expect(() => wrapper.state()).to.throw();
});
it('should throw when trying to set state', () => {
const Foo = () => (
<div>abc</div>
);
const wrapper = shallow(<Foo />);
expect(() => wrapper.setState({ a: 1 })).to.throw();
});
});
});
describe('.is(selector)', () => {
it('should return true when selector matches current element', () => {
const wrapper = shallow(<div className="foo bar baz" />);
expect(wrapper.is('.foo')).to.equal(true);
});
it('should allow for compound selectors', () => {
const wrapper = shallow(<div className="foo bar baz" />);
expect(wrapper.is('.foo.bar')).to.equal(true);
});
it('should ignore insignificant whitespace', () => {
const className = `foo
`;
const wrapper = shallow(<div className={className} />);
expect(wrapper.is('.foo')).to.equal(true);
});
it('should handle all significant whitespace', () => {
const className = `foo
bar
baz`;
const wrapper = shallow(<div className={className} />);
expect(wrapper.is('.foo.bar.baz')).to.equal(true);
});
it('should return false when selector does not match', () => {
const wrapper = shallow(<div className="bar baz" />);
expect(wrapper.is('.foo')).to.equal(false);
});
});
describe('.not(selector)', () => {
it('filters to things not matching a selector', () => {
const wrapper = shallow(
<div>
<div className="foo bar baz" />
<div className="foo" />
<div className="bar baz" />
<div className="baz" />
<div className="foo bar" />
</div>
);
expect(wrapper.find('.foo').not('.bar').length).to.equal(1);
expect(wrapper.find('.baz').not('.foo').length).to.equal(2);
expect(wrapper.find('.foo').not('div').length).to.equal(0);
});
});
describe('.filter(selector)', () => {
it('should return a new wrapper of just the nodes that matched the selector', () => {
const wrapper = shallow(
<div>
<div className="foo bar baz" />
<div className="foo" />
<div className="bar baz">
<div className="foo bar baz" />
<div className="foo" />
</div>
<div className="baz" />
<div className="foo bar" />
</div>
);
expect(wrapper.find('.foo').filter('.bar').length).to.equal(3);
expect(wrapper.find('.bar').filter('.foo').length).to.equal(3);
expect(wrapper.find('.bar').filter('.bax').length).to.equal(0);
expect(wrapper.find('.foo').filter('.baz.bar').length).to.equal(2);
});
it('should only look in the current wrappers nodes, not their children', () => {
const wrapper = shallow(
<div>
<div className="foo">
<div className="bar" />
</div>
<div className="foo bar" />
</div>
);
expect(wrapper.find('.foo').filter('.bar').length).to.equal(1);
});
});
describe('.filterWhere(predicate)', () => {
it('should filter only the nodes of the wrapper', () => {
const wrapper = shallow(
<div>
<div className="foo bar" />
<div className="foo baz" />
<div className="foo bux" />
</div>
);
const stub = sinon.stub();
stub.onCall(0).returns(false);
stub.onCall(1).returns(true);
stub.onCall(2).returns(false);
const baz = wrapper.find('.foo').filterWhere(stub);
expect(baz.length).to.equal(1);
expect(baz.hasClass('baz')).to.equal(true);
});
it('should call the predicate with the wrapped node as the first argument', () => {
const wrapper = shallow(
<div>
<div className="foo bar" />
<div className="foo baz" />
<div className="foo bux" />
</div>
);
const stub = sinon.stub();
stub.returns(true);
const spy = sinon.spy(stub);
wrapper.find('.foo').filterWhere(spy);
expect(spy.callCount).to.equal(3);
expect(spy.args[0][0]).to.be.instanceOf(ShallowWrapper);
expect(spy.args[1][0]).to.be.instanceOf(ShallowWrapper);
expect(spy.args[2][0]).to.be.instanceOf(ShallowWrapper);
expect(spy.args[0][0].hasClass('bar')).to.equal(true);
expect(spy.args[1][0].hasClass('baz')).to.equal(true);
expect(spy.args[2][0].hasClass('bux')).to.equal(true);
});
});
describe('.text()', () => {
const matchesRender = function matchesRender(node) {
const actual = shallow(node).text();
const expected = render(node).text();
expect(expected).to.equal(actual);
};
it('should handle simple text nodes', () => {
const wrapper = shallow(
<div>some text</div>
);
expect(wrapper.text()).to.equal('some text');
});
it('should handle nodes with mapped children', () => {
class Foo extends React.Component {
render() {
return (
<div>
{this.props.items.map(x => x)}
</div>
);
}
}
matchesRender(<Foo items={['abc', 'def', 'hij']} />);
matchesRender(
<Foo
items={[
<i key={1}>abc</i>,
<i key={2}>def</i>,
<i key={3}>hij</i>,
]}
/>
);
});
it('should render composite components dumbly', () => {
class Foo extends React.Component {
render() { return <div />; }
}
const wrapper = shallow(
<div>
<Foo />
<div>test</div>
</div>
);
expect(wrapper.text()).to.equal('<Foo />test');
});
it('should handle html entities', () => {
matchesRender(<div>></div>);
});
describeIf(!REACT013, 'stateless function components', () => {
it('should handle nodes with mapped children', () => {
const Foo = (props) => (
<div>
{props.items.map(x => x)}
</div>
);
matchesRender(<Foo items={['abc', 'def', 'hij']} />);
matchesRender(
<Foo
items={[
<i key={1}>abc</i>,
<i key={2}>def</i>,
<i key={3}>hij</i>,
]}
/>
);
});
it('should render composite components dumbly', () => {
const Foo = () => (
<div />
);
const wrapper = shallow(
<div>
<Foo />
<div>test</div>
</div>
);
expect(wrapper.text()).to.equal('<Foo />test');
});
});
});
describe('.props()', () => {
it('should return the props object', () => {
const fn = () => ({});
const wrapper = shallow(
<div id="fooId" className="bax" onClick={fn} >
<div className="baz" />
<div className="foo" />
</div>
);
expect(wrapper.props().className).to.equal('bax');
expect(wrapper.props().onClick).to.equal(fn);
expect(wrapper.props().id).to.equal('fooId');
});
it('should be allowed to be used on an inner node', () => {
const fn = () => ({});
const wrapper = shallow(
<div className="bax">
<div className="baz" onClick={fn} />
<div className="foo" id="fooId" />
</div>
);
expect(wrapper.find('.baz').props().onClick).to.equal(fn);
expect(wrapper.find('.foo').props().id).to.equal('fooId');
});
});
describe('.state(name)', () => {
it('should return the state object', () => {
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = { foo: 'foo' };
}
render() { return <div />; }
}
const wrapper = shallow(<Foo />);
expect(wrapper.state()).to.eql({ foo: 'foo' });
});
it('should return the current state after state transitions', () => {
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = { foo: 'foo' };
}
render() { return <div />; }
}
const wrapper = shallow(<Foo />);
wrapper.setState({ foo: 'bar' });
expect(wrapper.state()).to.eql({ foo: 'bar' });
});
it('should allow a state property name be passed in as an argument', () => {
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = { foo: 'foo' };
}
render() { return <div />; }
}
const wrapper = shallow(<Foo />);
expect(wrapper.state('foo')).to.equal('foo');
});
});
describe('.children([selector])', () => {
it('should return empty wrapper for node with no children', () => {
const wrapper = shallow(<div />);
expect(wrapper.children().length).to.equal(0);
});
it('should skip the falsy children', () => {
const wrapper = shallow(
<div>
<div>
{false}
{[false, false]}
<p>foo</p>
</div>
<div>
{undefined}
{[undefined, undefined]}
<p>bar</p>
</div>
<div>
{null}
{[null, null]}
<p>baz</p>
</div>
</div>
);
expect(wrapper.childAt(0).children().length).to.equal(1);
expect(wrapper.childAt(1).children().length).to.equal(1);
expect(wrapper.childAt(2).children().length).to.equal(1);
});
it('should return the children nodes of the root', () => {
const wrapper = shallow(
<div>
<div className="foo" />
<div className="bar" />
<div className="baz" />
</div>
);
expect(wrapper.children().length).to.equal(3);
expect(wrapper.children().at(0).hasClass('foo')).to.equal(true);
expect(wrapper.children().at(1).hasClass('bar')).to.equal(true);
expect(wrapper.children().at(2).hasClass('baz')).to.equal(true);
});
it('should not return any of the children of children', () => {
const wrapper = shallow(
<div>
<div className="foo">
<div className="bar" />
</div>
<div className="baz" />
</div>
);
expect(wrapper.children().length).to.equal(2);
expect(wrapper.children().at(0).hasClass('foo')).to.equal(true);
expect(wrapper.children().at(1).hasClass('baz')).to.equal(true);
});
it('should handle mixed children with and without arrays', () => {
class Foo extends React.Component {
render() {
return (
<div>
<span className="foo"></span>
{this.props.items.map(x => x)}
</div>
);
}
}
const wrapper = shallow(
<Foo
items={[
<i key={1} className="bar">abc</i>,
<i key={2} className="baz">def</i>,
]}
/>
);
expect(wrapper.children().length).to.equal(3);
expect(wrapper.children().at(0).hasClass('foo')).to.equal(true);
expect(wrapper.children().at(1).hasClass('bar')).to.equal(true);
expect(wrapper.children().at(2).hasClass('baz')).to.equal(true);
});
it('should optionally allow a selector to filter by', () => {
const wrapper = shallow(
<div>
<div className="foo" />
<div className="bar bip" />
<div className="baz bip" />
</div>
);
const children = wrapper.children('.bip');
expect(children.length).to.equal(2);
expect(children.at(0).hasClass('bar')).to.equal(true);
expect(children.at(1).hasClass('baz')).to.equal(true);
});
describeIf(!REACT013, 'stateless function components', () => {
it('should handle mixed children with and without arrays', () => {
const Foo = (props) => (
<div>
<span className="foo"></span>
{props.items.map(x => x)}
</div>
);
const wrapper = shallow(
<Foo
items={[
<i key={1} className="bar">abc</i>,
<i key={2} className="baz">def</i>,
]}
/>
);
expect(wrapper.children().length).to.equal(3);
expect(wrapper.children().at(0).hasClass('foo')).to.equal(true);
expect(wrapper.children().at(1).hasClass('bar')).to.equal(true);
expect(wrapper.children().at(2).hasClass('baz')).to.equal(true);
});
});
});
describe('.childAt(index)', () => {
it('should get a wrapped node at the specified index', () => {
const wrapper = shallow(
<div>
<div className="bar" />
<div className="baz" />
</div>
);
expect(wrapper.childAt(0).hasClass('bar')).to.equal(true);
expect(wrapper.childAt(1).hasClass('baz')).to.equal(true);
});
});
describe('.parents([selector])', () => {
it('should return an array of current nodes ancestors', () => {
const wrapper = shallow(
<div className="bax">
<div className="foo">
<div className="bar">
<div className="baz" />
</div>
</div>
</div>
);
const parents = wrapper.find('.baz').parents();
expect(parents.length).to.equal(3);
expect(parents.at(0).hasClass('bar')).to.equal(true);
expect(parents.at(1).hasClass('foo')).to.equal(true);
expect(parents.at(2).hasClass('bax')).to.equal(true);
});
it('should work for non-leaf nodes as well', () => {
const wrapper = shallow(
<div className="bax">
<div className="foo">
<div className="bar">
<div className="baz" />
</div>
</div>
</div>
);
const parents = wrapper.find('.bar').parents();
expect(parents.length).to.equal(2);
expect(parents.at(0).hasClass('foo')).to.equal(true);
expect(parents.at(1).hasClass('bax')).to.equal(true);
});
it('should optionally allow a selector', () => {
const wrapper = shallow(
<div className="bax foo">
<div className="foo">
<div className="bar">
<div className="baz" />
</div>
</div>
</div>
);
const parents = wrapper.find('.baz').parents('.foo');
expect(parents.length).to.equal(2);
expect(parents.at(0).hasClass('foo')).to.equal(true);
expect(parents.at(1).hasClass('bax')).to.equal(true);
});
});
describe('.parent()', () => {
it('should return only the immediate parent of the node', () => {
const wrapper = shallow(
<div className="bax">
<div className="foo">
<div className="bar">
<div className="baz" />
</div>
</div>
</div>
);
expect(wrapper.find('.baz').parent().hasClass('bar')).to.equal(true);
});
it('should work when the sibling node has children', () => {
const wrapper = shallow(
<div className="bax">
<div className="foo">
<div className="bar">
<div className="baz" />
<div>
<div />
</div>
</div>
</div>
</div>
);
expect(wrapper.find('.baz').parent().hasClass('bar')).to.equal(true);
});
it('should work for multiple nodes', () => {
const wrapper = shallow(
<div>
<div className="foo">
<div className="baz" />
</div>
<div className="bar">
<div className="baz" />
</div>
<div className="bax">
<div className="baz" />
</div>
</div>
);
const parents = wrapper.find('.baz').parent();
expect(parents).to.have.length(3);
expect(parents.at(0).hasClass('foo')).to.equal(true);
expect(parents.at(1).hasClass('bar')).to.equal(true);
expect(parents.at(2).hasClass('bax')).to.equal(true);
});
});
describe('.closest(selector)', () => {
it('should return the closest ancestor for a given selector', () => {
const wrapper = shallow(
<div className="foo">
<div className="foo baz">
<div className="bax">
<div className="bar" />
</div>
</div>
</div>
);
const closestFoo = wrapper.find('.bar').closest('.foo');
expect(closestFoo.hasClass('baz')).to.equal(true);
expect(closestFoo.length).to.equal(1);
});
it('should only ever return a wrapper of a single node', () => {
const wrapper = shallow(
<div className="bax">
<div className="foo">
<div className="bar">
<div className="baz" />
</div>
</div>
</div>
);
expect(wrapper.find('.baz').parent().hasClass('bar')).to.equal(true);
});
it('should return itself if matching', () => {
const wrapper = shallow(
<div className="bax">
<div className="foo">
<div className="baz">
<div className="bux baz" />
</div>
</div>
</div>
);
expect(wrapper.find('.bux').closest('.baz').hasClass('bux')).to.equal(true);
});
});
describe('.hasClass(className)', () => {
it('should return whether or not node has a certain class', () => {
const wrapper = shallow(
<div className="foo bar baz some-long-string FoOo" />
);
expect(wrapper.hasClass('foo')).to.equal(true);
expect(wrapper.hasClass('bar')).to.equal(true);
expect(wrapper.hasClass('baz')).to.equal(true);
expect(wrapper.hasClass('some-long-string')).to.equal(true);
expect(wrapper.hasClass('FoOo')).to.equal(true);
expect(wrapper.hasClass('doesnt-exist')).to.equal(false);
});
});
describe('.forEach(fn)', () => {
it('should call a function for each node in the wrapper', () => {
const wrapper = shallow(
<div>
<div className="foo bax" />
<div className="foo bar" />
<div className="foo baz" />
</div>
);
const spy = sinon.spy();
wrapper.find('.foo').forEach(spy);
expect(spy.callCount).to.equal(3);
expect(spy.args[0][0]).to.be.instanceOf(ShallowWrapper);
expect(spy.args[0][0].hasClass('bax')).to.equal(true);
expect(spy.args[1][0]).to.be.instanceOf(ShallowWrapper);
expect(spy.args[1][0].hasClass('bar')).to.equal(true);
expect(spy.args[2][0]).to.be.instanceOf(ShallowWrapper);
expect(spy.args[2][0].hasClass('baz')).to.equal(true);
});
});
describe('.map(fn)', () => {
it('should call a function with a wrapper for each node in the wrapper', () => {
const wrapper = shallow(
<div>
<div className="foo bax" />
<div className="foo bar" />
<div className="foo baz" />
</div>
);
const spy = sinon.spy();
wrapper.find('.foo').map(spy);
expect(spy.callCount).to.equal(3);
expect(spy.args[0][0]).to.be.instanceOf(ShallowWrapper);