diff --git a/packages/create-subscription/src/__tests__/createSubscription-test.internal.js b/packages/create-subscription/src/__tests__/createSubscription-test.internal.js index cd924069ab39..66a8a652a831 100644 --- a/packages/create-subscription/src/__tests__/createSubscription-test.internal.js +++ b/packages/create-subscription/src/__tests__/createSubscription-test.internal.js @@ -11,7 +11,6 @@ let createSubscription; let BehaviorSubject; -let ReactFeatureFlags; let React; let ReactNoop; let Scheduler; @@ -21,8 +20,7 @@ describe('createSubscription', () => { beforeEach(() => { jest.resetModules(); createSubscription = require('create-subscription').createSubscription; - ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); diff --git a/packages/react-art/src/__tests__/ReactART-test.js b/packages/react-art/src/__tests__/ReactART-test.js index 6e25b0e25e2c..1613360ce636 100644 --- a/packages/react-art/src/__tests__/ReactART-test.js +++ b/packages/react-art/src/__tests__/ReactART-test.js @@ -391,7 +391,7 @@ describe('ReactART', () => { , ); - expect(Scheduler).toFlushAndYieldThrough(__DEV__ ? ['A', 'A'] : ['A']); + expect(Scheduler).toFlushAndYieldThrough(['A']); ReactDOM.render( @@ -406,9 +406,7 @@ describe('ReactART', () => { expect(ops).toEqual([null, 'ART']); ops = []; - expect(Scheduler).toFlushAndYield( - __DEV__ ? ['B', 'B', 'C', 'C'] : ['B', 'C'], - ); + expect(Scheduler).toFlushAndYield(['B', 'C']); expect(ops).toEqual(['Test']); }); diff --git a/packages/react-cache/src/__tests__/ReactCache-test.internal.js b/packages/react-cache/src/__tests__/ReactCache-test.internal.js index 24c3b3d390d8..0ad2269e12a3 100644 --- a/packages/react-cache/src/__tests__/ReactCache-test.internal.js +++ b/packages/react-cache/src/__tests__/ReactCache-test.internal.js @@ -24,7 +24,7 @@ describe('ReactCache', () => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; React = require('react'); Suspense = React.Suspense; diff --git a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js index e88bfc7b4601..a9e6e534bec0 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js @@ -10,7 +10,6 @@ 'use strict'; let React; -let ReactFeatureFlags = require('shared/ReactFeatureFlags'); let ReactDOM; let Scheduler; @@ -149,8 +148,7 @@ describe('ReactDOMFiberAsync', () => { describe('concurrent mode', () => { beforeEach(() => { jest.resetModules(); - ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactDOM = require('react-dom'); Scheduler = require('scheduler'); }); @@ -639,9 +637,7 @@ describe('ReactDOMFiberAsync', () => { expect(container.textContent).toEqual(''); // Everything should render immediately in the next event - expect(Scheduler).toFlushExpired( - __DEV__ ? ['A', 'A', 'B', 'B', 'C', 'C'] : ['A', 'B', 'C'], - ); + expect(Scheduler).toFlushExpired(['A', 'B', 'C']); expect(container.textContent).toEqual('ABC'); }); }); diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js index 06fca95894ae..a910b011f050 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js @@ -40,7 +40,7 @@ function initModules() { jest.resetModuleRegistry(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.flushSuspenseFallbacksInTests = false; React = require('react'); ReactDOM = require('react-dom'); diff --git a/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js index 4303263778ae..10cd143c54d8 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js @@ -77,7 +77,6 @@ describe('ReactDOMServerPartialHydration', () => { ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.enableSuspenseCallback = true; ReactFeatureFlags.enableDeprecatedFlareAPI = true; - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; React = require('react'); ReactDOM = require('react-dom'); diff --git a/packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js index 6c957b4767ad..4b02cd9c7386 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js @@ -97,7 +97,6 @@ describe('ReactDOMServerSelectiveHydration', () => { const ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.enableDeprecatedFlareAPI = true; - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; React = require('react'); ReactDOM = require('react-dom'); diff --git a/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js b/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js index ddd44e0004df..48d603fe49b6 100644 --- a/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js +++ b/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js @@ -121,7 +121,6 @@ describe('ReactTestUtils.act()', () => { ); }).toErrorDev([ 'An update to App ran an effect, but was not wrapped in act(...)', - 'An update to App ran an effect, but was not wrapped in act(...)', ]); }); @@ -132,7 +131,6 @@ describe('ReactTestUtils.act()', () => { Scheduler.unstable_flushAll(); }).toErrorDev([ 'An update to App ran an effect, but was not wrapped in act(...)', - 'An update to App ran an effect, but was not wrapped in act(...)', ]); }); @@ -143,7 +141,6 @@ describe('ReactTestUtils.act()', () => { Scheduler.unstable_flushAll(); }).toErrorDev([ 'An update to App ran an effect, but was not wrapped in act(...)', - 'An update to App ran an effect, but was not wrapped in act(...)', ]); }); }); diff --git a/packages/react-dom/src/__tests__/ReactUpdates-test.js b/packages/react-dom/src/__tests__/ReactUpdates-test.js index 79e0f6640b3a..29bccc13b6e0 100644 --- a/packages/react-dom/src/__tests__/ReactUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactUpdates-test.js @@ -1324,30 +1324,12 @@ describe('ReactUpdates', () => { let hiddenDiv; act(() => { root.render(); - if (__DEV__) { - expect(Scheduler).toFlushAndYieldThrough([ - 'Foo', - 'Foo', - 'Baz', - 'Baz', - 'Foo#effect', - ]); - } else { - expect(Scheduler).toFlushAndYieldThrough([ - 'Foo', - 'Baz', - 'Foo#effect', - ]); - } + expect(Scheduler).toFlushAndYieldThrough(['Foo', 'Baz', 'Foo#effect']); hiddenDiv = container.firstChild.firstChild; expect(hiddenDiv.hidden).toBe(true); expect(hiddenDiv.innerHTML).toBe(''); // Run offscreen update - if (__DEV__) { - expect(Scheduler).toFlushAndYield(['Bar', 'Bar']); - } else { - expect(Scheduler).toFlushAndYield(['Bar']); - } + expect(Scheduler).toFlushAndYield(['Bar']); expect(hiddenDiv.hidden).toBe(true); expect(hiddenDiv.innerHTML).toBe('

bar 0

'); }); @@ -1359,11 +1341,7 @@ describe('ReactUpdates', () => { expect(hiddenDiv.innerHTML).toBe('

bar 0

'); // Run offscreen update - if (__DEV__) { - expect(Scheduler).toFlushAndYield(['Bar', 'Bar']); - } else { - expect(Scheduler).toFlushAndYield(['Bar']); - } + expect(Scheduler).toFlushAndYield(['Bar']); expect(hiddenDiv.innerHTML).toBe('

bar 1

'); }, ); diff --git a/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js b/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js index f88e0d9e85e1..56ade67fef36 100644 --- a/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js +++ b/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js @@ -1701,12 +1701,7 @@ describe('DOMModernPluginEventSystem', () => { const root = ReactDOM.createRoot(container); root.render(); - // Dev double-render - if (__DEV__) { - expect(Scheduler).toFlushAndYield(['Test', 'Test']); - } else { - expect(Scheduler).toFlushAndYield(['Test']); - } + expect(Scheduler).toFlushAndYield(['Test']); // Click the button dispatchClickEvent(ref.current); @@ -1718,12 +1713,7 @@ describe('DOMModernPluginEventSystem', () => { // Increase counter root.render(); // Yield before committing - // Dev double-render - if (__DEV__) { - expect(Scheduler).toFlushAndYieldThrough(['Test', 'Test']); - } else { - expect(Scheduler).toFlushAndYieldThrough(['Test']); - } + expect(Scheduler).toFlushAndYieldThrough(['Test']); // Click the button again dispatchClickEvent(ref.current); diff --git a/packages/react-dom/src/events/__tests__/DeprecatedDOMEventResponderSystem-test.internal.js b/packages/react-dom/src/events/__tests__/DeprecatedDOMEventResponderSystem-test.internal.js index 7df4e3650434..20835d4d2e21 100644 --- a/packages/react-dom/src/events/__tests__/DeprecatedDOMEventResponderSystem-test.internal.js +++ b/packages/react-dom/src/events/__tests__/DeprecatedDOMEventResponderSystem-test.internal.js @@ -811,7 +811,7 @@ describe('DOMEventResponderSystem', () => { const root = ReactDOM.createRoot(container); root.render(); - expect(Scheduler).toFlushAndYield(__DEV__ ? ['Test', 'Test'] : ['Test']); + expect(Scheduler).toFlushAndYield(['Test']); // Click the button dispatchClickEvent(ref.current); @@ -823,9 +823,7 @@ describe('DOMEventResponderSystem', () => { // Increase counter root.render(); // Yield before committing - expect(Scheduler).toFlushAndYieldThrough( - __DEV__ ? ['Test', 'Test'] : ['Test'], - ); + expect(Scheduler).toFlushAndYieldThrough(['Test']); // Click the button again dispatchClickEvent(ref.current); diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index f08189c3ef01..2af5d28fcfd7 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -181,6 +181,8 @@ import { getWorkInProgressRoot, } from './ReactFiberWorkLoop'; +import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev'; + const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; let didReceiveUpdate: boolean = false; @@ -320,14 +322,19 @@ function updateForwardRef( debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode ) { - nextChildren = renderWithHooks( - current, - workInProgress, - render, - nextProps, - ref, - renderExpirationTime, - ); + disableLogs(); + try { + nextChildren = renderWithHooks( + current, + workInProgress, + render, + nextProps, + ref, + renderExpirationTime, + ); + } finally { + reenableLogs(); + } } setIsRendering(false); } else { @@ -658,14 +665,19 @@ function updateFunctionComponent( debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode ) { - nextChildren = renderWithHooks( - current, - workInProgress, - Component, - nextProps, - context, - renderExpirationTime, - ); + disableLogs(); + try { + nextChildren = renderWithHooks( + current, + workInProgress, + Component, + nextProps, + context, + renderExpirationTime, + ); + } finally { + reenableLogs(); + } } setIsRendering(false); } else { @@ -731,14 +743,19 @@ function updateBlock( debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode ) { - nextChildren = renderWithHooks( - current, - workInProgress, - render, - nextProps, - data, - renderExpirationTime, - ); + disableLogs(); + try { + nextChildren = renderWithHooks( + current, + workInProgress, + render, + nextProps, + data, + renderExpirationTime, + ); + } finally { + reenableLogs(); + } } setIsRendering(false); } else { @@ -923,7 +940,12 @@ function finishClassComponent( debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode ) { - instance.render(); + disableLogs(); + try { + instance.render(); + } finally { + reenableLogs(); + } } setIsRendering(false); } else { @@ -1485,14 +1507,19 @@ function mountIndeterminateComponent( debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode ) { - value = renderWithHooks( - null, - workInProgress, - Component, - props, - context, - renderExpirationTime, - ); + disableLogs(); + try { + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderExpirationTime, + ); + } finally { + reenableLogs(); + } } } reconcileChildren(null, workInProgress, value, renderExpirationTime); diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.js b/packages/react-reconciler/src/ReactFiberClassComponent.js index a688b891fa51..16ed860b83dd 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.js @@ -56,6 +56,8 @@ import { } from './ReactFiberWorkLoop'; import {requestCurrentSuspenseConfig} from './ReactFiberSuspenseConfig'; +import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev'; + const fakeInternalInstance = {}; const isArray = Array.isArray; @@ -151,8 +153,13 @@ export function applyDerivedStateFromProps( debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode ) { - // Invoke the function an extra time to help detect side-effects. - getDerivedStateFromProps(nextProps, prevState); + disableLogs(); + try { + // Invoke the function an extra time to help detect side-effects. + getDerivedStateFromProps(nextProps, prevState); + } finally { + reenableLogs(); + } } } @@ -266,8 +273,13 @@ function checkShouldComponentUpdate( debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode ) { - // Invoke the function an extra time to help detect side-effects. - instance.shouldComponentUpdate(newProps, newState, nextContext); + disableLogs(); + try { + // Invoke the function an extra time to help detect side-effects. + instance.shouldComponentUpdate(newProps, newState, nextContext); + } finally { + reenableLogs(); + } } } const shouldUpdate = instance.shouldComponentUpdate( @@ -598,7 +610,12 @@ function constructClassInstance( debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode ) { - new ctor(props, context); // eslint-disable-line no-new + disableLogs(); + try { + new ctor(props, context); // eslint-disable-line no-new + } finally { + reenableLogs(); + } } } diff --git a/packages/react-reconciler/src/ReactUpdateQueue.js b/packages/react-reconciler/src/ReactUpdateQueue.js index a2e1f3d2b5ff..ec29c4252017 100644 --- a/packages/react-reconciler/src/ReactUpdateQueue.js +++ b/packages/react-reconciler/src/ReactUpdateQueue.js @@ -107,6 +107,8 @@ import { import invariant from 'shared/invariant'; import {getCurrentPriorityLevel} from './SchedulerWithReactIntegration'; +import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev'; + export type Update = {| expirationTime: ExpirationTime, suspenseConfig: null | SuspenseConfig, @@ -336,7 +338,12 @@ function getStateFromUpdate( debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode ) { - payload.call(instance, prevState, nextProps); + disableLogs(); + try { + payload.call(instance, prevState, nextProps); + } finally { + reenableLogs(); + } } } const nextState = payload.call(instance, prevState, nextProps); @@ -364,7 +371,12 @@ function getStateFromUpdate( debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode ) { - payload.call(instance, prevState, nextProps); + disableLogs(); + try { + payload.call(instance, prevState, nextProps); + } finally { + reenableLogs(); + } } } partialState = payload.call(instance, prevState, nextProps); diff --git a/packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js b/packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js index 64b9aa592109..58c25dfdc6a4 100644 --- a/packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js @@ -12,7 +12,7 @@ describe('ErrorBoundaryReconciliation', () => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; ReactTestRenderer = require('react-test-renderer'); React = require('react'); diff --git a/packages/react-reconciler/src/__tests__/ReactBatchedMode-test.internal.js b/packages/react-reconciler/src/__tests__/ReactBatchedMode-test.internal.js index 1104d0bcbabe..c6af59fbd915 100644 --- a/packages/react-reconciler/src/__tests__/ReactBatchedMode-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactBatchedMode-test.internal.js @@ -10,7 +10,7 @@ describe('ReactBlockingMode', () => { beforeEach(() => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; React = require('react'); ReactNoop = require('react-noop-renderer'); diff --git a/packages/react-reconciler/src/__tests__/ReactDisableSchedulerTimeoutBasedOnReactExpirationTime-test.internal.js b/packages/react-reconciler/src/__tests__/ReactDisableSchedulerTimeoutBasedOnReactExpirationTime-test.internal.js index b37db4250b79..1a46bed43730 100644 --- a/packages/react-reconciler/src/__tests__/ReactDisableSchedulerTimeoutBasedOnReactExpirationTime-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactDisableSchedulerTimeoutBasedOnReactExpirationTime-test.internal.js @@ -10,7 +10,7 @@ describe('ReactSuspenseList', () => { beforeEach(() => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; ReactFeatureFlags.disableSchedulerTimeoutBasedOnReactExpirationTime = true; React = require('react'); diff --git a/packages/react-reconciler/src/__tests__/ReactExpiration-test.internal.js b/packages/react-reconciler/src/__tests__/ReactExpiration-test.internal.js index e063489c6eeb..7218aa98721a 100644 --- a/packages/react-reconciler/src/__tests__/ReactExpiration-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactExpiration-test.internal.js @@ -10,15 +10,13 @@ 'use strict'; let React; -let ReactFeatureFlags; let ReactNoop; let Scheduler; describe('ReactExpiration', () => { beforeEach(() => { jest.resetModules(); - ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); diff --git a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js index 5cfeee3c652e..129a83f639c8 100644 --- a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js @@ -26,7 +26,7 @@ describe('ReactHooks', () => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + React = require('react'); ReactTestRenderer = require('react-test-renderer'); Scheduler = require('scheduler'); diff --git a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js index ecc37d2c2d02..0f116f3645ae 100644 --- a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js @@ -42,7 +42,7 @@ describe('ReactHooksWithNoopRenderer', () => { jest.useFakeTimers(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.enableSchedulerTracing = true; ReactFeatureFlags.flushSuspenseFallbacksInTests = false; ReactFeatureFlags.enableProfilerTimer = true; @@ -299,25 +299,29 @@ describe('ReactHooksWithNoopRenderer', () => { }); it('returns the same updater function every time', () => { - const updaters = []; + let updater = null; function Counter() { const [count, updateCount] = useState(0); - updaters.push(updateCount); + updater = updateCount; return ; } ReactNoop.render(); expect(Scheduler).toFlushAndYield(['Count: 0']); expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]); - act(() => updaters[0](1)); + const firstUpdater = updater; + + act(() => firstUpdater(1)); expect(Scheduler).toHaveYielded(['Count: 1']); expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]); - act(() => updaters[0](count => count + 10)); + const secondUpdater = updater; + + act(() => firstUpdater(count => count + 10)); expect(Scheduler).toHaveYielded(['Count: 11']); expect(ReactNoop.getChildren()).toEqual([span('Count: 11')]); - expect(updaters).toEqual([updaters[0], updaters[0], updaters[0]]); + expect(firstUpdater).toBe(secondUpdater); }); it('warns on set after unmount', () => { @@ -476,7 +480,11 @@ describe('ReactHooksWithNoopRenderer', () => { , ); expect(() => - expect(Scheduler).toFlushAndYield(['Foo [0]', 'Bar', 'Foo [1]']), + expect(Scheduler).toFlushAndYield( + __DEV__ + ? ['Foo [0]', 'Bar', 'Foo [2]'] + : ['Foo [0]', 'Bar', 'Foo [1]'], + ), ).toErrorDev([ 'Cannot update a component (`Foo`) while rendering a ' + 'different component (`Bar`). To locate the bad setState() call inside `Bar`', @@ -491,7 +499,11 @@ describe('ReactHooksWithNoopRenderer', () => { , ); - expect(Scheduler).toFlushAndYield(['Foo [1]', 'Bar', 'Foo [2]']); + expect(Scheduler).toFlushAndYield( + __DEV__ + ? ['Foo [2]', 'Bar', 'Foo [4]'] + : ['Foo [1]', 'Bar', 'Foo [2]'], + ); }); }); diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js index f0393623c4ba..e4ade52f4eea 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js @@ -188,14 +188,13 @@ describe('ReactIncrementalErrorLogging', () => { expect(Scheduler).toFlushAndYield( [ 'render: 0', - __DEV__ && 'render: 0', // replay 'render: 1', - __DEV__ && 'render: 1', // replay + __DEV__ && 'render: 1', // replay due to invokeGuardedCallback // Retry one more time before handling error 'render: 1', - __DEV__ && 'render: 1', // replay + __DEV__ && 'render: 1', // replay due to invokeGuardedCallback 'componentWillUnmount: 0', ].filter(Boolean), diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalReflection-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalReflection-test.internal.js index fe594a2d4f5c..0f41be8d5686 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalReflection-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalReflection-test.internal.js @@ -11,15 +11,13 @@ 'use strict'; let React; -let ReactFeatureFlags; let ReactNoop; let Scheduler; describe('ReactIncrementalReflection', () => { beforeEach(() => { jest.resetModules(); - ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.internal.js index 8544542b8893..766c1e84b64f 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.internal.js @@ -11,15 +11,13 @@ 'use strict'; let React; -let ReactFeatureFlags; let ReactNoop; let Scheduler; describe('ReactIncrementalSideEffects', () => { beforeEach(() => { jest.resetModules(); - ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); @@ -897,12 +895,12 @@ describe('ReactIncrementalSideEffects', () => { constructor() { super(); this.state = {active: false}; - barInstances.push(this); } activate() { this.setState({active: true}); } render() { + barInstances.push(this); Scheduler.unstable_yieldValue('Bar'); return ; } diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js index 33533a754586..4c2b44d62307 100644 --- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js @@ -10,7 +10,7 @@ describe('ReactLazy', () => { beforeEach(() => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; PropTypes = require('prop-types'); React = require('react'); diff --git a/packages/react-reconciler/src/__tests__/ReactMemo-test.internal.js b/packages/react-reconciler/src/__tests__/ReactMemo-test.internal.js index 88a5a1b759a9..aa2774085dc1 100644 --- a/packages/react-reconciler/src/__tests__/ReactMemo-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactMemo-test.internal.js @@ -14,7 +14,6 @@ let PropTypes; let React; -let ReactFeatureFlags; let ReactNoop; let Suspense; let Scheduler; @@ -22,8 +21,7 @@ let Scheduler; describe('memo', () => { beforeEach(() => { jest.resetModules(); - ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + PropTypes = require('prop-types'); React = require('react'); ReactNoop = require('react-noop-renderer'); diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js index 22e4416468cf..58609e6fc4c0 100644 --- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js @@ -9,8 +9,6 @@ 'use strict'; -let ReactFeatureFlags = require('shared/ReactFeatureFlags'); - let React = require('react'); let useContext; let ReactNoop; @@ -20,8 +18,7 @@ let gen; describe('ReactNewContext', () => { beforeEach(() => { jest.resetModules(); - ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + React = require('react'); useContext = React.useContext; ReactNoop = require('react-noop-renderer'); @@ -1096,16 +1093,13 @@ describe('ReactNewContext', () => { // Get a new copy of ReactNoop jest.resetModules(); - ReactFeatureFlags = require('shared/ReactFeatureFlags'); React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); // Render the provider again using a different renderer ReactNoop.render(); - expect(Scheduler).toFlushAndYield( - __DEV__ ? ['Foo', 'Foo', 'Foo', 'Foo'] : ['Foo', 'Foo'], - ); + expect(Scheduler).toFlushAndYield(['Foo', 'Foo']); if (__DEV__) { expect(console.error.calls.argsFor(0)[0]).toContain( @@ -1481,6 +1475,8 @@ describe('ReactNewContext', () => { ReactNoop.render(); expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev([ + 'Context can only be read while React is rendering', + // A second warning comes from to setStates being added to the queue. 'Context can only be read while React is rendering', 'Cannot update during an existing state transition', ]); diff --git a/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.internal.js index d5dc4f01ffee..084194f34db8 100644 --- a/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.internal.js @@ -11,7 +11,6 @@ 'use strict'; let React; -let ReactFeatureFlags; let ReactNoop; let Scheduler; let ImmediatePriority; @@ -24,8 +23,7 @@ let runWithPriority; describe('ReactSchedulerIntegration', () => { beforeEach(() => { jest.resetModules(); - ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); @@ -417,8 +415,6 @@ describe( beforeEach(() => { jest.resetModules(); - ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; jest.mock('scheduler', () => { const actual = require.requireActual('scheduler/unstable_mock'); diff --git a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js index 8164c77adb95..5ece006e99d9 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js @@ -16,7 +16,7 @@ describe('ReactSuspense', () => { beforeEach(() => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; ReactFeatureFlags.enableSchedulerTracing = true; React = require('react'); diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseFuzz-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseFuzz-test.internal.js index 0e0c13a3230f..eabcb41be0e6 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseFuzz-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseFuzz-test.internal.js @@ -21,7 +21,7 @@ describe('ReactSuspenseFuzz', () => { beforeEach(() => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; React = require('react'); Suspense = React.Suspense; diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.internal.js index 6bb2972ee6dc..3ed8f664bde7 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.internal.js @@ -14,7 +14,7 @@ describe('ReactSuspenseList', () => { beforeEach(() => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; ReactFeatureFlags.enableSuspenseServerRenderer = true; React = require('react'); diff --git a/packages/react-reconciler/src/__tests__/ReactSuspensePlaceholder-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspensePlaceholder-test.internal.js index 012511d7654c..5b121c06babe 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspensePlaceholder-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspensePlaceholder-test.internal.js @@ -23,7 +23,7 @@ describe('ReactSuspensePlaceholder', () => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.enableProfilerTimer = true; ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; React = require('react'); diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js index 646ebd28afe8..e6005f514f66 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js @@ -20,7 +20,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; ReactFeatureFlags.flushSuspenseFallbacksInTests = false; React = require('react'); diff --git a/packages/react-reconciler/src/__tests__/ReactTransition-test.internal.js b/packages/react-reconciler/src/__tests__/ReactTransition-test.internal.js index 28fbca9f885e..c9f876a0a42a 100644 --- a/packages/react-reconciler/src/__tests__/ReactTransition-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactTransition-test.internal.js @@ -24,7 +24,7 @@ describe('ReactTransition', () => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.enableSchedulerTracing = true; ReactFeatureFlags.flushSuspenseFallbacksInTests = false; React = require('react'); diff --git a/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js b/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js index d9ff4ad3ac2d..fce1cd634e58 100644 --- a/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js +++ b/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js @@ -24,7 +24,7 @@ function loadModules() { jest.useFakeTimers(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.enableSchedulerTracing = true; ReactFeatureFlags.flushSuspenseFallbacksInTests = false; ReactFeatureFlags.enableProfilerTimer = true; diff --git a/packages/react-test-renderer/src/__tests__/ReactTestRendererAsync-test.internal.js b/packages/react-test-renderer/src/__tests__/ReactTestRendererAsync-test.internal.js index ab2377f47698..f83cbb8820be 100644 --- a/packages/react-test-renderer/src/__tests__/ReactTestRendererAsync-test.internal.js +++ b/packages/react-test-renderer/src/__tests__/ReactTestRendererAsync-test.internal.js @@ -11,15 +11,13 @@ 'use strict'; let React; -let ReactFeatureFlags; let ReactTestRenderer; let Scheduler; describe('ReactTestRendererAsync', () => { beforeEach(() => { jest.resetModules(); - ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + React = require('react'); ReactTestRenderer = require('react-test-renderer'); Scheduler = require('scheduler'); diff --git a/packages/react/src/__tests__/ReactDOMTracing-test.internal.js b/packages/react/src/__tests__/ReactDOMTracing-test.internal.js index 3f08e531e9e4..fa6be59c7d0b 100644 --- a/packages/react/src/__tests__/ReactDOMTracing-test.internal.js +++ b/packages/react/src/__tests__/ReactDOMTracing-test.internal.js @@ -25,7 +25,7 @@ let onWorkStopped; function loadModules() { ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.enableProfilerTimer = true; ReactFeatureFlags.enableSchedulerTracing = true; ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index eccf657795cc..1fce1caa623c 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -32,7 +32,7 @@ function loadModules({ useNoopRenderer = false, } = {}) { ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.deferPassiveEffectCleanupDuringUnmount = deferPassiveEffectCleanupDuringUnmount; ReactFeatureFlags.runAllPassiveEffectDestroysBeforeCreates = deferPassiveEffectCleanupDuringUnmount; ReactFeatureFlags.enableProfilerTimer = enableProfilerTimer; diff --git a/packages/react/src/__tests__/ReactProfilerDOM-test.internal.js b/packages/react/src/__tests__/ReactProfilerDOM-test.internal.js index 1152818abc19..b5509ad7de34 100644 --- a/packages/react/src/__tests__/ReactProfilerDOM-test.internal.js +++ b/packages/react/src/__tests__/ReactProfilerDOM-test.internal.js @@ -17,7 +17,7 @@ let Scheduler; function loadModules() { ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.enableProfilerTimer = true; ReactFeatureFlags.enableSchedulerTracing = true; diff --git a/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js b/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js index fa2650919c55..d2f52dea1b11 100644 --- a/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js +++ b/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js @@ -188,7 +188,7 @@ describe('ReactProfiler DevTools integration', () => { // Commit something root.update(); - expect(Scheduler).toFlushAndYield(__DEV__ ? ['A', 'A'] : ['A']); + expect(Scheduler).toFlushAndYield(['A']); expect(root).toMatchRenderedOutput('A'); // Advance time by many seconds, larger than the default expiration time @@ -200,7 +200,7 @@ describe('ReactProfiler DevTools integration', () => { // Update B should not instantly expire. expect(Scheduler).toFlushExpired([]); - expect(Scheduler).toFlushAndYield(__DEV__ ? ['B', 'B'] : ['B']); + expect(Scheduler).toFlushAndYield(['B']); expect(root).toMatchRenderedOutput('B'); }); }); diff --git a/packages/react/src/__tests__/forwardRef-test.internal.js b/packages/react/src/__tests__/forwardRef-test.internal.js index 31c8867d571c..d98dfabcad67 100644 --- a/packages/react/src/__tests__/forwardRef-test.internal.js +++ b/packages/react/src/__tests__/forwardRef-test.internal.js @@ -18,7 +18,7 @@ describe('forwardRef', () => { beforeEach(() => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; + ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; React = require('react'); ReactNoop = require('react-noop-renderer'); diff --git a/packages/scheduler/src/forks/SchedulerHostConfig.mock.js b/packages/scheduler/src/forks/SchedulerHostConfig.mock.js index cef9f1b2e102..070b31043a42 100644 --- a/packages/scheduler/src/forks/SchedulerHostConfig.mock.js +++ b/packages/scheduler/src/forks/SchedulerHostConfig.mock.js @@ -192,6 +192,12 @@ export function unstable_flushAll(): void { } export function unstable_yieldValue(value: mixed): void { + // eslint-disable-next-line react-internal/no-production-logging + if (console.log.name === 'disabledLog') { + // If console.log has been patched, we assume we're in render + // replaying and we ignore any values yielding in the second pass. + return; + } if (yieldedValues === null) { yieldedValues = [value]; } else { @@ -200,6 +206,12 @@ export function unstable_yieldValue(value: mixed): void { } export function unstable_advanceTime(ms: number) { + // eslint-disable-next-line react-internal/no-production-logging + if (console.log.name === 'disabledLog') { + // If console.log has been patched, we assume we're in render + // replaying and we ignore any time advancing in the second pass. + return; + } currentTime += ms; if (scheduledTimeout !== null && timeoutTime <= currentTime) { scheduledTimeout(currentTime); diff --git a/packages/shared/ConsolePatchingDev.js b/packages/shared/ConsolePatchingDev.js new file mode 100644 index 000000000000..41c16a761d24 --- /dev/null +++ b/packages/shared/ConsolePatchingDev.js @@ -0,0 +1,48 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +// Helpers to patch console.logs to avoid logging during side-effect free +// replaying on render function. This currently only patches the object +// lazily which won't cover if the log function was extracted eagerly. +// We could also eagerly patch the method. + +let prevLog; +let prevInfo; +let prevWarn; +let prevError; + +function disabledLog() {} + +export function disableLogs(): void { + if (__DEV__) { + /* eslint-disable react-internal/no-production-logging */ + prevLog = console.log; + prevInfo = console.info; + prevWarn = console.warn; + prevError = console.error; + // $FlowFixMe Flow thinks console is immutable. + console.log = console.info = console.warn = console.error = disabledLog; + /* eslint-enable react-internal/no-production-logging */ + } +} + +export function reenableLogs(): void { + if (__DEV__) { + /* eslint-disable react-internal/no-production-logging */ + // $FlowFixMe Flow thinks console is immutable. + console.log = prevLog; + // $FlowFixMe Flow thinks console is immutable. + console.info = prevInfo; + // $FlowFixMe Flow thinks console is immutable. + console.warn = prevWarn; + // $FlowFixMe Flow thinks console is immutable. + console.error = prevError; + /* eslint-enable react-internal/no-production-logging */ + } +} diff --git a/packages/use-subscription/src/__tests__/useSubscription-test.internal.js b/packages/use-subscription/src/__tests__/useSubscription-test.internal.js index 56e6c0ea0acc..52e15fd42822 100644 --- a/packages/use-subscription/src/__tests__/useSubscription-test.internal.js +++ b/packages/use-subscription/src/__tests__/useSubscription-test.internal.js @@ -22,9 +22,6 @@ describe('useSubscription', () => { jest.resetModules(); jest.mock('scheduler', () => require('scheduler/unstable_mock')); - const ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; - useSubscription = require('use-subscription').useSubscription; React = require('react'); ReactTestRenderer = require('react-test-renderer');