Skip to content

Commit

Permalink
Merge pull request #62 from airbnb/lmr--context-support
Browse files Browse the repository at this point in the history
Added context support
  • Loading branch information
lelandrichardson committed Dec 10, 2015
2 parents bdf85cc + 9acb9d1 commit 9d5d3de
Show file tree
Hide file tree
Showing 16 changed files with 401 additions and 48 deletions.
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
* [simulate(event[, data])](/docs/api/ShallowWrapper/simulate.md)
* [setState(nextState)](/docs/api/ShallowWrapper/setState.md)
* [setProps(nextProps)](/docs/api/ShallowWrapper/setProps.md)
* [setContext(context)](/docs/api/ShallowWrapper/setContext.md)
* [instance()](/docs/api/ShallowWrapper/instance.md)
* [update()](/docs/api/ShallowWrapper/update.md)
* [debug()](/docs/api/ShallowWrapper/debug.md)
Expand Down Expand Up @@ -69,6 +70,7 @@
* [simulate(event[, data])](/docs/api/ReactWrapper/simulate.md)
* [setState(nextState)](/docs/api/ReactWrapper/setState.md)
* [setProps(nextProps)](/docs/api/ReactWrapper/setProps.md)
* [setContext(context)](/docs/api/ReactWrapper/setContext.md)
* [instance()](/docs/api/ReactWrapper/instance.md)
* [update()](/docs/api/ReactWrapper/update.md)
* [type()](/docs/api/ReactWrapper/type.md)
Expand Down
55 changes: 55 additions & 0 deletions docs/api/ReactWrapper/setContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# `.setContext(context) => Self`

A method that sets the context of the root component, and re-renders. Useful for when you are
wanting to test how the component behaves over time with changing contexts.

NOTE: can only be called on a wrapper instance that is also the root instance.


#### Arguments

1. `context` (`Object`): An object containing new props to merge in with the current state



#### Returns

`ReactWrapper`: Returns itself.



#### Example

```jsx
const SimpleComponent = React.createClass({
contextTypes: {
name: React.PropTypes.string,
},
render() {
return <div>{this.context.name}</div>;
},
});
```
```jsx
const context = { name: 'foo' };
const wrapper = mount(<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');
```

#### Common Gotchas

- `.setContext()` can only be used on a wrapper that was initially created with a call to `mount()`
that includes a `context` specified in the options argument.
- The root component you are rendering must have a `contextTypes` static property.


#### Related Methods

- [`.setState(state) => Self`](setState.md)
- [`.setProps(props) => Self`](setProps.md)


1 change: 1 addition & 0 deletions docs/api/ReactWrapper/setProps.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@ expect(spy.calledOnce).to.be.true;
#### Related Methods

- [`.setState(state) => Self`](setState.md)
- [`.setContext(context) => Self`](setContext.md)


1 change: 1 addition & 0 deletions docs/api/ReactWrapper/setState.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ expect(wrapper.find('.bar')).to.have.length(1);
#### Related Methods

- [`.setProps(props) => Self`](setProps.md)
- [`.setContext(context) => Self`](setContext.md)


55 changes: 55 additions & 0 deletions docs/api/ShallowWrapper/setContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# `.setContext(context) => Self`

A method that sets the context of the root component, and re-renders. Useful for when you are
wanting to test how the component behaves over time with changing contexts.

NOTE: can only be called on a wrapper instance that is also the root instance.


#### Arguments

1. `context` (`Object`): An object containing new props to merge in with the current state



#### Returns

`ShallowWrapper`: Returns itself.



#### Example

```jsx
const SimpleComponent = React.createClass({
contextTypes: {
name: React.PropTypes.string,
},
render() {
return <div>{this.context.name}</div>;
},
});
```
```jsx
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');
```

#### Common Gotchas

- `.setContext()` can only be used on a wrapper that was initially created with a call to `shallow()`
that includes a `context` specified in the options argument.
- The root component you are rendering must have a `contextTypes` static property.


#### Related Methods

- [`.setState(state) => Self`](setState.md)
- [`.setProps(props) => Self`](setProps.md)


1 change: 1 addition & 0 deletions docs/api/ShallowWrapper/setProps.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@ expect(spy.calledOnce).to.be.true;
#### Related Methods

- [`.setState(state) => Self`](setState.md)
- [`.setContext(context) => Self`](setContext.md)


1 change: 1 addition & 0 deletions docs/api/ShallowWrapper/setState.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ expect(wrapper.find('.bar')).to.have.length(1);
#### Related Methods

- [`.setProps(props) => Self`](setProps.md)
- [`.setContext(context) => Self`](setContext.md)


15 changes: 15 additions & 0 deletions docs/api/mount.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ describe('<Foo />', () => {
});
```

## `mount(node[, options]) => ReactWrapper`

#### Arguments

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

#### Returns

`ReactWrapper`: The wrapper instance around the rendered output.


## ReactWrapper API

Expand Down Expand Up @@ -109,6 +121,9 @@ Manually sets state of the root component.
#### [`.setProps(nextProps) => ReactWrapper`](ReactWrapper/setProps.md)
Manually sets props of the root component.

#### [`.setContext(context) => ReactWrapper`](ReactWrapper/setContext.md)
Manually sets context of the root component.

#### [`.instance() => ReactComponent`](ReactWrapper/instance.md)
Returns the instance of the root component.

Expand Down
15 changes: 15 additions & 0 deletions docs/api/shallow.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ describe('<MyComponent />', () => {

```

## `shallow(node[, options]) => ReactWrapper`

#### Arguments

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

#### Returns

`ShallowWrapper`: The wrapper instance around the rendered output.


## ShallowWrapper API

Expand Down Expand Up @@ -121,6 +133,9 @@ Manually sets state of the root component.
#### [`.setProps(nextProps) => ShallowWrapper`](ShallowWrapper/setProps.md)
Manually sets props of the root component.

#### [`.setContext(context) => ShallowWrapper`](ShallowWrapper/setContext.md)
Manually sets context of the root component.

#### [`.instance() => ReactComponent`](ShallowWrapper/instance.md)
Returns the instance of the root component.

Expand Down
32 changes: 29 additions & 3 deletions src/ReactWrapper.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { flatten, unique, compact } from 'underscore';
import ReactWrapperComponent from './ReactWrapperComponent';
import createWrapperComponent from './ReactWrapperComponent';
import {
instHasClassName,
childrenOfInst,
Expand Down Expand Up @@ -45,7 +45,7 @@ function filterWhereUnwrapped(wrapper, predicate) {
*/
export default class ReactWrapper {

constructor(nodes, root) {
constructor(nodes, root, options = {}) {
if (!global.window && !global.document) {
throw new Error(
`It looks like you called \`mount()\` without a jsdom document being loaded. ` +
Expand All @@ -54,10 +54,12 @@ export default class ReactWrapper {
}

if (!root) {
const ReactWrapperComponent = createWrapperComponent(nodes, options);
this.component = renderIntoDocument(
<ReactWrapperComponent
Component={nodes.type}
props={nodes.props}
context={options.context}
/>
);
this.root = this;
Expand All @@ -76,6 +78,7 @@ export default class ReactWrapper {
}
this.length = this.nodes.length;
}
this.options = options;
}

/**
Expand Down Expand Up @@ -147,7 +150,7 @@ export default class ReactWrapper {
if (this.root !== this) {
throw new Error('ReactWrapper::setProps() can only be called on the root');
}
this.component.setProps(props);
this.component.setChildProps(props);
return this;
}

Expand All @@ -171,6 +174,29 @@ export default class ReactWrapper {
return this;
}

/**
* A method that sets the context of the root component, and re-renders. Useful for when you are
* wanting to test how the component behaves over time with changing contexts.
*
* NOTE: can only be called on a wrapper instance that is also the root instance.
*
* @param {Object} context object
* @returns {ReactWrapper}
*/
setContext(context) {
if (this.root !== this) {
throw new Error('ReactWrapper::setContext() can only be called on the root');
}
if (!this.options.context) {
throw new Error(
'ShallowWrapper::setContext() can only be called on a wrapper that was originally passed ' +
'a context option'
);
}
this.component.setChildContext(context);
return this;
}

/**
* Whether or not a given react element exists in the mount render tree.
*
Expand Down
Loading

0 comments on commit 9d5d3de

Please sign in to comment.