Replace test renderer's fake Scheduler implementation with mock build (#14970)

* Replace test renderer's fake Scheduler implementation with mock build

The test renderer has its own mock implementation of the Scheduler
interface, with the ability to partially render work in tests. Now that
this functionality has been lifted into a proper mock Scheduler build,
we can use that instead.

* Fix Profiler tests in prod
This commit is contained in:
Andrew Clark
2019-02-28 10:50:38 -08:00
committed by GitHub
parent 53e787b45f
commit ccb2a8a44e
16 changed files with 592 additions and 755 deletions

View File

@@ -26,7 +26,8 @@ function captureAssertion(fn) {
}
function assertYieldsWereCleared(root) {
const actualYields = root.unstable_clearYields();
const Scheduler = root._Scheduler;
const actualYields = Scheduler.unstable_clearYields();
invariant(
actualYields.length === 0,
'Log of yielded values is not empty. ' +

View File

@@ -14,55 +14,15 @@ let createResource;
let React;
let ReactFeatureFlags;
let ReactTestRenderer;
let Scheduler;
let Suspense;
let TextResource;
let textResourceShouldFail;
let flushScheduledWork;
let evictLRU;
describe('ReactCache', () => {
beforeEach(() => {
jest.resetModules();
let currentPriorityLevel = 3;
jest.mock('scheduler', () => {
let callbacks = [];
return {
unstable_scheduleCallback(callback) {
const callbackIndex = callbacks.length;
callbacks.push(callback);
return {callbackIndex};
},
flushScheduledWork() {
while (callbacks.length) {
const callback = callbacks.pop();
callback();
}
},
unstable_ImmediatePriority: 1,
unstable_UserBlockingPriority: 2,
unstable_NormalPriority: 3,
unstable_LowPriority: 4,
unstable_IdlePriority: 5,
unstable_runWithPriority(priorityLevel, fn) {
const prevPriorityLevel = currentPriorityLevel;
currentPriorityLevel = priorityLevel;
try {
return fn();
} finally {
currentPriorityLevel = prevPriorityLevel;
}
},
unstable_getCurrentPriorityLevel() {
return currentPriorityLevel;
},
};
});
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
@@ -71,8 +31,7 @@ describe('ReactCache', () => {
ReactCache = require('react-cache');
createResource = ReactCache.unstable_createResource;
ReactTestRenderer = require('react-test-renderer');
flushScheduledWork = require('scheduler').flushScheduledWork;
evictLRU = flushScheduledWork;
Scheduler = require('scheduler');
TextResource = createResource(([text, ms = 0]) => {
let listeners = null;
@@ -86,16 +45,12 @@ describe('ReactCache', () => {
listeners = [{resolve, reject}];
setTimeout(() => {
if (textResourceShouldFail) {
ReactTestRenderer.unstable_yield(
`Promise rejected [${text}]`,
);
Scheduler.yieldValue(`Promise rejected [${text}]`);
status = 'rejected';
value = new Error('Failed to load: ' + text);
listeners.forEach(listener => listener.reject(value));
} else {
ReactTestRenderer.unstable_yield(
`Promise resolved [${text}]`,
);
Scheduler.yieldValue(`Promise resolved [${text}]`);
status = 'resolved';
value = text;
listeners.forEach(listener => listener.resolve(value));
@@ -123,7 +78,7 @@ describe('ReactCache', () => {
});
function Text(props) {
ReactTestRenderer.unstable_yield(props.text);
Scheduler.yieldValue(props.text);
return props.text;
}
@@ -131,13 +86,13 @@ describe('ReactCache', () => {
const text = props.text;
try {
TextResource.read([props.text, props.ms]);
ReactTestRenderer.unstable_yield(text);
Scheduler.yieldValue(text);
return text;
} catch (promise) {
if (typeof promise.then === 'function') {
ReactTestRenderer.unstable_yield(`Suspend! [${text}]`);
Scheduler.yieldValue(`Suspend! [${text}]`);
} else {
ReactTestRenderer.unstable_yield(`Error! [${text}]`);
Scheduler.yieldValue(`Error! [${text}]`);
}
throw promise;
}
@@ -201,7 +156,7 @@ describe('ReactCache', () => {
});
function App() {
ReactTestRenderer.unstable_yield('App');
Scheduler.yieldValue('App');
return BadTextResource.read(['Hi', 100]);
}
@@ -284,9 +239,7 @@ describe('ReactCache', () => {
expect(root).toMatchRenderedOutput('145');
// We've now rendered values 1, 2, 3, 4, 5, over our limit of 3. The least
// recently used values are 2 and 3. They will be evicted during the
// next sweep.
evictLRU();
// recently used values are 2 and 3. They should have been evicted.
root.update(
<Suspense fallback={<Text text="Loading..." />}>
@@ -368,13 +321,13 @@ describe('ReactCache', () => {
const text = props.text;
try {
const actualText = BadTextResource.read([props.text, props.ms]);
ReactTestRenderer.unstable_yield(actualText);
Scheduler.yieldValue(actualText);
return actualText;
} catch (promise) {
if (typeof promise.then === 'function') {
ReactTestRenderer.unstable_yield(`Suspend! [${text}]`);
Scheduler.yieldValue(`Suspend! [${text}]`);
} else {
ReactTestRenderer.unstable_yield(`Error! [${text}]`);
Scheduler.yieldValue(`Error! [${text}]`);
}
throw promise;
}

View File

@@ -5,6 +5,7 @@ describe('ErrorBoundaryReconciliation', () => {
let React;
let ReactFeatureFlags;
let ReactTestRenderer;
let Scheduler;
let span;
beforeEach(() => {
@@ -14,6 +15,7 @@ describe('ErrorBoundaryReconciliation', () => {
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
ReactTestRenderer = require('react-test-renderer');
React = require('react');
Scheduler = require('scheduler');
DidCatchErrorBoundary = class extends React.Component {
state = {error: null};
@@ -56,9 +58,7 @@ describe('ErrorBoundaryReconciliation', () => {
</ErrorBoundary>,
{unstable_isConcurrent: isConcurrent},
);
if (isConcurrent) {
renderer.unstable_flushAll();
}
Scheduler.flushAll();
expect(renderer).toMatchRenderedOutput(<span prop="BrokenRender" />);
expect(() => {
@@ -67,9 +67,7 @@ describe('ErrorBoundaryReconciliation', () => {
<BrokenRender fail={true} />
</ErrorBoundary>,
);
if (isConcurrent) {
renderer.unstable_flushAll();
}
Scheduler.flushAll();
}).toWarnDev(isConcurrent ? ['invalid', 'invalid'] : ['invalid']);
const Fallback = fallbackTagName;
expect(renderer).toMatchRenderedOutput(<Fallback prop="ErrorBoundary" />);

View File

@@ -15,6 +15,7 @@
let React;
let ReactFeatureFlags;
let ReactTestRenderer;
let Scheduler;
let ReactDOMServer;
let act;
@@ -28,6 +29,7 @@ describe('ReactHooks', () => {
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
React = require('react');
ReactTestRenderer = require('react-test-renderer');
Scheduler = require('scheduler');
ReactDOMServer = require('react-dom/server');
act = ReactTestRenderer.act;
});
@@ -53,7 +55,7 @@ describe('ReactHooks', () => {
const {useState, useLayoutEffect} = React;
function Child({text}) {
ReactTestRenderer.unstable_yield('Child: ' + text);
Scheduler.yieldValue('Child: ' + text);
return text;
}
@@ -66,9 +68,9 @@ describe('ReactHooks', () => {
setCounter2 = _setCounter2;
const text = `${counter1}, ${counter2}`;
ReactTestRenderer.unstable_yield(`Parent: ${text}`);
Scheduler.yieldValue(`Parent: ${text}`);
useLayoutEffect(() => {
ReactTestRenderer.unstable_yield(`Effect: ${text}`);
Scheduler.yieldValue(`Effect: ${text}`);
});
return <Child text={text} />;
}
@@ -161,7 +163,7 @@ describe('ReactHooks', () => {
const {useState, memo} = React;
function Child({text}) {
ReactTestRenderer.unstable_yield('Child: ' + text);
Scheduler.yieldValue('Child: ' + text);
return text;
}
@@ -174,7 +176,7 @@ describe('ReactHooks', () => {
setCounter2 = _setCounter2;
const text = `${counter1}, ${counter2} (${theme})`;
ReactTestRenderer.unstable_yield(`Parent: ${text}`);
Scheduler.yieldValue(`Parent: ${text}`);
return <Child text={text} />;
}
@@ -243,7 +245,7 @@ describe('ReactHooks', () => {
const [counter, _setCounter] = useState(0);
setCounter = _setCounter;
ReactTestRenderer.unstable_yield(`Count: ${counter}`);
Scheduler.yieldValue(`Count: ${counter}`);
return counter;
}
@@ -277,7 +279,7 @@ describe('ReactHooks', () => {
const [counter, _dispatch] = useReducer((s, a) => a, 0);
dispatch = _dispatch;
ReactTestRenderer.unstable_yield(`Count: ${counter}`);
Scheduler.yieldValue(`Count: ${counter}`);
return counter;
}
@@ -311,7 +313,7 @@ describe('ReactHooks', () => {
let setTheme;
function ThemeProvider({children}) {
const [theme, _setTheme] = useState('light');
ReactTestRenderer.unstable_yield('Theme: ' + theme);
Scheduler.yieldValue('Theme: ' + theme);
setTheme = _setTheme;
return (
<ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>
@@ -319,7 +321,7 @@ describe('ReactHooks', () => {
}
function Child({text}) {
ReactTestRenderer.unstable_yield('Child: ' + text);
Scheduler.yieldValue('Child: ' + text);
return text;
}
@@ -331,9 +333,9 @@ describe('ReactHooks', () => {
const theme = useContext(ThemeContext);
const text = `${counter} (${theme})`;
ReactTestRenderer.unstable_yield(`Parent: ${text}`);
Scheduler.yieldValue(`Parent: ${text}`);
useLayoutEffect(() => {
ReactTestRenderer.unstable_yield(`Effect: ${text}`);
Scheduler.yieldValue(`Effect: ${text}`);
});
return <Child text={text} />;
}
@@ -392,7 +394,7 @@ describe('ReactHooks', () => {
const {useState, useLayoutEffect} = React;
function Child({text}) {
ReactTestRenderer.unstable_yield('Child: ' + text);
Scheduler.yieldValue('Child: ' + text);
return text;
}
@@ -400,9 +402,9 @@ describe('ReactHooks', () => {
function Parent() {
const [counter, _setCounter] = useState(0);
setCounter = _setCounter;
ReactTestRenderer.unstable_yield('Parent: ' + counter);
Scheduler.yieldValue('Parent: ' + counter);
useLayoutEffect(() => {
ReactTestRenderer.unstable_yield('Effect: ' + counter);
Scheduler.yieldValue('Effect: ' + counter);
});
return <Child text={counter} />;
}
@@ -470,7 +472,7 @@ describe('ReactHooks', () => {
const {useState} = React;
function Child({text}) {
ReactTestRenderer.unstable_yield('Child: ' + text);
Scheduler.yieldValue('Child: ' + text);
return text;
}
@@ -478,7 +480,7 @@ describe('ReactHooks', () => {
function Parent() {
const [counter, _setCounter] = useState(0);
setCounter = _setCounter;
ReactTestRenderer.unstable_yield('Parent: ' + counter);
Scheduler.yieldValue('Parent: ' + counter);
return <Child text={counter} />;
}
@@ -489,9 +491,7 @@ describe('ReactHooks', () => {
const update = value => {
setCounter(previous => {
ReactTestRenderer.unstable_yield(
`Compute state (${previous} -> ${value})`,
);
Scheduler.yieldValue(`Compute state (${previous} -> ${value})`);
return value;
});
};
@@ -530,7 +530,7 @@ describe('ReactHooks', () => {
const {useState} = React;
function Child({text}) {
ReactTestRenderer.unstable_yield('Child: ' + text);
Scheduler.yieldValue('Child: ' + text);
return text;
}
@@ -538,7 +538,7 @@ describe('ReactHooks', () => {
function Parent() {
const [counter, _setCounter] = useState(1);
setCounter = _setCounter;
ReactTestRenderer.unstable_yield('Parent: ' + counter);
Scheduler.yieldValue('Parent: ' + counter);
return <Child text={counter} />;
}
@@ -550,9 +550,7 @@ describe('ReactHooks', () => {
const update = compute => {
setCounter(previous => {
const value = compute(previous);
ReactTestRenderer.unstable_yield(
`Compute state (${previous} -> ${value})`,
);
Scheduler.yieldValue(`Compute state (${previous} -> ${value})`);
return value;
});
};
@@ -590,9 +588,7 @@ describe('ReactHooks', () => {
const {useLayoutEffect} = React;
function App(props) {
useLayoutEffect(() => {
ReactTestRenderer.unstable_yield(
'Did commit: ' + props.dependencies.join(', '),
);
Scheduler.yieldValue('Did commit: ' + props.dependencies.join(', '));
}, props.dependencies);
return props.dependencies;
}
@@ -613,7 +609,7 @@ describe('ReactHooks', () => {
const {useMemo} = React;
function App({text, hasDeps}) {
const resolvedText = useMemo(() => {
ReactTestRenderer.unstable_yield('Compute');
Scheduler.yieldValue('Compute');
return text.toUpperCase();
}, hasDeps ? null : [text]);
return resolvedText;

View File

@@ -1,6 +1,7 @@
let PropTypes;
let React;
let ReactTestRenderer;
let Scheduler;
let ReactFeatureFlags;
let Suspense;
let lazy;
@@ -16,10 +17,11 @@ describe('ReactLazy', () => {
Suspense = React.Suspense;
lazy = React.lazy;
ReactTestRenderer = require('react-test-renderer');
Scheduler = require('scheduler');
});
function Text(props) {
ReactTestRenderer.unstable_yield(props.text);
Scheduler.yieldValue(props.text);
return props.text;
}
@@ -203,10 +205,10 @@ describe('ReactLazy', () => {
it('mount and reorder', async () => {
class Child extends React.Component {
componentDidMount() {
ReactTestRenderer.unstable_yield('Did mount: ' + this.props.label);
Scheduler.yieldValue('Did mount: ' + this.props.label);
}
componentDidUpdate() {
ReactTestRenderer.unstable_yield('Did update: ' + this.props.label);
Scheduler.yieldValue('Did update: ' + this.props.label);
}
render() {
return <Text text={this.props.label} />;
@@ -287,7 +289,7 @@ describe('ReactLazy', () => {
it('resolves defaultProps without breaking memoization', async () => {
function LazyImpl(props) {
ReactTestRenderer.unstable_yield('Lazy');
Scheduler.yieldValue('Lazy');
return (
<React.Fragment>
<Text text={props.siblingText} />
@@ -337,44 +339,38 @@ describe('ReactLazy', () => {
state = {};
static getDerivedStateFromProps(props) {
ReactTestRenderer.unstable_yield(
`getDerivedStateFromProps: ${props.text}`,
);
Scheduler.yieldValue(`getDerivedStateFromProps: ${props.text}`);
return null;
}
constructor(props) {
super(props);
ReactTestRenderer.unstable_yield(`constructor: ${this.props.text}`);
Scheduler.yieldValue(`constructor: ${this.props.text}`);
}
componentDidMount() {
ReactTestRenderer.unstable_yield(
`componentDidMount: ${this.props.text}`,
);
Scheduler.yieldValue(`componentDidMount: ${this.props.text}`);
}
componentDidUpdate(prevProps) {
ReactTestRenderer.unstable_yield(
Scheduler.yieldValue(
`componentDidUpdate: ${prevProps.text} -> ${this.props.text}`,
);
}
componentWillUnmount() {
ReactTestRenderer.unstable_yield(
`componentWillUnmount: ${this.props.text}`,
);
Scheduler.yieldValue(`componentWillUnmount: ${this.props.text}`);
}
shouldComponentUpdate(nextProps) {
ReactTestRenderer.unstable_yield(
Scheduler.yieldValue(
`shouldComponentUpdate: ${this.props.text} -> ${nextProps.text}`,
);
return true;
}
getSnapshotBeforeUpdate(prevProps) {
ReactTestRenderer.unstable_yield(
Scheduler.yieldValue(
`getSnapshotBeforeUpdate: ${prevProps.text} -> ${this.props.text}`,
);
return null;
@@ -443,19 +439,17 @@ describe('ReactLazy', () => {
state = {};
UNSAFE_componentWillMount() {
ReactTestRenderer.unstable_yield(
`UNSAFE_componentWillMount: ${this.props.text}`,
);
Scheduler.yieldValue(`UNSAFE_componentWillMount: ${this.props.text}`);
}
UNSAFE_componentWillUpdate(nextProps) {
ReactTestRenderer.unstable_yield(
Scheduler.yieldValue(
`UNSAFE_componentWillUpdate: ${this.props.text} -> ${nextProps.text}`,
);
}
UNSAFE_componentWillReceiveProps(nextProps) {
ReactTestRenderer.unstable_yield(
Scheduler.yieldValue(
`UNSAFE_componentWillReceiveProps: ${this.props.text} -> ${
nextProps.text
}`,
@@ -512,7 +506,7 @@ describe('ReactLazy', () => {
it('resolves defaultProps on the outer wrapper but warns', async () => {
function T(props) {
ReactTestRenderer.unstable_yield(props.inner + ' ' + props.outer);
Scheduler.yieldValue(props.inner + ' ' + props.outer);
return props.inner + ' ' + props.outer;
}
T.defaultProps = {inner: 'Hi'};
@@ -580,9 +574,7 @@ describe('ReactLazy', () => {
<BadLazy />
</Suspense>,
);
expect(() => {
root.unstable_flushAll();
}).toThrow(
expect(Scheduler).toFlushAndThrow(
'Element type is invalid. Received a promise that resolves to: 42. ' +
'Lazy element type must resolve to a class or function.',
);
@@ -610,9 +602,7 @@ describe('ReactLazy', () => {
<Lazy2 text="Hello" />
</Suspense>,
);
expect(() => {
root.unstable_flushAll();
}).toThrow(
expect(Scheduler).toFlushAndThrow(
'Element type is invalid. Received a promise that resolves to: [object Object]. ' +
'Lazy element type must resolve to a class or function.' +
(__DEV__
@@ -659,10 +649,11 @@ describe('ReactLazy', () => {
// Mount
await Promise.resolve();
expect(() => {
root.unstable_flushAll();
}).toWarnDev(
expect(Scheduler);
Scheduler.flushAll();
}).toWarnDev([
'Invalid prop `inner` of type `string` supplied to `Add`, expected `number`.',
);
]);
expect(root).toMatchRenderedOutput('22');
// Update
@@ -672,7 +663,7 @@ describe('ReactLazy', () => {
<LazyAdd inner={false} outer={false} />
</Suspense>,
);
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev(
'Invalid prop `inner` of type `boolean` supplied to `Add`, expected `number`.',
);
@@ -844,7 +835,7 @@ describe('ReactLazy', () => {
// Mount
await Promise.resolve();
expect(() => {
root.unstable_flushAll();
expect(Scheduler).toFlushAndYield(['Inner default text']);
}).toWarnDev(
'The prop `text` is marked as required in `T`, but its value is `undefined`',
);
@@ -857,7 +848,7 @@ describe('ReactLazy', () => {
<LazyText text={null} />
</Suspense>,
);
root.unstable_flushAll();
expect(Scheduler).toFlushAndYield([null]);
}).toWarnDev(
'The prop `text` is marked as required in `T`, but its value is `null`',
);
@@ -866,7 +857,7 @@ describe('ReactLazy', () => {
it('includes lazy-loaded component in warning stack', async () => {
const LazyFoo = lazy(() => {
ReactTestRenderer.unstable_yield('Started loading');
Scheduler.yieldValue('Started loading');
const Foo = props => <div>{[<Text text="A" />, <Text text="B" />]}</div>;
return fakeImport(Foo);
});
@@ -909,7 +900,7 @@ describe('ReactLazy', () => {
}
return fakeImport(
React.forwardRef((props, ref) => {
ReactTestRenderer.unstable_yield('forwardRef');
Scheduler.yieldValue('forwardRef');
return <Bar ref={ref} />;
}),
);
@@ -959,7 +950,7 @@ describe('ReactLazy', () => {
// Mount
await Promise.resolve();
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput('4');
// Update (shallowly equal)
@@ -968,7 +959,7 @@ describe('ReactLazy', () => {
<LazyAdd outer={2} />
</Suspense>,
);
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput('4');
// Update
@@ -977,7 +968,7 @@ describe('ReactLazy', () => {
<LazyAdd outer={3} />
</Suspense>,
);
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput('5');
// Update (shallowly equal)
@@ -986,7 +977,7 @@ describe('ReactLazy', () => {
<LazyAdd outer={3} />
</Suspense>,
);
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput('5');
// Update (explicit props)
@@ -995,7 +986,7 @@ describe('ReactLazy', () => {
<LazyAdd outer={1} inner={1} />
</Suspense>,
);
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput('2');
// Update (explicit props, shallowly equal)
@@ -1004,7 +995,7 @@ describe('ReactLazy', () => {
<LazyAdd outer={1} inner={1} />
</Suspense>,
);
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput('2');
// Update
@@ -1013,7 +1004,7 @@ describe('ReactLazy', () => {
<LazyAdd outer={1} />
</Suspense>,
);
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput('3');
});
@@ -1043,7 +1034,7 @@ describe('ReactLazy', () => {
// Mount
await Promise.resolve();
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput('4');
// Update
@@ -1052,7 +1043,7 @@ describe('ReactLazy', () => {
<LazyAdd outer={3} />
</Suspense>,
);
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput('5');
// Update
@@ -1061,7 +1052,7 @@ describe('ReactLazy', () => {
<LazyAdd />
</Suspense>,
);
root.unstable_flushAll();
expect(Scheduler).toFlushWithoutYielding();
expect(root).toMatchRenderedOutput('2');
});

View File

@@ -1,12 +1,11 @@
let React;
let ReactTestRenderer;
let ReactFeatureFlags;
let Scheduler;
let ReactCache;
let Suspense;
let act;
// let JestReact;
let TextResource;
let textResourceShouldFail;
@@ -21,7 +20,7 @@ describe('ReactSuspense', () => {
React = require('react');
ReactTestRenderer = require('react-test-renderer');
act = ReactTestRenderer.act;
// JestReact = require('jest-react');
Scheduler = require('scheduler');
ReactCache = require('react-cache');
Suspense = React.Suspense;
@@ -38,16 +37,12 @@ describe('ReactSuspense', () => {
listeners = [{resolve, reject}];
setTimeout(() => {
if (textResourceShouldFail) {
ReactTestRenderer.unstable_yield(
`Promise rejected [${text}]`,
);
Scheduler.yieldValue(`Promise rejected [${text}]`);
status = 'rejected';
value = new Error('Failed to load: ' + text);
listeners.forEach(listener => listener.reject(value));
} else {
ReactTestRenderer.unstable_yield(
`Promise resolved [${text}]`,
);
Scheduler.yieldValue(`Promise resolved [${text}]`);
status = 'resolved';
value = text;
listeners.forEach(listener => listener.resolve(value));
@@ -74,7 +69,7 @@ describe('ReactSuspense', () => {
});
function Text(props) {
ReactTestRenderer.unstable_yield(props.text);
Scheduler.yieldValue(props.text);
return props.text;
}
@@ -82,13 +77,13 @@ describe('ReactSuspense', () => {
const text = props.text;
try {
TextResource.read([props.text, props.ms]);
ReactTestRenderer.unstable_yield(text);
Scheduler.yieldValue(text);
return text;
} catch (promise) {
if (typeof promise.then === 'function') {
ReactTestRenderer.unstable_yield(`Suspend! [${text}]`);
Scheduler.yieldValue(`Suspend! [${text}]`);
} else {
ReactTestRenderer.unstable_yield(`Error! [${text}]`);
Scheduler.yieldValue(`Error! [${text}]`);
}
throw promise;
}
@@ -96,12 +91,12 @@ describe('ReactSuspense', () => {
it('suspends rendering and continues later', () => {
function Bar(props) {
ReactTestRenderer.unstable_yield('Bar');
Scheduler.yieldValue('Bar');
return props.children;
}
function Foo() {
ReactTestRenderer.unstable_yield('Foo');
Scheduler.yieldValue('Foo');
return (
<Suspense fallback={<Text text="Loading..." />}>
<Bar>
@@ -208,10 +203,10 @@ describe('ReactSuspense', () => {
function Async() {
if (!didResolve) {
ReactTestRenderer.unstable_yield('Suspend!');
Scheduler.yieldValue('Suspend!');
throw thenable;
}
ReactTestRenderer.unstable_yield('Async');
Scheduler.yieldValue('Async');
return 'Async';
}
@@ -243,10 +238,10 @@ describe('ReactSuspense', () => {
it('mounts a lazy class component in non-concurrent mode', async () => {
class Class extends React.Component {
componentDidMount() {
ReactTestRenderer.unstable_yield('Did mount: ' + this.props.label);
Scheduler.yieldValue('Did mount: ' + this.props.label);
}
componentDidUpdate() {
ReactTestRenderer.unstable_yield('Did update: ' + this.props.label);
Scheduler.yieldValue('Did update: ' + this.props.label);
}
render() {
return <Text text={this.props.label} />;
@@ -304,7 +299,7 @@ describe('ReactSuspense', () => {
});
it('throws if tree suspends and none of the Suspense ancestors have a fallback', () => {
const root = ReactTestRenderer.create(
ReactTestRenderer.create(
<Suspense>
<AsyncText text="Hi" ms={1000} />
</Suspense>,
@@ -313,34 +308,23 @@ describe('ReactSuspense', () => {
},
);
let err;
try {
root.unstable_flushAll();
} catch (e) {
err = e;
}
expect(err.message.replace(/at .+?:\d+/g, 'at **')).toBe(
'AsyncText suspended while rendering, but no fallback UI was specified.\n' +
'\n' +
'Add a <Suspense fallback=...> component higher in the tree to provide ' +
'a loading indicator or placeholder to display.\n' +
(__DEV__ ? ' in AsyncText (at **)\n' : ' in AsyncText\n') +
(__DEV__ ? ' in Suspense (at **)' : ' in Suspense'),
expect(Scheduler).toFlushAndThrow(
'AsyncText suspended while rendering, but no fallback UI was specified.',
);
expect(ReactTestRenderer).toHaveYielded(['Suspend! [Hi]', 'Suspend! [Hi]']);
expect(Scheduler).toHaveYielded(['Suspend! [Hi]', 'Suspend! [Hi]']);
});
describe('outside concurrent mode', () => {
it('a mounted class component can suspend without losing state', () => {
class TextWithLifecycle extends React.Component {
componentDidMount() {
ReactTestRenderer.unstable_yield(`Mount [${this.props.text}]`);
Scheduler.yieldValue(`Mount [${this.props.text}]`);
}
componentDidUpdate() {
ReactTestRenderer.unstable_yield(`Update [${this.props.text}]`);
Scheduler.yieldValue(`Update [${this.props.text}]`);
}
componentWillUnmount() {
ReactTestRenderer.unstable_yield(`Unmount [${this.props.text}]`);
Scheduler.yieldValue(`Unmount [${this.props.text}]`);
}
render() {
return <Text {...this.props} />;
@@ -351,17 +335,15 @@ describe('ReactSuspense', () => {
class AsyncTextWithLifecycle extends React.Component {
state = {step: 1};
componentDidMount() {
ReactTestRenderer.unstable_yield(
`Mount [${this.props.text}:${this.state.step}]`,
);
Scheduler.yieldValue(`Mount [${this.props.text}:${this.state.step}]`);
}
componentDidUpdate() {
ReactTestRenderer.unstable_yield(
Scheduler.yieldValue(
`Update [${this.props.text}:${this.state.step}]`,
);
}
componentWillUnmount() {
ReactTestRenderer.unstable_yield(
Scheduler.yieldValue(
`Unmount [${this.props.text}:${this.state.step}]`,
);
}
@@ -371,13 +353,13 @@ describe('ReactSuspense', () => {
const ms = this.props.ms;
try {
TextResource.read([text, ms]);
ReactTestRenderer.unstable_yield(text);
Scheduler.yieldValue(text);
return text;
} catch (promise) {
if (typeof promise.then === 'function') {
ReactTestRenderer.unstable_yield(`Suspend! [${text}]`);
Scheduler.yieldValue(`Suspend! [${text}]`);
} else {
ReactTestRenderer.unstable_yield(`Error! [${text}]`);
Scheduler.yieldValue(`Error! [${text}]`);
}
throw promise;
}
@@ -556,20 +538,20 @@ describe('ReactSuspense', () => {
it('suspends in a class that has componentWillUnmount and is then deleted', () => {
class AsyncTextWithUnmount extends React.Component {
componentWillUnmount() {
ReactTestRenderer.unstable_yield('will unmount');
Scheduler.yieldValue('will unmount');
}
render() {
const text = this.props.text;
const ms = this.props.ms;
try {
TextResource.read([text, ms]);
ReactTestRenderer.unstable_yield(text);
Scheduler.yieldValue(text);
return text;
} catch (promise) {
if (typeof promise.then === 'function') {
ReactTestRenderer.unstable_yield(`Suspend! [${text}]`);
Scheduler.yieldValue(`Suspend! [${text}]`);
} else {
ReactTestRenderer.unstable_yield(`Error! [${text}]`);
Scheduler.yieldValue(`Error! [${text}]`);
}
throw promise;
}
@@ -600,20 +582,20 @@ describe('ReactSuspense', () => {
useLayoutEffect(
() => {
ReactTestRenderer.unstable_yield('Did commit: ' + text);
Scheduler.yieldValue('Did commit: ' + text);
},
[text],
);
try {
TextResource.read([props.text, props.ms]);
ReactTestRenderer.unstable_yield(text);
Scheduler.yieldValue(text);
return text;
} catch (promise) {
if (typeof promise.then === 'function') {
ReactTestRenderer.unstable_yield(`Suspend! [${text}]`);
Scheduler.yieldValue(`Suspend! [${text}]`);
} else {
ReactTestRenderer.unstable_yield(`Error! [${text}]`);
Scheduler.yieldValue(`Error! [${text}]`);
}
throw promise;
}
@@ -840,13 +822,13 @@ describe('ReactSuspense', () => {
const fullText = `${text}:${step}`;
try {
TextResource.read([fullText, ms]);
ReactTestRenderer.unstable_yield(fullText);
Scheduler.yieldValue(fullText);
return fullText;
} catch (promise) {
if (typeof promise.then === 'function') {
ReactTestRenderer.unstable_yield(`Suspend! [${fullText}]`);
Scheduler.yieldValue(`Suspend! [${fullText}]`);
} else {
ReactTestRenderer.unstable_yield(`Error! [${fullText}]`);
Scheduler.yieldValue(`Error! [${fullText}]`);
}
throw promise;
}

View File

@@ -1,6 +1,7 @@
let React;
let Suspense;
let ReactTestRenderer;
let Scheduler;
let ReactFeatureFlags;
let Random;
@@ -26,6 +27,7 @@ describe('ReactSuspenseFuzz', () => {
React = require('react');
Suspense = React.Suspense;
ReactTestRenderer = require('react-test-renderer');
Scheduler = require('scheduler');
Random = require('random-seed');
});
@@ -55,7 +57,7 @@ describe('ReactSuspenseFuzz', () => {
};
const timeoutID = setTimeout(() => {
pendingTasks.delete(task);
ReactTestRenderer.unstable_yield(task.label);
Scheduler.yieldValue(task.label);
setStep(i + 1);
}, remountAfter);
pendingTasks.add(task);
@@ -88,7 +90,7 @@ describe('ReactSuspenseFuzz', () => {
};
const timeoutID = setTimeout(() => {
pendingTasks.delete(task);
ReactTestRenderer.unstable_yield(task.label);
Scheduler.yieldValue(task.label);
setStep([i + 1, suspendFor]);
}, beginAfter);
pendingTasks.add(task);
@@ -120,24 +122,24 @@ describe('ReactSuspenseFuzz', () => {
setTimeout(() => {
cache.set(fullText, fullText);
pendingTasks.delete(task);
ReactTestRenderer.unstable_yield(task.label);
Scheduler.yieldValue(task.label);
resolve();
}, delay);
},
};
cache.set(fullText, thenable);
ReactTestRenderer.unstable_yield(`Suspended! [${fullText}]`);
Scheduler.yieldValue(`Suspended! [${fullText}]`);
throw thenable;
} else if (typeof resolvedText.then === 'function') {
const thenable = resolvedText;
ReactTestRenderer.unstable_yield(`Suspended! [${fullText}]`);
Scheduler.yieldValue(`Suspended! [${fullText}]`);
throw thenable;
}
} else {
resolvedText = fullText;
}
ReactTestRenderer.unstable_yield(resolvedText);
Scheduler.yieldValue(resolvedText);
return resolvedText;
}
@@ -151,7 +153,7 @@ describe('ReactSuspenseFuzz', () => {
{children}
</ShouldSuspendContext.Provider>,
);
root.unstable_flushAll();
Scheduler.unstable_flushWithoutYielding();
let elapsedTime = 0;
while (pendingTasks && pendingTasks.size > 0) {
@@ -159,7 +161,7 @@ describe('ReactSuspenseFuzz', () => {
throw new Error('Something did not resolve properly.');
}
ReactTestRenderer.act(() => jest.advanceTimersByTime(1000));
root.unstable_flushAll();
Scheduler.unstable_flushWithoutYielding();
}
return root.toJSON();
@@ -189,9 +191,7 @@ describe('ReactSuspenseFuzz', () => {
const concurrentOutput = renderToRoot(concurrentRoot, children);
expect(concurrentOutput).toEqual(expectedOutput);
concurrentRoot.unmount();
concurrentRoot.unstable_flushAll();
ReactTestRenderer.unstable_clearYields();
Scheduler.unstable_flushWithoutYielding();
}
function pickRandomWeighted(rand, options) {

View File

@@ -19,11 +19,10 @@ runPlaceholderTests('ReactSuspensePlaceholder (persistence)', () =>
);
function runPlaceholderTests(suiteLabel, loadReactNoop) {
let advanceTimeBy;
let mockNow;
let Profiler;
let React;
let ReactTestRenderer;
let Scheduler;
let ReactFeatureFlags;
let ReactCache;
let Suspense;
@@ -34,20 +33,13 @@ function runPlaceholderTests(suiteLabel, loadReactNoop) {
beforeEach(() => {
jest.resetModules();
let currentTime = 0;
mockNow = jest.fn().mockImplementation(() => currentTime);
global.Date.now = mockNow;
advanceTimeBy = amount => {
currentTime += amount;
};
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
ReactFeatureFlags.enableProfilerTimer = true;
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
React = require('react');
ReactTestRenderer = require('react-test-renderer');
ReactTestRenderer.unstable_setNowImplementation(mockNow);
Scheduler = require('scheduler');
ReactCache = require('react-cache');
Profiler = React.unstable_Profiler;
@@ -65,16 +57,12 @@ function runPlaceholderTests(suiteLabel, loadReactNoop) {
listeners = [{resolve, reject}];
setTimeout(() => {
if (textResourceShouldFail) {
ReactTestRenderer.unstable_yield(
`Promise rejected [${text}]`,
);
Scheduler.yieldValue(`Promise rejected [${text}]`);
status = 'rejected';
value = new Error('Failed to load: ' + text);
listeners.forEach(listener => listener.reject(value));
} else {
ReactTestRenderer.unstable_yield(
`Promise resolved [${text}]`,
);
Scheduler.yieldValue(`Promise resolved [${text}]`);
status = 'resolved';
value = text;
listeners.forEach(listener => listener.resolve(value));
@@ -101,22 +89,22 @@ function runPlaceholderTests(suiteLabel, loadReactNoop) {
});
function Text({fakeRenderDuration = 0, text = 'Text'}) {
advanceTimeBy(fakeRenderDuration);
ReactTestRenderer.unstable_yield(text);
Scheduler.advanceTime(fakeRenderDuration);
Scheduler.yieldValue(text);
return text;
}
function AsyncText({fakeRenderDuration = 0, ms, text}) {
advanceTimeBy(fakeRenderDuration);
Scheduler.advanceTime(fakeRenderDuration);
try {
TextResource.read([text, ms]);
ReactTestRenderer.unstable_yield(text);
Scheduler.yieldValue(text);
return text;
} catch (promise) {
if (typeof promise.then === 'function') {
ReactTestRenderer.unstable_yield(`Suspend! [${text}]`);
Scheduler.yieldValue(`Suspend! [${text}]`);
} else {
ReactTestRenderer.unstable_yield(`Error! [${text}]`);
Scheduler.yieldValue(`Error! [${text}]`);
}
throw promise;
}
@@ -126,7 +114,7 @@ function runPlaceholderTests(suiteLabel, loadReactNoop) {
class HiddenText extends React.PureComponent {
render() {
const text = this.props.text;
ReactTestRenderer.unstable_yield(text);
Scheduler.yieldValue(text);
return <span hidden={true}>{text}</span>;
}
}
@@ -243,19 +231,19 @@ function runPlaceholderTests(suiteLabel, loadReactNoop) {
onRender = jest.fn();
const Fallback = () => {
ReactTestRenderer.unstable_yield('Fallback');
advanceTimeBy(10);
Scheduler.yieldValue('Fallback');
Scheduler.advanceTime(10);
return 'Loading...';
};
const Suspending = () => {
ReactTestRenderer.unstable_yield('Suspending');
advanceTimeBy(2);
Scheduler.yieldValue('Suspending');
Scheduler.advanceTime(2);
return <AsyncText ms={1000} text="Loaded" fakeRenderDuration={1} />;
};
App = ({shouldSuspend, text = 'Text', textRenderDuration = 5}) => {
ReactTestRenderer.unstable_yield('App');
Scheduler.yieldValue('App');
return (
<Profiler id="root" onRender={onRender}>
<Suspense maxDuration={500} fallback={<Fallback />}>

View File

@@ -7,13 +7,8 @@
* @flow
*/
import * as Scheduler from 'scheduler/unstable_mock';
import warning from 'shared/warning';
import {
nowImplementation as TestRendererSchedulingNowImplementation,
scheduleDeferredCallback as TestRendererSchedulingScheduleDeferredCallback,
cancelDeferredCallback as TestRendererSchedulingCancelDeferredCallback,
shouldYield as TestRendererSchedulingShouldYield,
} from './ReactTestRendererScheduling';
export type Type = string;
export type Props = Object;
@@ -202,16 +197,16 @@ export function createTextInstance(
export const isPrimaryRenderer = false;
// This approach enables `now` to be mocked by tests,
// Even after the reconciler has initialized and read host config values.
export const now = () => TestRendererSchedulingNowImplementation();
export const scheduleDeferredCallback = TestRendererSchedulingScheduleDeferredCallback;
export const cancelDeferredCallback = TestRendererSchedulingCancelDeferredCallback;
export const shouldYield = TestRendererSchedulingShouldYield;
export const now = Scheduler.unstable_now;
export const scheduleDeferredCallback = Scheduler.unstable_scheduleCallback;
export const cancelDeferredCallback = Scheduler.unstable_cancelCallback;
export const shouldYield = Scheduler.unstable_shouldYield;
export const scheduleTimeout = setTimeout;
export const cancelTimeout = clearTimeout;
export const noTimeout = -1;
export const schedulePassiveEffects = scheduleDeferredCallback;
export const cancelPassiveEffects = cancelDeferredCallback;
export const schedulePassiveEffects = Scheduler.unstable_scheduleCallback;
export const cancelPassiveEffects = Scheduler.unstable_cancelCallback;
// -------------------
// Mutation

View File

@@ -11,6 +11,7 @@ import type {Fiber} from 'react-reconciler/src/ReactFiber';
import type {FiberRoot} from 'react-reconciler/src/ReactFiberRoot';
import type {Instance, TextInstance} from './ReactTestHostConfig';
import * as Scheduler from 'scheduler/unstable_mock';
import {
getPublicRootInstance,
createContainer,
@@ -42,13 +43,6 @@ import ReactVersion from 'shared/ReactVersion';
import warningWithoutStack from 'shared/warningWithoutStack';
import {getPublicInstance} from './ReactTestHostConfig';
import {
flushAll,
flushNumberOfYields,
clearYields,
setNowImplementation,
yieldValue,
} from './ReactTestRendererScheduling';
type TestRendererOptions = {
createNodeMock: (element: React$Element<any>) => any,
@@ -430,6 +424,8 @@ function propsMatch(props: Object, filter: Object): boolean {
}
const ReactTestRendererFiber = {
_Scheduler: Scheduler,
create(element: React$Element<any>, options: TestRendererOptions) {
let createNodeMock = defaultTestOptions.createNodeMock;
let isConcurrent = false;
@@ -455,6 +451,8 @@ const ReactTestRendererFiber = {
updateContainer(element, root, null, null);
const entry = {
_Scheduler: Scheduler,
root: undefined, // makes flow happy
// we define a 'getter' for 'root' below using 'Object.defineProperty'
toJSON(): Array<ReactTestRendererNode> | ReactTestRendererNode | null {
@@ -518,13 +516,9 @@ const ReactTestRendererFiber = {
return getPublicRootInstance(root);
},
unstable_flushAll: flushAll,
unstable_flushSync<T>(fn: () => T): T {
clearYields();
return flushSync(fn);
},
unstable_flushNumberOfYields: flushNumberOfYields,
unstable_clearYields: clearYields,
};
Object.defineProperty(
@@ -555,15 +549,10 @@ const ReactTestRendererFiber = {
return entry;
},
unstable_yield: yieldValue,
unstable_clearYields: clearYields,
/* eslint-disable camelcase */
unstable_batchedUpdates: batchedUpdates,
/* eslint-enable camelcase */
unstable_setNowImplementation: setNowImplementation,
act(callback: () => void): Thenable {
// note: keep these warning messages in sync with
// createNoop.js and ReactTestUtils.js

View File

@@ -1,86 +0,0 @@
/**
* 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
*/
// Current virtual time
export let nowImplementation = () => 0;
export let scheduledCallback: (() => mixed) | null = null;
export let yieldedValues: Array<mixed> = [];
let didStop: boolean = false;
let expectedNumberOfYields: number = -1;
export function scheduleDeferredCallback(
callback: () => mixed,
options?: {timeout: number},
): number {
scheduledCallback = callback;
const fakeCallbackId = 0;
return fakeCallbackId;
}
export function cancelDeferredCallback(timeoutID: number): void {
scheduledCallback = null;
}
export function setNowImplementation(implementation: () => number): void {
nowImplementation = implementation;
}
export function shouldYield() {
if (
expectedNumberOfYields !== -1 &&
yieldedValues.length >= expectedNumberOfYields
) {
// We yielded at least as many values as expected. Stop rendering.
didStop = true;
return true;
}
// Keep rendering.
return false;
}
export function flushAll(): Array<mixed> {
yieldedValues = [];
while (scheduledCallback !== null) {
const cb = scheduledCallback;
scheduledCallback = null;
cb();
}
const values = yieldedValues;
yieldedValues = [];
return values;
}
export function flushNumberOfYields(count: number): Array<mixed> {
expectedNumberOfYields = count;
didStop = false;
yieldedValues = [];
try {
while (scheduledCallback !== null && !didStop) {
const cb = scheduledCallback;
scheduledCallback = null;
cb();
}
return yieldedValues;
} finally {
expectedNumberOfYields = -1;
didStop = false;
yieldedValues = [];
}
}
export function yieldValue(value: mixed): void {
yieldedValues.push(value);
}
export function clearYields(): Array<mixed> {
const values = yieldedValues;
yieldedValues = [];
return values;
}

View File

@@ -12,12 +12,14 @@
let React;
let ReactTestRenderer;
let Scheduler;
describe('ReactTestRendererAsync', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactTestRenderer = require('react-test-renderer');
Scheduler = require('scheduler');
});
it('flushAll flushes all work', () => {
@@ -46,7 +48,7 @@ describe('ReactTestRendererAsync', () => {
it('flushAll returns array of yielded values', () => {
function Child(props) {
ReactTestRenderer.unstable_yield(props.children);
Scheduler.yieldValue(props.children);
return props.children;
}
function Parent(props) {
@@ -72,7 +74,7 @@ describe('ReactTestRendererAsync', () => {
it('flushThrough flushes until the expected values is yielded', () => {
function Child(props) {
ReactTestRenderer.unstable_yield(props.children);
Scheduler.yieldValue(props.children);
return props.children;
}
function Parent(props) {
@@ -100,7 +102,7 @@ describe('ReactTestRendererAsync', () => {
it('supports high priority interruptions', () => {
function Child(props) {
ReactTestRenderer.unstable_yield(props.children);
Scheduler.yieldValue(props.children);
return props.children;
}
@@ -141,7 +143,7 @@ describe('ReactTestRendererAsync', () => {
describe('Jest matchers', () => {
it('toFlushAndYieldThrough', () => {
const Yield = ({id}) => {
ReactTestRenderer.unstable_yield(id);
Scheduler.yieldValue(id);
return id;
};
@@ -163,7 +165,7 @@ describe('ReactTestRendererAsync', () => {
it('toFlushAndYield', () => {
const Yield = ({id}) => {
ReactTestRenderer.unstable_yield(id);
Scheduler.yieldValue(id);
return id;
};
@@ -197,7 +199,7 @@ describe('ReactTestRendererAsync', () => {
it('toFlushAndThrow', () => {
const Yield = ({id}) => {
ReactTestRenderer.unstable_yield(id);
Scheduler.yieldValue(id);
return id;
};
@@ -254,7 +256,7 @@ describe('ReactTestRendererAsync', () => {
it('toHaveYielded', () => {
const Yield = ({id}) => {
ReactTestRenderer.unstable_yield(id);
Scheduler.yieldValue(id);
return id;
};
@@ -278,7 +280,7 @@ describe('ReactTestRendererAsync', () => {
const renderer = ReactTestRenderer.create(<div />, {
unstable_isConcurrent: true,
});
ReactTestRenderer.unstable_yield('Something');
Scheduler.yieldValue('Something');
expect(() => expect(renderer).toFlushWithoutYielding()).toThrow(
'Log of yielded values is not empty.',
);

File diff suppressed because it is too large Load Diff

View File

@@ -14,11 +14,10 @@ describe('ReactProfiler DevTools integration', () => {
let React;
let ReactFeatureFlags;
let ReactTestRenderer;
let Scheduler;
let SchedulerTracing;
let AdvanceTime;
let advanceTimeBy;
let hook;
let mockNow;
beforeEach(() => {
global.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook = {
@@ -30,24 +29,14 @@ describe('ReactProfiler DevTools integration', () => {
jest.resetModules();
let currentTime = 0;
mockNow = jest.fn().mockImplementation(() => currentTime);
global.Date.now = mockNow;
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableProfilerTimer = true;
ReactFeatureFlags.enableSchedulerTracing = true;
Scheduler = require('scheduler');
SchedulerTracing = require('scheduler/tracing');
React = require('react');
ReactTestRenderer = require('react-test-renderer');
ReactTestRenderer.unstable_setNowImplementation(mockNow);
advanceTimeBy = amount => {
currentTime += amount;
};
AdvanceTime = class extends React.Component {
static defaultProps = {
byAmount: 10,
@@ -58,7 +47,7 @@ describe('ReactProfiler DevTools integration', () => {
}
render() {
// Simulate time passing when this component is rendered
advanceTimeBy(this.props.byAmount);
Scheduler.advanceTime(this.props.byAmount);
return this.props.children || null;
}
};
@@ -66,7 +55,7 @@ describe('ReactProfiler DevTools integration', () => {
it('should auto-Profile all fibers if the DevTools hook is detected', () => {
const App = ({multiplier}) => {
advanceTimeBy(2);
Scheduler.advanceTime(2);
return (
<React.unstable_Profiler id="Profiler" onRender={onRender}>
<AdvanceTime byAmount={3 * multiplier} shouldComponentUpdate={true} />
@@ -132,7 +121,7 @@ describe('ReactProfiler DevTools integration', () => {
});
it('should reset the fiber stack correctly after an error when profiling host roots', () => {
advanceTimeBy(20);
Scheduler.advanceTime(20);
const rendered = ReactTestRenderer.create(
<div>
@@ -140,7 +129,7 @@ describe('ReactProfiler DevTools integration', () => {
</div>,
);
advanceTimeBy(20);
Scheduler.advanceTime(20);
expect(() => {
rendered.update(
@@ -150,7 +139,7 @@ describe('ReactProfiler DevTools integration', () => {
);
}).toThrow();
advanceTimeBy(20);
Scheduler.advanceTime(20);
// But this should render correctly, if the profiler's fiber stack has been reset.
rendered.update(
@@ -175,9 +164,9 @@ describe('ReactProfiler DevTools integration', () => {
const root = rendered.root._currentFiber().return;
expect(root.stateNode.memoizedInteractions).toContainNoInteractions();
advanceTimeBy(10);
Scheduler.advanceTime(10);
const eventTime = mockNow();
const eventTime = Scheduler.unstable_now();
// Render with an interaction
SchedulerTracing.unstable_trace('some event', eventTime, () => {

View File

@@ -23,10 +23,7 @@ function resolveScheduler(obj) {
if (obj._Scheduler !== undefined) {
return obj._Scheduler;
}
if (typeof obj.unstable_scheduleCallback === 'function') {
return obj;
}
return null;
return obj;
}
function assertYieldsWereCleared(Scheduler) {
@@ -34,48 +31,33 @@ function assertYieldsWereCleared(Scheduler) {
if (actualYields.length !== 0) {
throw new Error(
'Log of yielded values is not empty. ' +
'Call expect(ReactNoop).toHaveYielded(...) first.'
'Call expect(Scheduler).toHaveYielded(...) first.'
);
}
}
function toFlushAndYield(ReactNoop, expectedYields) {
const Scheduler = resolveScheduler(ReactNoop);
if (Scheduler === null) {
return JestReact.unstable_toFlushAndYield(ReactNoop, expectedYields);
}
return SchedulerMatchers.toFlushAndYield(Scheduler, expectedYields);
}
function toFlushAndYieldThrough(ReactNoop, expectedYields) {
const Scheduler = resolveScheduler(ReactNoop);
if (Scheduler === null) {
return JestReact.unstable_toFlushAndYieldThrough(ReactNoop, expectedYields);
}
return SchedulerMatchers.toFlushAndYieldThrough(Scheduler, expectedYields);
}
function toFlushWithoutYielding(ReactNoop) {
const Scheduler = resolveScheduler(ReactNoop);
if (Scheduler === null) {
return JestReact.unstable_toFlushWithoutYielding(ReactNoop);
}
return SchedulerMatchers.toFlushWithoutYielding(Scheduler);
}
function toHaveYielded(ReactNoop, expectedYields) {
const Scheduler = resolveScheduler(ReactNoop);
if (Scheduler === null) {
return JestReact.unstable_toHaveYielded(ReactNoop, expectedYields);
}
return SchedulerMatchers.toHaveYielded(Scheduler, expectedYields);
}
function toFlushAndThrow(ReactNoop, ...rest) {
const Scheduler = resolveScheduler(ReactNoop);
if (Scheduler === null) {
return JestReact.unstable_toFlushAndThrow(ReactNoop, ...rest);
}
return SchedulerMatchers.toFlushAndThrow(Scheduler, ...rest);
}

View File

@@ -172,7 +172,8 @@ const forks = Object.freeze({
if (
entry === 'scheduler/unstable_mock' ||
entry === 'react-noop-renderer' ||
entry === 'react-noop-renderer/persistent'
entry === 'react-noop-renderer/persistent' ||
entry === 'react-test-renderer'
) {
return 'scheduler/src/forks/SchedulerHostConfig.mock';
}