Skip to content

Commit

Permalink
[New] shallow: add .dive()
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed Sep 21, 2016
1 parent f8fb23c commit c2414ca
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 2 deletions.
52 changes: 52 additions & 0 deletions docs/api/ShallowWrapper/dive.md
@@ -0,0 +1,52 @@
# `.dive([options]) => ShallowWrapper`

Shallow render the one non-DOM child of the current wrapper, and return a wrapper around the result.

NOTE: can only be called on wrapper of a single non-DOM component element node.


#### Arguments

1. `options` (`Object` [optional]):
- `options.context`: (`Object` [optional]): Context to be passed into the component



#### Returns

`ShallowWrapper`: A new wrapper that wraps the current node after it's been shallow rendered.



#### Examples

```jsx
class Bar extends React.Component {
render() {
return (
<div>
<div className="in-bar" />
</div>
);
}
}
```

```jsx
class Foo extends React.Component {
render() {
return (
<div>
<Bar />
</div>
);
}
}
```

```jsx
const wrapper = shallow(<Foo />);
expect(wrapper.find('.in-bar')).to.have.length(0);
expect(wrapper.find(Bar)).to.have.length(1);
expect(wrapper.dive().find('.in-bar')).to.have.length(1);
```
3 changes: 3 additions & 0 deletions docs/api/shallow.md
Expand Up @@ -207,3 +207,6 @@ Returns whether or not all of the nodes in the wrapper match the provided select

#### [`.everyWhere(predicate) => Boolean`](ShallowWrapper/everyWhere.md)
Returns whether or not all of the nodes in the wrapper pass the provided predicate function.

#### [`.dive([options]) => ShallowWrapper`](ShallowWrapper/dive.md)
Shallow render the one non-DOM child of the current wrapper, and return a wrapper around the result.
24 changes: 23 additions & 1 deletion src/ShallowWrapper.js
Expand Up @@ -15,6 +15,7 @@ import {
isReactElementAlike,
displayNameOfNode,
isFunctionalComponent,
isCustomComponentElement,
} from './Utils';
import {
debugNodes,
Expand All @@ -31,6 +32,7 @@ import {
createShallowRenderer,
renderToStaticMarkup,
batchedUpdates,
isDOMComponentElement,
} from './react-compat';

/**
Expand Down Expand Up @@ -698,7 +700,7 @@ export default class ShallowWrapper {

/**
* Returns the type of the current node of this wrapper. If it's a composite component, this will
* be the component constructor. If it's native DOM node, it will be a string.
* be the component constructor. If it's a native DOM node, it will be a string.
*
* @returns {String|Function}
*/
Expand Down Expand Up @@ -959,4 +961,24 @@ export default class ShallowWrapper {
intercepter(this);
return this;
}

/**
* Primarily useful for HOCs (higher-order components), this method may only be
* run on a single, non-DOM node, and will return the node, shallow-rendered.
*
* @param options object
* @returns {ShallowWrapper}
*/
dive(options) {
const name = 'dive';
return this.single(name, (n) => {
if (isDOMComponentElement(n)) {
throw new TypeError(`ShallowWrapper::${name}() can not be called on DOM components`);
}
if (!isCustomComponentElement(n)) {
throw new TypeError(`ShallowWrapper::${name}() can only be called on components`);
}
return new ShallowWrapper(n, null, options);
});
}
}
70 changes: 69 additions & 1 deletion test/ShallowWrapper-spec.jsx
Expand Up @@ -69,7 +69,7 @@ describe('shallow', () => {
);

const context = { name: 'foo' };
expect(() => shallow(<SimpleComponent />, { context })).not.to.throw(Error);
expect(() => shallow(<SimpleComponent />, { context })).not.to.throw();
});

it('is instrospectable through context API', () => {
Expand Down Expand Up @@ -3558,4 +3558,72 @@ describe('shallow', () => {
});
});

describe('.dive()', () => {
class RendersDOM extends React.Component {
render() {
return <div><i /></div>;
}
}
class RendersNull extends React.Component {
render() {
return null;
}
}
class RendersMultiple extends React.Component {
render() {
return (
<div>
<RendersNull />
<RendersDOM />
</div>
);
}
}
class WrapsRendersDOM extends React.Component {
render() {
return <RendersDOM />;
}
}
class DoubleWrapsRendersDOM extends React.Component {
render() {
return <WrapsRendersDOM />;
}
}

it('throws on a DOM node', () => {
const wrapper = shallow(<RendersDOM />);
expect(wrapper.is('div')).to.equal(true);

expect(() => { wrapper.dive(); }).to.throw(
TypeError,
'ShallowWrapper::dive() can not be called on DOM components'
);
});

it('throws on a non-component', () => {
const wrapper = shallow(<RendersNull />);
expect(wrapper.type()).to.equal(null);

expect(() => { wrapper.dive(); }).to.throw(
TypeError,
'ShallowWrapper::dive() can only be called on components'
);
});

it('throws on multiple children found', () => {
const wrapper = shallow(<RendersMultiple />).find('div').children();
expect(() => { wrapper.dive(); }).to.throw(
Error,
'Method “dive” is only meant to be run on a single node. 2 found instead.'
);
});

it('dives + shallow-renders when there is one component child', () => {
const wrapper = shallow(<DoubleWrapsRendersDOM />);
expect(wrapper.is(WrapsRendersDOM)).to.equal(true);

const underwater = wrapper.dive();
expect(underwater.is(RendersDOM)).to.equal(true);
});
});
});

0 comments on commit c2414ca

Please sign in to comment.