diff --git a/test-utils/src/index.js b/test-utils/src/index.js index 447f502cfc..9e7a677da2 100644 --- a/test-utils/src/index.js +++ b/test-utils/src/index.js @@ -24,20 +24,28 @@ export function act(cb) { // Override requestAnimationFrame so we can flush pending hooks. options.requestAnimationFrame = (fc) => flush = fc; - // Execute the callback we were passed. - cb(); - rerender(); + const finish = () => { + rerender(); + while (flush) { + toFlush = flush; + flush = null; - while (flush) { - toFlush = flush; - flush = null; + toFlush(); + rerender(); + } - toFlush(); - rerender(); + teardown(); + options.requestAnimationFrame = previousRequestAnimationFrame; + }; + + const result = cb(); + + if (result != null && typeof result.then === 'function') { + return result.then(finish); } - teardown(); - options.requestAnimationFrame = previousRequestAnimationFrame; + finish(); + return Promise.resolve(); } /** diff --git a/test-utils/test/shared/act.test.js b/test-utils/test/shared/act.test.js index f1d3750e9b..bf9c58a0a6 100644 --- a/test-utils/test/shared/act.test.js +++ b/test-utils/test/shared/act.test.js @@ -191,4 +191,51 @@ describe('act', () => { }); expect(scratch.firstChild.textContent).to.equal('1'); }); + + it('returns a Promise if invoked with a sync callback', () => { + const result = act(() => {}); + expect(result.then).to.be.a('function'); + return result; + }); + + it('returns a Promise if invoked with an async callback', () => { + const result = act(async () => {}); + expect(result.then).to.be.a('function'); + return result; + }); + + it('should await "thenable" result of callback before flushing', async () => { + const events = []; + + function TestComponent() { + useEffect(() => { + events.push('flushed effect'); + }, []); + events.push('scheduled effect'); + return
Test
; + } + + const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); + + events.push('began test'); + const acted = act(async () => { + events.push('began act callback'); + await delay(1); + render(, scratch); + events.push('end act callback'); + }); + events.push('act returned'); + await acted; + events.push('act result resolved'); + + expect(events).to.deep.equal([ + 'began test', + 'began act callback', + 'act returned', + 'scheduled effect', + 'end act callback', + 'flushed effect', + 'act result resolved' + ]); + }); });