diff --git a/SUMMARY.md b/SUMMARY.md
index b2adcb25a..3fedeea45 100644
--- a/SUMMARY.md
+++ b/SUMMARY.md
@@ -48,6 +48,7 @@
* [hostNodes()](/docs/api/ShallowWrapper/hostNodes.md)
* [html()](/docs/api/ShallowWrapper/html.md)
* [instance()](/docs/api/ShallowWrapper/instance.md)
+ * [invoke(propName)](/docs/api/ShallowWrapper/invoke.md)
* [is(selector)](/docs/api/ShallowWrapper/is.md)
* [isEmpty()](/docs/api/ShallowWrapper/isEmpty.md)
* [isEmptyRender()](/docs/api/ShallowWrapper/isEmptyRender.md)
@@ -108,6 +109,7 @@
* [hostNodes()](/docs/api/ReactWrapper/hostNodes.md)
* [html()](/docs/api/ReactWrapper/html.md)
* [instance()](/docs/api/ReactWrapper/instance.md)
+ * [invoke(propName)](/docs/api/ReactWrapper/invoke.md)
* [is(selector)](/docs/api/ReactWrapper/is.md)
* [isEmpty()](/docs/api/ReactWrapper/isEmpty.md)
* [isEmptyRender()](/docs/api/ReactWrapper/isEmptyRender.md)
diff --git a/docs/api/ReactWrapper/invoke.md b/docs/api/ReactWrapper/invoke.md
new file mode 100644
index 000000000..57a404e5d
--- /dev/null
+++ b/docs/api/ReactWrapper/invoke.md
@@ -0,0 +1,41 @@
+# `.invoke(propName)(...args]) => Any`
+
+Invokes a function prop.
+
+#### Arguments
+
+1. `propName` (`String`): The function prop that is invoked
+2. `...args` (`Any` [optional]): Arguments that is 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 (
+
+
+
+ );
+ }
+}
+const wrapper = mount();
+wrapper.find('a').invoke('onClick')().then(() => {
+ // expect()
+});
+```
diff --git a/docs/api/ShallowWrapper/invoke.md b/docs/api/ShallowWrapper/invoke.md
new file mode 100644
index 000000000..b13ae615e
--- /dev/null
+++ b/docs/api/ShallowWrapper/invoke.md
@@ -0,0 +1,41 @@
+# `.invoke(invokePropName)(...args]) => Any`
+
+Invokes a function prop.
+
+#### Arguments
+
+1. `propName` (`String`): The function prop that is invoked
+2. `...args` (`Any` [optional]): Arguments that is passed to the prop function
+
+This essentially calls wrapper.prop(propName)(...args).
+
+#### Returns
+
+`Any`: Returns the value from the prop function
+
+#### Example
+
+```jsx
+class Foo extends React.Component {
+ loadData() {
+ return fetch();
+ }
+
+ render() {
+ return (
+
+
+
+ );
+ }
+}
+const wrapper = shallow();
+wrapper.find('a').invoke('onClick')().then(() => {
+ // expect()
+});
+```
diff --git a/docs/api/mount.md b/docs/api/mount.md
index 58b4e1f16..db2b6e8cd 100644
--- a/docs/api/mount.md
+++ b/docs/api/mount.md
@@ -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.
diff --git a/docs/api/shallow.md b/docs/api/shallow.md
index 7fd47d65a..3b67977ad 100644
--- a/docs/api/shallow.md
+++ b/docs/api/shallow.md
@@ -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.
diff --git a/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx b/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
index e39eaa063..451abe8a1 100644
--- a/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
+++ b/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
@@ -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 (
+
+
+
+ );
+ }
+ }
+ const wrapper = mount();
+ 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 (
+
+ );
+ }
+ }
+ const wrapper = mount();
+ 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 (
+
+ );
+ }
+ }
+ const wrapper = mount();
+ 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()', () => {
diff --git a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
index 422ee07f4..a826b218e 100644
--- a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
+++ b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
@@ -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 (
+
+
+
+ );
+ }
+ }
+ const wrapper = shallow();
+ 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 (
+
+
+
+ );
+ }
+ }
+ const wrapper = shallow();
+ 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 (
+
+
+
+ );
+ }
+ }
+ const wrapper = shallow();
+ 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()', () => {
diff --git a/packages/enzyme/src/ReactWrapper.js b/packages/enzyme/src/ReactWrapper.js
index 6b6c9e3f0..5de937047 100644
--- a/packages/enzyme/src/ReactWrapper.js
+++ b/packages/enzyme/src/ReactWrapper.js
@@ -802,6 +802,27 @@ class ReactWrapper {
return this.props()[propName];
}
+ /**
+ * Used to invoke a function prop.
+ * Will invoke an function prop and return its value.
+ *
+ * @param {String} propName
+ * @returns {Any}
+ */
+ invoke(propName) {
+ 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');
+ }
+ return (...args) => {
+ const response = handler.apply(this, args);
+ this[ROOT].update();
+ return response;
+ };
+ });
+ }
+
/**
* Returns a wrapper of the node rendered by the provided render prop.
*
diff --git a/packages/enzyme/src/ShallowWrapper.js b/packages/enzyme/src/ShallowWrapper.js
index b0165110e..b7d4f6cf1 100644
--- a/packages/enzyme/src/ShallowWrapper.js
+++ b/packages/enzyme/src/ShallowWrapper.js
@@ -1132,6 +1132,27 @@ class ShallowWrapper {
return this.props()[propName];
}
+ /**
+ * Used to invoke a function prop.
+ * Will invoke an function prop and return its value.
+ *
+ * @param {String} propName
+ * @returns {Any}
+ */
+ invoke(propName) {
+ 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');
+ }
+ return (...args) => {
+ const response = handler.apply(this, args);
+ this[ROOT].update();
+ return response;
+ };
+ });
+ }
+
/**
* Returns a wrapper of the node rendered by the provided render prop.
*