From 8e9ace462dfdf39776b68a6465c906d409f9c698 Mon Sep 17 00:00:00 2001 From: Justin Bay Date: Sat, 9 Jul 2016 18:54:50 -0400 Subject: [PATCH] use getter for .node and .nodes in ShallowWrapper to ensure render output is always fresh. removes need for .update --- docs/README.md | 1 - docs/api/ShallowWrapper/update.md | 33 --------------------- docs/api/shallow.md | 3 -- src/ShallowWrapper.js | 25 +++++++--------- test/ShallowWrapper-spec.jsx | 49 ++++++++++++++++++++++++++++++- 5 files changed, 59 insertions(+), 52 deletions(-) diff --git a/docs/README.md b/docs/README.md index 42a111882..f762881ad 100644 --- a/docs/README.md +++ b/docs/README.md @@ -67,7 +67,6 @@ * [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 3dc372353..e69de29bb 100644 --- a/docs/api/ShallowWrapper/update.md +++ b/docs/api/ShallowWrapper/update.md @@ -1,33 +0,0 @@ -# `.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 2e31a3b31..38b5bbdc6 100644 --- a/docs/api/shallow.md +++ b/docs/api/shallow.md @@ -169,9 +169,6 @@ 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 32fc2d25b..7ae106f2a 100644 --- a/src/ShallowWrapper.js +++ b/src/ShallowWrapper.js @@ -84,8 +84,16 @@ class ShallowWrapper { } }); }); - this.node = this.renderer.getRenderOutput(); - this.nodes = [this.node]; + Object.defineProperty(this, 'node', { + get() { + return this.renderer.getRenderOutput(); + }, + }); + Object.defineProperty(this, 'nodes', { + get() { + return [this.renderer.getRenderOutput()]; + }, + }); this.length = 1; } else { this.root = root; @@ -125,21 +133,10 @@ class ShallowWrapper { } /** - * 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. - * + * @deprecated * @returns {ShallowWrapper} */ update() { - if (this.root !== this) { - throw new Error('ShallowWrapper::update() can only be called on the root'); - } - this.single('update', () => { - this.node = this.renderer.getRenderOutput(); - this.nodes = [this.node]; - }); return this; } diff --git a/test/ShallowWrapper-spec.jsx b/test/ShallowWrapper-spec.jsx index ccbdb1a8b..688ca5b38 100644 --- a/test/ShallowWrapper-spec.jsx +++ b/test/ShallowWrapper-spec.jsx @@ -4,7 +4,7 @@ import sinon from 'sinon'; import { shallow, render, ShallowWrapper } from '../src/'; import { describeIf, itIf, itWithData, generateEmptyRenderData } from './_helpers'; -import { ITERATOR_SYMBOL } from '../src/Utils'; +import { ITERATOR_SYMBOL, withSetStateAllowed } from '../src/Utils'; import { REACT013, REACT15 } from '../src/version'; describe('shallow', () => { @@ -3718,6 +3718,53 @@ describe('shallow', () => { }); }); + describe('out-of-band state updates', () => { + class Child extends React.Component { + render() { + return ; + } + } + + class Test extends React.Component { + safeSetState(newState) { + withSetStateAllowed(() => { + this.setState(newState); + }); + } + + asyncUpdate() { + setImmediate(() => { + this.safeSetState({ showSpan: true }); + }); + } + + render() { + return ( +
+ {this.state && this.state.showSpan && } +
+ ); + } + } + + it('should have updated output after an asynchronous setState', done => { + const wrapper = shallow(); + wrapper.find('.async-btn').simulate('click'); + setImmediate(() => { + expect(wrapper.find('.show-me').length).to.equal(1); + done(); + }); + }); + + it('should have updated output after child prop callback invokes setState', () => { + const wrapper = shallow(); + wrapper.find(Child).props().callback(); + expect(wrapper.find('.show-me').length).to.equal(1); + }); + }); + describe('#single()', () => { it('throws if run on multiple nodes', () => { const wrapper = shallow(
).children();