diff --git a/test-utils/src/index.js b/test-utils/src/index.js index 270147926b..fb5457eea9 100644 --- a/test-utils/src/index.js +++ b/test-utils/src/index.js @@ -11,16 +11,23 @@ export function setupRerender() { } export function act(cb) { - const previousDebounce = options.debounceRendering; const previousRequestAnimationFrame = options.requestAnimationFrame; const rerender = setupRerender(); let flush; + // Override requestAnimationFrame so we can flush pending hooks. options.requestAnimationFrame = (fc) => flush = fc; + // Execute the callback we were passed. cb(); + // State COULD be built up flush it. if (flush) { flush(); } rerender(); - options.debounceRendering = previousDebounce; + // If rerendering with new state has triggered effects + // flush them aswell since options.raf will have repopulated this. + if (flush) { + flush(); + } + options.debounceRendering = Component.__test__previousDebounce; options.requestAnimationFrame = previousRequestAnimationFrame; } diff --git a/test-utils/test/shared/act.test.js b/test-utils/test/shared/act.test.js index baf03c2aa5..f0e410ee53 100644 --- a/test-utils/test/shared/act.test.js +++ b/test-utils/test/shared/act.test.js @@ -24,9 +24,47 @@ describe('act', () => { expect(options.requestAnimationFrame).to.equal(undefined); }); + it('should flush pending effects', () => { + let spy = sinon.spy(); + function StateContainer() { + useEffect(spy); + return
; + } + act(() => render(, scratch)); + expect(spy).to.be.calledOnce; + }); + + it('should flush pending and initial effects', () => { + const spy = sinon.spy(); + function StateContainer() { + const [count, setCount] = useState(0); + useEffect(() => spy(), [count]); + return ( +
+

Count: {count}

+
+ ); + } + + act(() => render(, scratch)); + expect(spy).to.be.calledOnce; + expect(scratch.textContent).to.include('Count: 0'); + act(() => { + const button = scratch.querySelector('button'); + button.click(); + expect(spy).to.be.calledOnce; + expect(scratch.textContent).to.include('Count: 0'); + }); + expect(spy).to.be.calledTwice; + expect(scratch.textContent).to.include('Count: 1'); + }); + it('should drain the queue of hooks', () => { + const spy = sinon.spy(); function StateContainer() { const [count, setCount] = useState(0); + useEffect(() => spy()); return (

Count: {count}