diff --git a/docs/README.md b/docs/README.md
index f762881ad..42a111882 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -67,6 +67,7 @@
* [text()](/docs/api/ShallowWrapper/text.md)
* [type()](/docs/api/ShallowWrapper/type.md)
* [unmount()](/docs/api/ShallowWrapper/unmount.md)
+ * [update()](/docs/api/ShallowWrapper/update.md)
* [Full DOM Rendering](/docs/api/mount.md)
* [at(index)](/docs/api/ReactWrapper/at.md)
* [contains(nodeOrNodes)](/docs/api/ReactWrapper/contains.md)
diff --git a/docs/api/ShallowWrapper/update.md b/docs/api/ShallowWrapper/update.md
index e69de29bb..3dc372353 100644
--- a/docs/api/ShallowWrapper/update.md
+++ b/docs/api/ShallowWrapper/update.md
@@ -0,0 +1,33 @@
+# `.update() => Self`
+
+Forces a re-render. Useful to run before checking the render output if something external
+may be updating the state of the component somewhere.
+
+NOTE: can only be called on a wrapper instance that is also the root instance.
+
+
+#### Returns
+
+`ShallowWrapper`: Returns itself.
+
+
+
+#### Example
+
+```jsx
+class ImpureRender extends React.Component {
+ constructor(props) {
+ super(props);
+ this.count = 0;
+ }
+ render() {
+ return
{this.count++}
+ }
+}
+```
+```jsx
+const wrapper = shallow();
+expect(wrapper.text()).to.equal("0");
+wrapper.update();
+expect(wrapper.text()).to.equal("1");
+```
diff --git a/docs/api/shallow.md b/docs/api/shallow.md
index 38b5bbdc6..2e31a3b31 100644
--- a/docs/api/shallow.md
+++ b/docs/api/shallow.md
@@ -169,6 +169,9 @@ Manually sets context of the root component.
#### [`.instance() => ReactComponent`](ShallowWrapper/instance.md)
Returns the instance of the root component.
+#### [`.update() => ShallowWrapper`](ShallowWrapper/update.md)
+Calls `.forceUpdate()` on the root component instance.
+
#### [`.debug() => String`](ShallowWrapper/debug.md)
Returns a string representation of the current shallow render tree for debugging purposes.
diff --git a/src/ShallowWrapper.js b/src/ShallowWrapper.js
index d86e9f3e5..9e0db7d2d 100644
--- a/src/ShallowWrapper.js
+++ b/src/ShallowWrapper.js
@@ -145,10 +145,23 @@ class ShallowWrapper {
}
/**
- * @deprecated
+ * Forces a re-render. Useful to run before checking the render output if something external
+ * may be updating the state of the component somewhere.
+ *
+ * NOTE: can only be called on a wrapper instance that is also the root instance.
+ *
* @returns {ShallowWrapper}
*/
update() {
+ if (this.root !== this) {
+ throw new Error('ShallowWrapper::update() can only be called on the root');
+ }
+ this.single(() => {
+ const instance = this.instance();
+ if (instance) {
+ instance.forceUpdate();
+ }
+ });
return this;
}
diff --git a/test/ShallowWrapper-spec.jsx b/test/ShallowWrapper-spec.jsx
index 47ff4c660..48e21253f 100644
--- a/test/ShallowWrapper-spec.jsx
+++ b/test/ShallowWrapper-spec.jsx
@@ -3726,24 +3726,37 @@ describe('shallow', () => {
}
class Test extends React.Component {
+ componentWillMount() {
+ this.state = {};
+ }
+
safeSetState(newState) {
withSetStateAllowed(() => {
this.setState(newState);
});
}
- asyncUpdate() {
+ asyncSetState() {
setImmediate(() => {
this.safeSetState({ showSpan: true });
});
}
+ mutateState() {
+ this.state.showSpan = true;
+ }
+
+ callbackSetState() {
+ this.safeSetState({ showSpan: true });
+ }
+
render() {
return (
{this.state && this.state.showSpan && }
-
);
}
@@ -3763,6 +3776,13 @@ describe('shallow', () => {
wrapper.find(Child).props().callback();
expect(wrapper.find('.show-me').length).to.equal(1);
});
+
+ it('should have updated output after state mutation when .update() is called', () => {
+ const wrapper = shallow();
+ wrapper.find('.mutates-btn').simulate('click');
+ wrapper.update();
+ expect(wrapper.find('.show-me').length).to.equal(1);
+ });
});
describe('#single()', () => {