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()', () => {