Skip to content

Commit

Permalink
add invoke() api to shallow and mount
Browse files Browse the repository at this point in the history
  • Loading branch information
koba04 committed Mar 7, 2019
1 parent a00ed0b commit 02c2b1b
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 1 deletion.
2 changes: 2 additions & 0 deletions SUMMARY.md
Expand Up @@ -48,6 +48,7 @@
* [hostNodes()](/docs/api/ShallowWrapper/hostNodes.md)
* [html()](/docs/api/ShallowWrapper/html.md)
* [instance()](/docs/api/ShallowWrapper/instance.md)
* [invoke(propName[, ...args])](/docs/api/ShallowWrapper/invoke.md)
* [is(selector)](/docs/api/ShallowWrapper/is.md)
* [isEmpty()](/docs/api/ShallowWrapper/isEmpty.md)
* [isEmptyRender()](/docs/api/ShallowWrapper/isEmptyRender.md)
Expand Down Expand Up @@ -108,6 +109,7 @@
* [hostNodes()](/docs/api/ReactWrapper/hostNodes.md)
* [html()](/docs/api/ReactWrapper/html.md)
* [instance()](/docs/api/ReactWrapper/instance.md)
* [invoke(propName[, ...args])](/docs/api/ReactWrapper/invoke.md)
* [is(selector)](/docs/api/ReactWrapper/is.md)
* [isEmpty()](/docs/api/ReactWrapper/isEmpty.md)
* [isEmptyRender()](/docs/api/ReactWrapper/isEmptyRender.md)
Expand Down
38 changes: 38 additions & 0 deletions docs/api/ReactWrapper/invoke.md
@@ -0,0 +1,38 @@
# `.invoke(propName[, ...args]) => Any`

Invokes a function prop.

#### Arguments

1. `propName` (`String`): The function prop to be invoked
2. `...args` (`Any` [optional]): Arguments that will be passed to the prop function

#### Returns

`Any`: Returns the value from the prop function

#### Example

```jsx
class Foo extends React.Component {
loadData() {
return fetch();
}
render() {
return (
<div>
<button
type="button"
onClick={() => this.loadData()}
>
Load more
</button>
</div>
);
}
}
const wrapper = mount(<Foo />);
wrapper.find('a').invoke('onClick').then(() => {
// expect()
});
```
38 changes: 38 additions & 0 deletions docs/api/ShallowWrapper/invoke.md
@@ -0,0 +1,38 @@
# `.invoke(invokeName[, ...args]) => Any`

Invokes a function prop.

#### Arguments

1. `propName` (`String`): The function prop to be invoked
2. `...args` (`Any` [optional]): Arguments that will be passed to the prop function

#### Returns

`Any`: Returns the value from the prop function

#### Example

```jsx
class Foo extends React.Component {
loadData() {
return fetch();
}
render() {
return (
<div>
<button
type="button"
onClick={() => this.loadData()}
>
Load more
</button>
</div>
);
}
}
const wrapper = shallow(<Foo />);
wrapper.find('a').invoke('onClick').then(() => {
// expect()
});
```
3 changes: 3 additions & 0 deletions docs/api/mount.md
Expand Up @@ -159,6 +159,9 @@ Returns the props of the root component.
#### [`.prop(key) => Any`](ReactWrapper/prop.md)
Returns the named prop of the root component.

#### [`.invoke(propName[, ...args]) => Any`](ReactWrapper/invoke.md)
Invokes a prop function on the current node and returns the function's return value.

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

Expand Down
3 changes: 3 additions & 0 deletions docs/api/shallow.md
Expand Up @@ -175,6 +175,9 @@ Returns the named prop of the current node.
#### [`.key() => String`](ShallowWrapper/key.md)
Returns the key of the current node.

#### [`.invoke(propName[, ...args]) => Any`](ShallowWrapper/invoke.md)
Invokes a prop function on the current node and returns the function's return value.

#### [`.simulate(event[, data]) => ShallowWrapper`](ShallowWrapper/simulate.md)
Simulates an event on the current node.

Expand Down
2 changes: 1 addition & 1 deletion packages/enzyme-test-suite/package.json
Expand Up @@ -57,4 +57,4 @@
"eslint-plugin-react": "^7.12.4",
"react-is": "^16.7.0"
}
}
}
64 changes: 64 additions & 0 deletions packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
Expand Up @@ -5408,6 +5408,70 @@ describeWithDOM('mount', () => {
});
});

describe('.invoke(propName, ..args)', () => {
it('can update the state value', () => {
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}

render() {
const { count } = this.state;
return (
<div>
<button
type="button"
onClick={() => this.setState(state => ({ count: state.count + 1 }))}
>
{count}
</button>
</div>
);
}
}
const wrapper = mount(<Foo />);
wrapper.find('button').invoke('onClick');
expect(wrapper.state('count')).to.equal(1);
});
it('can return the handlers return value', () => {
const spy = sinon.stub().returns(123);
class Foo extends React.Component {
render() {
return (
<div>
<a onClick={spy}>foo</a>
</div>
);
}
}
const wrapper = mount(<Foo />);
const value = wrapper.find('a').invoke('onClick');
expect(value).to.equal(123);
expect(spy.called).to.equal(true);
});
it('can pass in arguments', () => {
const spy = sinon.spy();
class Foo extends React.Component {
render() {
return (
<div>
<a onClick={spy}>foo</a>
</div>
);
}
}
const wrapper = mount(<Foo />);
const a = {};
const b = {};
wrapper.find('a').invoke('onClick', a, b);
expect(spy.args[0][0]).to.equal(a);
expect(spy.args[0][1]).to.equal(b);
});
});

wrap()
.withConsoleThrows()
.describe('.renderProp()', () => {
Expand Down
64 changes: 64 additions & 0 deletions packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
Expand Up @@ -5489,6 +5489,70 @@ describe('shallow', () => {
});
});

describe('.invoke(propName, ..args)', () => {
it('can update the state value', () => {
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}

render() {
const { count } = this.state;
return (
<div>
<button
type="button"
onClick={() => this.setState(state => ({ count: state.count + 1 }))}
>
{count}
</button>
</div>
);
}
}
const wrapper = shallow(<Foo />);
wrapper.find('button').invoke('onClick');
expect(wrapper.state('count')).to.equal(1);
});
it('can return the handlers return value', () => {
const spy = sinon.stub().returns(123);
class Foo extends React.Component {
render() {
return (
<div>
<button onClick={spy}>foo</button>
</div>
);
}
}
const wrapper = shallow(<Foo />);
const value = wrapper.find('button').invoke('onClick');
expect(value).to.equal(123);
expect(spy.called).to.equal(true);
});
it('can pass in arguments', () => {
const spy = sinon.spy();
class Foo extends React.Component {
render() {
return (
<div>
<button onClick={spy}>foo</button>
</div>
);
}
}
const wrapper = shallow(<Foo />);
const a = {};
const b = {};
wrapper.find('button').invoke('onClick', a, b);
expect(spy.args[0][0]).to.equal(a);
expect(spy.args[0][1]).to.equal(b);
});
});

wrap()
.withConsoleThrows()
.describe('.renderProp()', () => {
Expand Down
20 changes: 20 additions & 0 deletions packages/enzyme/src/ReactWrapper.js
Expand Up @@ -802,6 +802,26 @@ class ReactWrapper {
return this.props()[propName];
}

/**
* Used to invoke a function prop.
* Will invoke an function prop and return its value.
*
* @param {String} propName
* @param {Array} args
* @returns {Any}
*/
invoke(propName, ...args) {
return this.single('invoke', () => {
const handler = this.prop(propName);
if (typeof handler !== 'function') {
throw new TypeError('ReactWrapper::invoke() expects a function prop name as its first argument');
}
const response = handler.apply(this, args);
this[ROOT].update();
return response;
});
}

/**
* Returns a wrapper of the node rendered by the provided render prop.
*
Expand Down
20 changes: 20 additions & 0 deletions packages/enzyme/src/ShallowWrapper.js
Expand Up @@ -1132,6 +1132,26 @@ class ShallowWrapper {
return this.props()[propName];
}

/**
* Used to invoke a function prop.
* Will invoke an function prop and return its value.
*
* @param {String} propName
* @param {Array} args
* @returns {Any}
*/
invoke(propName, ...args) {
return this.single('invoke', () => {
const handler = this.prop(propName);
if (typeof handler !== 'function') {
throw new TypeError('ShallowWrapper::invoke() expects a function prop name as its first argument');
}
const response = handler.apply(this, args);
this[ROOT].update();
return response;
});
}

/**
* Returns a wrapper of the node rendered by the provided render prop.
*
Expand Down

0 comments on commit 02c2b1b

Please sign in to comment.