From 1107b9673c779425a251ed5336ee8b6721498666 Mon Sep 17 00:00:00 2001 From: Sunil Pai Date: Wed, 6 Feb 2019 16:25:26 +0000 Subject: [PATCH] [TestUtils.act] warn when using TestUtils.act in node (#14768) * warn when using TestUtils.act in node * s/warns/throws * s/throw/warn * consistent ellipses --- .../src/test-utils/ReactTestUtils.js | 22 ++++++++++++++++--- .../ReactTestRenderer-test.internal.js | 16 +++++++++++++- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/packages/react-dom/src/test-utils/ReactTestUtils.js b/packages/react-dom/src/test-utils/ReactTestUtils.js index dcb20d88cf9f7..649598c759a15 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtils.js +++ b/packages/react-dom/src/test-utils/ReactTestUtils.js @@ -151,8 +151,8 @@ function validateClassInstance(inst, methodName) { ); } -// stub element used by act() when flushing effects -let actContainerElement = document.createElement('div'); +// a stub element, lazily initialized, used by act() when flushing effects +let actContainerElement = null; /** * Utilities for making it easy to test React components. @@ -391,9 +391,25 @@ const ReactTestUtils = { SimulateNative: {}, act(callback: () => void): Thenable { + if (actContainerElement === null) { + // warn if we can't actually create the stub element + if (__DEV__) { + warningWithoutStack( + typeof document !== 'undefined' && + document !== null && + typeof document.createElement === 'function', + 'It looks like you called TestUtils.act(...) in a non-browser environment. ' + + "If you're using TestRenderer for your tests, you should call " + + 'TestRenderer.act(...) instead of TestUtils.act(...).', + ); + } + // then make it + actContainerElement = document.createElement('div'); + } + + const result = ReactDOM.unstable_batchedUpdates(callback); // note: keep these warning messages in sync with // createReactNoop.js and ReactTestRenderer.js - const result = ReactDOM.unstable_batchedUpdates(callback); if (__DEV__) { if (result !== undefined) { let addendum; diff --git a/packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js b/packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js index 0ca6fb54b50a9..1ce786c27b8cd 100644 --- a/packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js +++ b/packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js @@ -1023,7 +1023,7 @@ describe('ReactTestRenderer', () => { }); describe('act', () => { - it('works', () => { + it('can use .act() to batch updates and effects', () => { function App(props) { React.useEffect(() => { props.callback(); @@ -1043,5 +1043,19 @@ describe('ReactTestRenderer', () => { expect(called).toBe(true); }); + it('warns and throws if you use TestUtils.act instead of TestRenderer.act in node', () => { + // we warn when you try to load 2 renderers in the same 'scope' + // so as suggested, we call resetModules() to carry on with the test + jest.resetModules(); + const {act} = require('react-dom/test-utils'); + expect(() => { + expect(() => act(() => {})).toThrow('document is not defined'); + }).toWarnDev( + [ + 'It looks like you called TestUtils.act(...) in a non-browser environment', + ], + {withoutStack: 1}, + ); + }); }); });