Disable console.logs in the second render pass of DEV mode double render (#18547)

* Disable console log during the second rerender

* Use the disabled log to avoid double yielding values in scheduler mock

* Reenable debugRenderPhaseSideEffectsForStrictMode in tests that can
This commit is contained in:
Sebastian Markbåge
2020-04-08 16:43:51 -07:00
committed by GitHub
parent b225d4f261
commit 5474a83e25
43 changed files with 221 additions and 162 deletions
@@ -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');
+2 -4
View File
@@ -391,7 +391,7 @@ describe('ReactART', () => {
</CurrentRendererContext.Provider>,
);
expect(Scheduler).toFlushAndYieldThrough(__DEV__ ? ['A', 'A'] : ['A']);
expect(Scheduler).toFlushAndYieldThrough(['A']);
ReactDOM.render(
<Surface>
@@ -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']);
});
@@ -24,7 +24,7 @@ describe('ReactCache', () => {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
React = require('react');
Suspense = React.Suspense;
@@ -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');
});
});
@@ -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');
@@ -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');
@@ -97,7 +97,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
React = require('react');
ReactDOM = require('react-dom');
@@ -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(...)',
]);
});
});
+3 -25
View File
@@ -1324,30 +1324,12 @@ describe('ReactUpdates', () => {
let hiddenDiv;
act(() => {
root.render(<Foo />);
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('<p>bar 0</p>');
});
@@ -1359,11 +1341,7 @@ describe('ReactUpdates', () => {
expect(hiddenDiv.innerHTML).toBe('<p>bar 0</p>');
// Run offscreen update
if (__DEV__) {
expect(Scheduler).toFlushAndYield(['Bar', 'Bar']);
} else {
expect(Scheduler).toFlushAndYield(['Bar']);
}
expect(Scheduler).toFlushAndYield(['Bar']);
expect(hiddenDiv.innerHTML).toBe('<p>bar 1</p>');
},
);
@@ -1701,12 +1701,7 @@ describe('DOMModernPluginEventSystem', () => {
const root = ReactDOM.createRoot(container);
root.render(<Test counter={0} />);
// 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(<Test counter={1} />);
// 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);
@@ -811,7 +811,7 @@ describe('DOMEventResponderSystem', () => {
const root = ReactDOM.createRoot(container);
root.render(<Test counter={0} />);
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(<Test counter={1} />);
// Yield before committing
expect(Scheduler).toFlushAndYieldThrough(
__DEV__ ? ['Test', 'Test'] : ['Test'],
);
expect(Scheduler).toFlushAndYieldThrough(['Test']);
// Click the button again
dispatchClickEvent(ref.current);
+60 -33
View File
@@ -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<Props, Data>(
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);
+22 -5
View File
@@ -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();
}
}
}
+14 -2
View File
@@ -107,6 +107,8 @@ import {
import invariant from 'shared/invariant';
import {getCurrentPriorityLevel} from './SchedulerWithReactIntegration';
import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev';
export type Update<State> = {|
expirationTime: ExpirationTime,
suspenseConfig: null | SuspenseConfig,
@@ -336,7 +338,12 @@ function getStateFromUpdate<State>(
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<State>(
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
) {
payload.call(instance, prevState, nextProps);
disableLogs();
try {
payload.call(instance, prevState, nextProps);
} finally {
reenableLogs();
}
}
}
partialState = payload.call(instance, prevState, nextProps);
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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');
@@ -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 <Text text={'Count: ' + count} />;
}
ReactNoop.render(<Counter />);
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', () => {
<Bar triggerUpdate={true} />
</>,
);
expect(Scheduler).toFlushAndYield(['Foo [1]', 'Bar', 'Foo [2]']);
expect(Scheduler).toFlushAndYield(
__DEV__
? ['Foo [2]', 'Bar', 'Foo [4]']
: ['Foo [1]', 'Bar', 'Foo [2]'],
);
});
});
@@ -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),
@@ -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');
@@ -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 <span prop={this.state.active ? 'X' : this.props.idx} />;
}
@@ -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');
@@ -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');
@@ -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(<App value={1} />);
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(<Cls />);
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',
]);
@@ -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');
@@ -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');
@@ -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;
@@ -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');
@@ -23,7 +23,7 @@ describe('ReactSuspensePlaceholder', () => {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
ReactFeatureFlags.enableProfilerTimer = true;
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
React = require('react');
@@ -20,7 +20,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
ReactFeatureFlags.flushSuspenseFallbacksInTests = false;
React = require('react');
@@ -24,7 +24,7 @@ describe('ReactTransition', () => {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
ReactFeatureFlags.enableSchedulerTracing = true;
ReactFeatureFlags.flushSuspenseFallbacksInTests = false;
React = require('react');
@@ -24,7 +24,7 @@ function loadModules() {
jest.useFakeTimers();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
ReactFeatureFlags.enableSchedulerTracing = true;
ReactFeatureFlags.flushSuspenseFallbacksInTests = false;
ReactFeatureFlags.enableProfilerTimer = true;
@@ -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');
@@ -25,7 +25,7 @@ let onWorkStopped;
function loadModules() {
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
ReactFeatureFlags.enableProfilerTimer = true;
ReactFeatureFlags.enableSchedulerTracing = true;
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
@@ -32,7 +32,7 @@ function loadModules({
useNoopRenderer = false,
} = {}) {
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
ReactFeatureFlags.deferPassiveEffectCleanupDuringUnmount = deferPassiveEffectCleanupDuringUnmount;
ReactFeatureFlags.runAllPassiveEffectDestroysBeforeCreates = deferPassiveEffectCleanupDuringUnmount;
ReactFeatureFlags.enableProfilerTimer = enableProfilerTimer;
@@ -17,7 +17,7 @@ let Scheduler;
function loadModules() {
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
ReactFeatureFlags.enableProfilerTimer = true;
ReactFeatureFlags.enableSchedulerTracing = true;
@@ -188,7 +188,7 @@ describe('ReactProfiler DevTools integration', () => {
// Commit something
root.update(<Text text="A" />);
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');
});
});
@@ -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');
@@ -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);
+48
View File
@@ -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 */
}
}
@@ -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');