From 7b07d45be5ec0922c07ce9ddc1463146868612fb Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 15 Jun 2021 15:06:24 -0400 Subject: [PATCH] Throw when `act` is used in production Upgrades the deprecation warning to a runtime error. I did it this way instead of removing the export so the type is the same in both builds. It will get dead code eliminated regardless. --- fixtures/legacy-jsx-runtimes/setupTests.js | 10 ---- .../src/__tests__/ReactTestUtilsAct-test.js | 46 +++++++++++-------- ...ReactTestUtilsActUnmockedScheduler-test.js | 5 ++ .../src/test-utils/ReactTestUtilsPublicAct.js | 13 ++---- .../src/ReactFiberWorkLoop.new.js | 12 ++--- .../src/ReactFiberWorkLoop.old.js | 12 ++--- .../ReactFiberHostContext-test.internal.js | 2 + .../__tests__/ReactUpdaters-test.internal.js | 35 +++++++------- .../__tests__/ReactTestRendererAct-test.js | 4 ++ .../ReactCoffeeScriptClass-test.coffee | 2 +- .../react/src/__tests__/ReactES6Class-test.js | 2 +- .../__tests__/ReactTypeScriptClass-test.ts | 21 +++++---- .../testDefinitions/ReactDOMTestUtils.d.ts | 2 +- scripts/error-codes/codes.json | 3 +- scripts/jest/shouldIgnoreConsoleError.js | 10 ---- 15 files changed, 87 insertions(+), 92 deletions(-) diff --git a/fixtures/legacy-jsx-runtimes/setupTests.js b/fixtures/legacy-jsx-runtimes/setupTests.js index 85a21cc15d911..3e675b3f7c2c5 100644 --- a/fixtures/legacy-jsx-runtimes/setupTests.js +++ b/fixtures/legacy-jsx-runtimes/setupTests.js @@ -33,16 +33,6 @@ function shouldIgnoreConsoleError(format, args) { // They are noisy too so we'll try to ignore them. return true; } - if ( - format.indexOf( - 'act(...) is not supported in production builds of React' - ) === 0 - ) { - // We don't yet support act() for prod builds, and warn for it. - // But we'd like to use act() ourselves for prod builds. - // Let's ignore the warning and #yolo. - return true; - } } // Looks legit return false; diff --git a/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js b/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js index d2ea73e09800c..2dabcfc5281b7 100644 --- a/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js +++ b/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js @@ -135,6 +135,7 @@ function runActTests(label, render, unmount, rerender) { }); describe('sync', () => { + // @gate __DEV__ it('can use act to flush effects', () => { function App() { React.useEffect(() => { @@ -150,6 +151,7 @@ function runActTests(label, render, unmount, rerender) { expect(Scheduler).toHaveYielded([100]); }); + // @gate __DEV__ it('flushes effects on every call', async () => { function App() { const [ctr, setCtr] = React.useState(0); @@ -186,6 +188,7 @@ function runActTests(label, render, unmount, rerender) { expect(button.innerHTML).toBe('5'); }); + // @gate __DEV__ it("should keep flushing effects until they're done", () => { function App() { const [ctr, setCtr] = React.useState(0); @@ -204,6 +207,7 @@ function runActTests(label, render, unmount, rerender) { expect(container.innerHTML).toBe('5'); }); + // @gate __DEV__ it('should flush effects only on exiting the outermost act', () => { function App() { React.useEffect(() => { @@ -224,6 +228,7 @@ function runActTests(label, render, unmount, rerender) { expect(Scheduler).toHaveYielded([0]); }); + // @gate __DEV__ it('warns if a setState is called outside of act(...)', () => { let setValue = null; function App() { @@ -250,6 +255,7 @@ function runActTests(label, render, unmount, rerender) { jest.useRealTimers(); }); + // @gate __DEV__ it('lets a ticker update', () => { function App() { const [toggle, setToggle] = React.useState(0); @@ -272,6 +278,7 @@ function runActTests(label, render, unmount, rerender) { expect(container.innerHTML).toBe('1'); }); + // @gate __DEV__ it('can use the async version to catch microtasks', async () => { function App() { const [toggle, setToggle] = React.useState(0); @@ -294,6 +301,7 @@ function runActTests(label, render, unmount, rerender) { expect(container.innerHTML).toBe('1'); }); + // @gate __DEV__ it('can handle cascading promises with fake timers', async () => { // this component triggers an effect, that waits a tick, // then sets state. repeats this 5 times. @@ -317,6 +325,7 @@ function runActTests(label, render, unmount, rerender) { expect(container.innerHTML).toBe('5'); }); + // @gate __DEV__ it('flushes immediate re-renders with act', () => { function App() { const [ctr, setCtr] = React.useState(0); @@ -346,6 +355,7 @@ function runActTests(label, render, unmount, rerender) { }); }); + // @gate __DEV__ it('warns if you return a value inside act', () => { expect(() => act(() => null)).toErrorDev( [ @@ -361,6 +371,7 @@ function runActTests(label, render, unmount, rerender) { ); }); + // @gate __DEV__ it('warns if you try to await a sync .act call', () => { expect(() => act(() => {}).then(() => {})).toErrorDev( [ @@ -372,6 +383,7 @@ function runActTests(label, render, unmount, rerender) { }); describe('asynchronous tests', () => { + // @gate __DEV__ it('works with timeouts', async () => { function App() { const [ctr, setCtr] = React.useState(0); @@ -396,6 +408,7 @@ function runActTests(label, render, unmount, rerender) { expect(container.innerHTML).toBe('1'); }); + // @gate __DEV__ it('flushes microtasks before exiting', async () => { function App() { const [ctr, setCtr] = React.useState(0); @@ -418,6 +431,7 @@ function runActTests(label, render, unmount, rerender) { expect(container.innerHTML).toEqual('1'); }); + // @gate __DEV__ it('warns if you do not await an act call', async () => { spyOnDevAndProd(console, 'error'); act(async () => {}); @@ -431,6 +445,7 @@ function runActTests(label, render, unmount, rerender) { } }); + // @gate __DEV__ it('warns if you try to interleave multiple act calls', async () => { spyOnDevAndProd(console, 'error'); // let's try to cheat and spin off a 'thread' with an act call @@ -450,6 +465,7 @@ function runActTests(label, render, unmount, rerender) { } }); + // @gate __DEV__ it('async commits and effects are guaranteed to be flushed', async () => { function App() { const [state, setState] = React.useState(0); @@ -475,6 +491,7 @@ function runActTests(label, render, unmount, rerender) { expect(container.innerHTML).toBe('1'); }); + // @gate __DEV__ it('can handle cascading promises', async () => { // this component triggers an effect, that waits a tick, // then sets state. repeats this 5 times. @@ -501,6 +518,7 @@ function runActTests(label, render, unmount, rerender) { }); describe('error propagation', () => { + // @gate __DEV__ it('propagates errors - sync', () => { let err; try { @@ -515,6 +533,7 @@ function runActTests(label, render, unmount, rerender) { } }); + // @gate __DEV__ it('should propagate errors from effects - sync', () => { function App() { React.useEffect(() => { @@ -536,6 +555,7 @@ function runActTests(label, render, unmount, rerender) { } }); + // @gate __DEV__ it('propagates errors - async', async () => { let err; try { @@ -551,6 +571,7 @@ function runActTests(label, render, unmount, rerender) { } }); + // @gate __DEV__ it('should cleanup after errors - sync', () => { function App() { React.useEffect(() => { @@ -576,6 +597,7 @@ function runActTests(label, render, unmount, rerender) { } }); + // @gate __DEV__ it('should cleanup after errors - async', async () => { function App() { async function somethingAsync() { @@ -611,6 +633,7 @@ function runActTests(label, render, unmount, rerender) { if (__DEV__ && __EXPERIMENTAL__) { // todo - remove __DEV__ check once we start using testing builds + // @gate __DEV__ it('triggers fallbacks if available', async () => { if (label !== 'legacy mode') { // FIXME: Support for Concurrent Root intentionally removed @@ -691,25 +714,12 @@ function runActTests(label, render, unmount, rerender) { }); } }); - describe('warn in prod mode', () => { + describe('throw in prod mode', () => { + // @gate !__DEV__ it('warns if you try to use act() in prod mode', () => { - const spy = spyOnDevAndProd(console, 'error'); - - act(() => {}); - - if (!__DEV__) { - expect(console.error).toHaveBeenCalledTimes(1); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'act(...) is not supported in production builds of React', - ); - } else { - expect(console.error).toHaveBeenCalledTimes(0); - } - - spy.calls.reset(); - // does not warn twice - act(() => {}); - expect(console.error).toHaveBeenCalledTimes(0); + expect(() => act(() => {})).toThrow( + 'act(...) is not supported in production builds of React', + ); }); }); }); diff --git a/packages/react-dom/src/__tests__/ReactTestUtilsActUnmockedScheduler-test.js b/packages/react-dom/src/__tests__/ReactTestUtilsActUnmockedScheduler-test.js index f7145f657c72d..e1ff6f8700195 100644 --- a/packages/react-dom/src/__tests__/ReactTestUtilsActUnmockedScheduler-test.js +++ b/packages/react-dom/src/__tests__/ReactTestUtilsActUnmockedScheduler-test.js @@ -47,6 +47,7 @@ afterEach(() => { document.body.removeChild(container); }); +// @gate __DEV__ it('can use act to flush effects', () => { function App() { React.useEffect(() => { @@ -62,6 +63,7 @@ it('can use act to flush effects', () => { expect(clearYields()).toEqual([100]); }); +// @gate __DEV__ it('flushes effects on every call', () => { function App() { const [ctr, setCtr] = React.useState(0); @@ -100,6 +102,7 @@ it('flushes effects on every call', () => { expect(button.innerHTML).toEqual('5'); }); +// @gate __DEV__ it("should keep flushing effects until they're done", () => { function App() { const [ctr, setCtr] = React.useState(0); @@ -118,6 +121,7 @@ it("should keep flushing effects until they're done", () => { expect(container.innerHTML).toEqual('5'); }); +// @gate __DEV__ it('should flush effects only on exiting the outermost act', () => { function App() { React.useEffect(() => { @@ -138,6 +142,7 @@ it('should flush effects only on exiting the outermost act', () => { expect(clearYields()).toEqual([0]); }); +// @gate __DEV__ it('can handle cascading promises', async () => { // this component triggers an effect, that waits a tick, // then sets state. repeats this 5 times. diff --git a/packages/react-dom/src/test-utils/ReactTestUtilsPublicAct.js b/packages/react-dom/src/test-utils/ReactTestUtilsPublicAct.js index 91ce4c9c5f68f..8f02e4b5f323c 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtilsPublicAct.js +++ b/packages/react-dom/src/test-utils/ReactTestUtilsPublicAct.js @@ -13,6 +13,7 @@ import * as ReactDOM from 'react-dom'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import enqueueTask from 'shared/enqueueTask'; import * as Scheduler from 'scheduler'; +import invariant from 'shared/invariant'; // Keep in sync with ReactDOM.js, and ReactTestUtils.js: const EventInternals = @@ -71,17 +72,13 @@ function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) { // so we can tell if any async act() calls try to run in parallel. let actingUpdatesScopeDepth = 0; -let didWarnAboutUsingActInProd = false; export function act(callback: () => Thenable): Thenable { if (!__DEV__) { - if (didWarnAboutUsingActInProd === false) { - didWarnAboutUsingActInProd = true; - // eslint-disable-next-line react-internal/no-production-logging - console.error( - 'act(...) is not supported in production builds of React, and might not behave as expected.', - ); - } + invariant( + false, + 'act(...) is not supported in production builds of React.', + ); } const previousActingUpdatesScopeDepth = actingUpdatesScopeDepth; actingUpdatesScopeDepth++; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js index 105e43229bd36..eb26348ca16e6 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js @@ -2985,17 +2985,13 @@ function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) { // so we can tell if any async act() calls try to run in parallel. let actingUpdatesScopeDepth = 0; -let didWarnAboutUsingActInProd = false; export function act(callback: () => Thenable): Thenable { if (!__DEV__) { - if (didWarnAboutUsingActInProd === false) { - didWarnAboutUsingActInProd = true; - // eslint-disable-next-line react-internal/no-production-logging - console.error( - 'act(...) is not supported in production builds of React, and might not behave as expected.', - ); - } + invariant( + false, + 'act(...) is not supported in production builds of React.', + ); } const previousActingUpdatesScopeDepth = actingUpdatesScopeDepth; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js index baff7e76b5e74..0b34957078535 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js @@ -2985,17 +2985,13 @@ function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) { // so we can tell if any async act() calls try to run in parallel. let actingUpdatesScopeDepth = 0; -let didWarnAboutUsingActInProd = false; export function act(callback: () => Thenable): Thenable { if (!__DEV__) { - if (didWarnAboutUsingActInProd === false) { - didWarnAboutUsingActInProd = true; - // eslint-disable-next-line react-internal/no-production-logging - console.error( - 'act(...) is not supported in production builds of React, and might not behave as expected.', - ); - } + invariant( + false, + 'act(...) is not supported in production builds of React.', + ); } const previousActingUpdatesScopeDepth = actingUpdatesScopeDepth; diff --git a/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js b/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js index a40a65671b8b2..8348c708f3bc5 100644 --- a/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js @@ -26,6 +26,7 @@ describe('ReactFiberHostContext', () => { .DefaultEventPriority; }); + // @gate __DEV__ it('works with null host context', async () => { let creates = 0; const Renderer = ReactFiberReconciler({ @@ -83,6 +84,7 @@ describe('ReactFiberHostContext', () => { expect(creates).toBe(2); }); + // @gate __DEV__ it('should send the context to prepareForCommit and resetAfterCommit', () => { const rootContext = {}; const Renderer = ReactFiberReconciler({ diff --git a/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js b/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js index 181b243c5cf65..66dd7d12b4927 100644 --- a/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js @@ -18,6 +18,7 @@ let mockDevToolsHook; let allSchedulerTags; let allSchedulerTypes; let onCommitRootShouldYield; +let act; describe('updaters', () => { beforeEach(() => { @@ -66,6 +67,8 @@ describe('updaters', () => { ReactDOM = require('react-dom'); ReactTestUtils = require('react-dom/test-utils'); Scheduler = require('scheduler'); + + act = ReactTestUtils.unstable_concurrentAct; }); it('should report the (host) root as the scheduler for root-level render', async () => { @@ -75,12 +78,12 @@ describe('updaters', () => { const Child = () => null; const container = document.createElement('div'); - await ReactTestUtils.act(async () => { + await act(async () => { ReactDOM.render(, container); }); expect(allSchedulerTags).toEqual([[HostRoot]]); - await ReactTestUtils.act(async () => { + await act(async () => { ReactDOM.render(, container); }); expect(allSchedulerTags).toEqual([[HostRoot], [HostRoot]]); @@ -108,19 +111,19 @@ describe('updaters', () => { }; const Child = () => null; - await ReactTestUtils.act(async () => { + await act(async () => { ReactDOM.render(, document.createElement('div')); }); expect(scheduleForA).not.toBeNull(); expect(scheduleForB).not.toBeNull(); expect(allSchedulerTypes).toEqual([[null]]); - await ReactTestUtils.act(async () => { + await act(async () => { scheduleForA(); }); expect(allSchedulerTypes).toEqual([[null], [SchedulingComponentA]]); - await ReactTestUtils.act(async () => { + await act(async () => { scheduleForB(); }); expect(allSchedulerTypes).toEqual([ @@ -141,13 +144,13 @@ describe('updaters', () => { } const Child = () => null; let instance; - await ReactTestUtils.act(async () => { + await act(async () => { ReactDOM.render(, document.createElement('div')); }); expect(allSchedulerTypes).toEqual([[null]]); expect(instance).not.toBeNull(); - await ReactTestUtils.act(async () => { + await act(async () => { instance.setState({}); }); expect(allSchedulerTypes).toEqual([[null], [SchedulingComponent]]); @@ -183,7 +186,7 @@ describe('updaters', () => { }; const root = ReactDOM.createRoot(document.createElement('div')); - await ReactTestUtils.act(async () => { + await act(async () => { root.render(); expect(Scheduler).toFlushAndYieldThrough([ 'CascadingChild 0', @@ -194,7 +197,7 @@ describe('updaters', () => { expect(triggerPassiveCascade).not.toBeNull(); expect(allSchedulerTypes).toEqual([[null]]); - await ReactTestUtils.act(async () => { + await act(async () => { triggerActiveCascade(); expect(Scheduler).toFlushAndYieldThrough([ 'CascadingChild 0', @@ -209,7 +212,7 @@ describe('updaters', () => { [CascadingChild], ]); - await ReactTestUtils.act(async () => { + await act(async () => { triggerPassiveCascade(); expect(Scheduler).toFlushAndYieldThrough([ 'CascadingChild 1', @@ -264,21 +267,21 @@ describe('updaters', () => { } }; - await ReactTestUtils.act(async () => { + await act(async () => { ReactDOM.render(, document.createElement('div')); expect(Scheduler).toHaveYielded(['onCommitRoot']); }); expect(setShouldSuspend).not.toBeNull(); expect(allSchedulerTypes).toEqual([[null]]); - await ReactTestUtils.act(async () => { + await act(async () => { setShouldSuspend(true); }); expect(Scheduler).toHaveYielded(['onCommitRoot']); expect(allSchedulerTypes).toEqual([[null], [Suspender]]); expect(resolver).not.toBeNull(); - await ReactTestUtils.act(() => { + await act(() => { resolver('abc'); return promise; }); @@ -328,7 +331,7 @@ describe('updaters', () => { }; const root = ReactDOM.createRoot(document.createElement('div')); - await ReactTestUtils.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['initial', 'onCommitRoot']); @@ -337,7 +340,7 @@ describe('updaters', () => { allSchedulerTypes.splice(0); onCommitRootShouldYield = true; - await ReactTestUtils.act(async () => { + await act(async () => { triggerError(); }); expect(Scheduler).toHaveYielded(['onCommitRoot', 'error', 'onCommitRoot']); @@ -398,7 +401,7 @@ describe('updaters', () => { expect(allSchedulerTags).toEqual([[HostRoot]]); // Render a partial update, but don't finish. - ReactTestUtils.act(() => { + act(() => { triggerLowPriorityUpdate(); expect(Scheduler).toFlushAndYieldThrough(['LowPriorityUpdater 1']); expect(allSchedulerTags).toEqual([[HostRoot]]); diff --git a/packages/react-test-renderer/src/__tests__/ReactTestRendererAct-test.js b/packages/react-test-renderer/src/__tests__/ReactTestRendererAct-test.js index 725b067b59f54..28cc0062e8a7b 100644 --- a/packages/react-test-renderer/src/__tests__/ReactTestRendererAct-test.js +++ b/packages/react-test-renderer/src/__tests__/ReactTestRendererAct-test.js @@ -13,6 +13,8 @@ describe('ReactTestRenderer.act()', () => { Scheduler = require('scheduler'); act = ReactTestRenderer.act; }); + + // @gate __DEV__ it('can use .act() to flush effects', () => { function App(props) { const [ctr, setCtr] = React.useState(0); @@ -56,6 +58,7 @@ describe('ReactTestRenderer.act()', () => { }); describe('async', () => { + // @gate __DEV__ it('should work with async/await', async () => { function fetch(url) { return Promise.resolve({ @@ -83,6 +86,7 @@ describe('ReactTestRenderer.act()', () => { expect(root.toJSON()).toEqual(['1', '2', '3']); }); + // @gate __DEV__ it('should not flush effects without also flushing microtasks', async () => { const {useEffect, useReducer} = React; diff --git a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee index 21463598cda43..24adba7561c6e 100644 --- a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee +++ b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee @@ -20,7 +20,7 @@ describe 'ReactCoffeeScriptClass', -> beforeEach -> React = require 'react' ReactDOM = require 'react-dom' - act = require('react-dom/test-utils').act + act = require('react-dom/test-utils').unstable_concurrentAct PropTypes = require 'prop-types' container = document.createElement 'div' root = ReactDOM.createRoot container diff --git a/packages/react/src/__tests__/ReactES6Class-test.js b/packages/react/src/__tests__/ReactES6Class-test.js index 3ae11bc4e74c2..8ce57867fcb0c 100644 --- a/packages/react/src/__tests__/ReactES6Class-test.js +++ b/packages/react/src/__tests__/ReactES6Class-test.js @@ -29,7 +29,7 @@ describe('ReactES6Class', () => { PropTypes = require('prop-types'); React = require('react'); ReactDOM = require('react-dom'); - act = require('react-dom/test-utils').act; + act = require('react-dom/test-utils').unstable_concurrentAct; container = document.createElement('div'); root = ReactDOM.createRoot(container); attachedListener = null; diff --git a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts index e8533b3e37af8..c0c2da07785e7 100644 --- a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts +++ b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts @@ -21,6 +21,7 @@ let container; let root; let attachedListener = null; let renderedName = null; +let act = ReactDOMTestUtils.unstable_concurrentAct; class Inner extends React.Component { getName() { @@ -34,7 +35,7 @@ class Inner extends React.Component { } function test(element, expectedTag, expectedClassName) { - ReactDOMTestUtils.act(() => root.render(element)); + act(() => root.render(element)); expect(container.firstChild).not.toBeNull(); expect(container.firstChild.tagName).toBe(expectedTag); expect(container.firstChild.className).toBe(expectedClassName); @@ -327,7 +328,7 @@ describe('ReactTypeScriptClass', function() { it('throws if no render function is defined', function() { expect(() => { expect(() => - ReactDOMTestUtils.act(() => root.render(React.createElement(Empty))) + act(() => root.render(React.createElement(Empty))) ).toThrow(); }).toErrorDev([ // A failed component renders four times in DEV in concurrent mode @@ -362,7 +363,7 @@ describe('ReactTypeScriptClass', function() { 'DIV', 'foo' ); - ReactDOMTestUtils.act(() => ref.current.changeState()); + act(() => ref.current.changeState()); test(React.createElement(StateBasedOnProps), 'SPAN', 'bar'); }); @@ -397,7 +398,7 @@ describe('ReactTypeScriptClass', function() { } } expect(function() { - ReactDOMTestUtils.act(() => + act(() => root.render(React.createElement(Foo, {foo: 'foo'})) ); }).toErrorDev( @@ -416,7 +417,7 @@ describe('ReactTypeScriptClass', function() { } } expect(function() { - ReactDOMTestUtils.act(() => + act(() => root.render(React.createElement(Foo, {foo: 'foo'})) ); }).toErrorDev( @@ -433,7 +434,7 @@ describe('ReactTypeScriptClass', function() { } } expect(function() { - ReactDOMTestUtils.act(() => + act(() => root.render(React.createElement(Foo, {foo: 'foo'})) ); }).toErrorDev( @@ -457,7 +458,7 @@ describe('ReactTypeScriptClass', function() { } } expect(function() { - ReactDOMTestUtils.act(() => + act(() => root.render(React.createElement(Foo, {foo: 'foo'})) ); }).toErrorDev( @@ -543,7 +544,7 @@ describe('ReactTypeScriptClass', function() { 'DIV', 'foo' ); - ReactDOMTestUtils.act(() => attachedListener()); + act(() => attachedListener()); expect(renderedName).toBe('bar'); }); @@ -562,7 +563,7 @@ describe('ReactTypeScriptClass', function() { 'DIV', 'foo' ); - ReactDOMTestUtils.act(() => attachedListener()); + act(() => attachedListener()); expect(renderedName).toBe('bar'); }); @@ -586,7 +587,7 @@ describe('ReactTypeScriptClass', function() { {}, ]); lifeCycles = []; // reset - ReactDOMTestUtils.act(() => root.unmount(container)); + act(() => root.unmount(container)); expect(lifeCycles).toEqual(['will-unmount']); }); diff --git a/packages/react/src/__tests__/testDefinitions/ReactDOMTestUtils.d.ts b/packages/react/src/__tests__/testDefinitions/ReactDOMTestUtils.d.ts index 50ff686037671..49ecaf208e054 100644 --- a/packages/react/src/__tests__/testDefinitions/ReactDOMTestUtils.d.ts +++ b/packages/react/src/__tests__/testDefinitions/ReactDOMTestUtils.d.ts @@ -13,5 +13,5 @@ */ declare module 'react-dom/test-utils' { - export function act(cb : () => any) : any + export function unstable_concurrentAct(cb : () => any) : any } diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json index d80cd0776ec23..38de792d6998c 100644 --- a/scripts/error-codes/codes.json +++ b/scripts/error-codes/codes.json @@ -393,5 +393,6 @@ "402": "The depth must equal at least at zero before reaching the root. This is a bug in React.", "403": "Tried to pop a Context at the root of the app. This is a bug in React.", "404": "Invalid hook call. Hooks can only be called inside of the body of a function component.", - "405": "hydrateRoot(...): Target container is not a DOM element." + "405": "hydrateRoot(...): Target container is not a DOM element.", + "406": "act(...) is not supported in production builds of React." } diff --git a/scripts/jest/shouldIgnoreConsoleError.js b/scripts/jest/shouldIgnoreConsoleError.js index 7534b4339abbf..02af0bfd28521 100644 --- a/scripts/jest/shouldIgnoreConsoleError.js +++ b/scripts/jest/shouldIgnoreConsoleError.js @@ -35,16 +35,6 @@ module.exports = function shouldIgnoreConsoleError(format, args) { // They are noisy too so we'll try to ignore them. return true; } - if ( - format.indexOf( - 'act(...) is not supported in production builds of React' - ) === 0 - ) { - // We don't yet support act() for prod builds, and warn for it. - // But we'd like to use act() ourselves for prod builds. - // Let's ignore the warning and #yolo. - return true; - } } // Looks legit return false;